xref: /openbmc/linux/fs/smb/client/reparse.c (revision 7b3a3558)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2024 Paulo Alcantara <pc@manguebit.com>
4  */
5 
6 #include <linux/fs.h>
7 #include <linux/stat.h>
8 #include <linux/slab.h>
9 #include "cifsglob.h"
10 #include "smb2proto.h"
11 #include "cifsproto.h"
12 #include "cifs_unicode.h"
13 #include "cifs_debug.h"
14 #include "fs_context.h"
15 #include "reparse.h"
16 
17 int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
18 				struct dentry *dentry, struct cifs_tcon *tcon,
19 				const char *full_path, const char *symname)
20 {
21 	struct reparse_symlink_data_buffer *buf = NULL;
22 	struct cifs_open_info_data data;
23 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
24 	struct inode *new;
25 	struct kvec iov;
26 	__le16 *path;
27 	char *sym, sep = CIFS_DIR_SEP(cifs_sb);
28 	u16 len, plen;
29 	int rc = 0;
30 
31 	sym = kstrdup(symname, GFP_KERNEL);
32 	if (!sym)
33 		return -ENOMEM;
34 
35 	data = (struct cifs_open_info_data) {
36 		.reparse_point = true,
37 		.reparse = { .tag = IO_REPARSE_TAG_SYMLINK, },
38 		.symlink_target = sym,
39 	};
40 
41 	convert_delimiter(sym, sep);
42 	path = cifs_convert_path_to_utf16(sym, cifs_sb);
43 	if (!path) {
44 		rc = -ENOMEM;
45 		goto out;
46 	}
47 
48 	plen = 2 * UniStrnlen((wchar_t *)path, PATH_MAX);
49 	len = sizeof(*buf) + plen * 2;
50 	buf = kzalloc(len, GFP_KERNEL);
51 	if (!buf) {
52 		rc = -ENOMEM;
53 		goto out;
54 	}
55 
56 	buf->ReparseTag = cpu_to_le32(IO_REPARSE_TAG_SYMLINK);
57 	buf->ReparseDataLength = cpu_to_le16(len - sizeof(struct reparse_data_buffer));
58 	buf->SubstituteNameOffset = cpu_to_le16(plen);
59 	buf->SubstituteNameLength = cpu_to_le16(plen);
60 	memcpy(&buf->PathBuffer[plen], path, plen);
61 	buf->PrintNameOffset = 0;
62 	buf->PrintNameLength = cpu_to_le16(plen);
63 	memcpy(buf->PathBuffer, path, plen);
64 	buf->Flags = cpu_to_le32(*symname != '/' ? SYMLINK_FLAG_RELATIVE : 0);
65 	if (*sym != sep)
66 		buf->Flags = cpu_to_le32(SYMLINK_FLAG_RELATIVE);
67 
68 	convert_delimiter(sym, '/');
69 	iov.iov_base = buf;
70 	iov.iov_len = len;
71 	new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
72 				     tcon, full_path, &iov, NULL);
73 	if (!IS_ERR(new))
74 		d_instantiate(dentry, new);
75 	else
76 		rc = PTR_ERR(new);
77 out:
78 	kfree(path);
79 	cifs_free_open_info(&data);
80 	kfree(buf);
81 	return rc;
82 }
83 
84 static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
85 			       mode_t mode, dev_t dev,
86 			       struct kvec *iov)
87 {
88 	u64 type;
89 	u16 len, dlen;
90 
91 	len = sizeof(*buf);
92 
93 	switch ((type = reparse_mode_nfs_type(mode))) {
94 	case NFS_SPECFILE_BLK:
95 	case NFS_SPECFILE_CHR:
96 		dlen = sizeof(__le64);
97 		break;
98 	case NFS_SPECFILE_FIFO:
99 	case NFS_SPECFILE_SOCK:
100 		dlen = 0;
101 		break;
102 	default:
103 		return -EOPNOTSUPP;
104 	}
105 
106 	buf->ReparseTag = cpu_to_le32(IO_REPARSE_TAG_NFS);
107 	buf->Reserved = 0;
108 	buf->InodeType = cpu_to_le64(type);
109 	buf->ReparseDataLength = cpu_to_le16(len + dlen -
110 					     sizeof(struct reparse_data_buffer));
111 	*(__le64 *)buf->DataBuffer = cpu_to_le64(((u64)MAJOR(dev) << 32) |
112 						 MINOR(dev));
113 	iov->iov_base = buf;
114 	iov->iov_len = len + dlen;
115 	return 0;
116 }
117 
118 static int mknod_nfs(unsigned int xid, struct inode *inode,
119 		     struct dentry *dentry, struct cifs_tcon *tcon,
120 		     const char *full_path, umode_t mode, dev_t dev)
121 {
122 	struct cifs_open_info_data data;
123 	struct reparse_posix_data *p;
124 	struct inode *new;
125 	struct kvec iov;
126 	__u8 buf[sizeof(*p) + sizeof(__le64)];
127 	int rc;
128 
129 	p = (struct reparse_posix_data *)buf;
130 	rc = nfs_set_reparse_buf(p, mode, dev, &iov);
131 	if (rc)
132 		return rc;
133 
134 	data = (struct cifs_open_info_data) {
135 		.reparse_point = true,
136 		.reparse = { .tag = IO_REPARSE_TAG_NFS, .posix = p, },
137 	};
138 
139 	new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
140 				     tcon, full_path, &iov, NULL);
141 	if (!IS_ERR(new))
142 		d_instantiate(dentry, new);
143 	else
144 		rc = PTR_ERR(new);
145 	cifs_free_open_info(&data);
146 	return rc;
147 }
148 
149 static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
150 			       mode_t mode, struct kvec *iov)
151 {
152 	u32 tag;
153 
154 	switch ((tag = reparse_mode_wsl_tag(mode))) {
155 	case IO_REPARSE_TAG_LX_BLK:
156 	case IO_REPARSE_TAG_LX_CHR:
157 	case IO_REPARSE_TAG_LX_FIFO:
158 	case IO_REPARSE_TAG_AF_UNIX:
159 		break;
160 	default:
161 		return -EOPNOTSUPP;
162 	}
163 
164 	buf->ReparseTag = cpu_to_le32(tag);
165 	buf->Reserved = 0;
166 	buf->ReparseDataLength = 0;
167 	iov->iov_base = buf;
168 	iov->iov_len = sizeof(*buf);
169 	return 0;
170 }
171 
172 static struct smb2_create_ea_ctx *ea_create_context(u32 dlen, size_t *cc_len)
173 {
174 	struct smb2_create_ea_ctx *cc;
175 
176 	*cc_len = round_up(sizeof(*cc) + dlen, 8);
177 	cc = kzalloc(*cc_len, GFP_KERNEL);
178 	if (!cc)
179 		return ERR_PTR(-ENOMEM);
180 
181 	cc->ctx.NameOffset = cpu_to_le16(offsetof(struct smb2_create_ea_ctx,
182 						  name));
183 	cc->ctx.NameLength = cpu_to_le16(4);
184 	memcpy(cc->name, SMB2_CREATE_EA_BUFFER, strlen(SMB2_CREATE_EA_BUFFER));
185 	cc->ctx.DataOffset = cpu_to_le16(offsetof(struct smb2_create_ea_ctx, ea));
186 	cc->ctx.DataLength = cpu_to_le32(dlen);
187 	return cc;
188 }
189 
190 struct wsl_xattr {
191 	const char	*name;
192 	__le64		value;
193 	u16		size;
194 	u32		next;
195 };
196 
197 static int wsl_set_xattrs(struct inode *inode, umode_t _mode,
198 			  dev_t _dev, struct kvec *iov)
199 {
200 	struct smb2_file_full_ea_info *ea;
201 	struct smb2_create_ea_ctx *cc;
202 	struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
203 	__le64 uid = cpu_to_le64(from_kuid(current_user_ns(), ctx->linux_uid));
204 	__le64 gid = cpu_to_le64(from_kgid(current_user_ns(), ctx->linux_gid));
205 	__le64 dev = cpu_to_le64(((u64)MINOR(_dev) << 32) | MAJOR(_dev));
206 	__le64 mode = cpu_to_le64(_mode);
207 	struct wsl_xattr xattrs[] = {
208 		{ .name = SMB2_WSL_XATTR_UID,  .value = uid,  .size = SMB2_WSL_XATTR_UID_SIZE, },
209 		{ .name = SMB2_WSL_XATTR_GID,  .value = gid,  .size = SMB2_WSL_XATTR_GID_SIZE, },
210 		{ .name = SMB2_WSL_XATTR_MODE, .value = mode, .size = SMB2_WSL_XATTR_MODE_SIZE, },
211 		{ .name = SMB2_WSL_XATTR_DEV,  .value = dev, .size = SMB2_WSL_XATTR_DEV_SIZE, },
212 	};
213 	size_t cc_len;
214 	u32 dlen = 0, next = 0;
215 	int i, num_xattrs;
216 	u8 name_size = SMB2_WSL_XATTR_NAME_LEN + 1;
217 
218 	memset(iov, 0, sizeof(*iov));
219 
220 	/* Exclude $LXDEV xattr for sockets and fifos */
221 	if (S_ISSOCK(_mode) || S_ISFIFO(_mode))
222 		num_xattrs = ARRAY_SIZE(xattrs) - 1;
223 	else
224 		num_xattrs = ARRAY_SIZE(xattrs);
225 
226 	for (i = 0; i < num_xattrs; i++) {
227 		xattrs[i].next = ALIGN(sizeof(*ea) + name_size +
228 				       xattrs[i].size, 4);
229 		dlen += xattrs[i].next;
230 	}
231 
232 	cc = ea_create_context(dlen, &cc_len);
233 	if (IS_ERR(cc))
234 		return PTR_ERR(cc);
235 
236 	ea = &cc->ea;
237 	for (i = 0; i < num_xattrs; i++) {
238 		ea = (void *)((u8 *)ea + next);
239 		next = xattrs[i].next;
240 		ea->next_entry_offset = cpu_to_le32(next);
241 
242 		ea->ea_name_length = name_size - 1;
243 		ea->ea_value_length = cpu_to_le16(xattrs[i].size);
244 		memcpy(ea->ea_data, xattrs[i].name, name_size);
245 		memcpy(&ea->ea_data[name_size],
246 		       &xattrs[i].value, xattrs[i].size);
247 	}
248 	ea->next_entry_offset = 0;
249 
250 	iov->iov_base = cc;
251 	iov->iov_len = cc_len;
252 	return 0;
253 }
254 
255 static int mknod_wsl(unsigned int xid, struct inode *inode,
256 		     struct dentry *dentry, struct cifs_tcon *tcon,
257 		     const char *full_path, umode_t mode, dev_t dev)
258 {
259 	struct cifs_open_info_data data;
260 	struct reparse_data_buffer buf;
261 	struct smb2_create_ea_ctx *cc;
262 	struct inode *new;
263 	unsigned int len;
264 	struct kvec reparse_iov, xattr_iov;
265 	int rc;
266 
267 	rc = wsl_set_reparse_buf(&buf, mode, &reparse_iov);
268 	if (rc)
269 		return rc;
270 
271 	rc = wsl_set_xattrs(inode, mode, dev, &xattr_iov);
272 	if (rc)
273 		return rc;
274 
275 	data = (struct cifs_open_info_data) {
276 		.reparse_point = true,
277 		.reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, },
278 	};
279 
280 	cc = xattr_iov.iov_base;
281 	len = le32_to_cpu(cc->ctx.DataLength);
282 	memcpy(data.wsl.eas, &cc->ea, len);
283 	data.wsl.eas_len = len;
284 
285 	new = smb2_get_reparse_inode(&data, inode->i_sb,
286 				     xid, tcon, full_path,
287 				     &reparse_iov, &xattr_iov);
288 	if (!IS_ERR(new))
289 		d_instantiate(dentry, new);
290 	else
291 		rc = PTR_ERR(new);
292 	cifs_free_open_info(&data);
293 	kfree(xattr_iov.iov_base);
294 	return rc;
295 }
296 
297 int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
298 		       struct dentry *dentry, struct cifs_tcon *tcon,
299 		       const char *full_path, umode_t mode, dev_t dev)
300 {
301 	struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
302 	int rc = -EOPNOTSUPP;
303 
304 	switch (ctx->reparse_type) {
305 	case CIFS_REPARSE_TYPE_NFS:
306 		rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev);
307 		break;
308 	case CIFS_REPARSE_TYPE_WSL:
309 		rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev);
310 		break;
311 	}
312 	return rc;
313 }
314 
315 /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */
316 static int parse_reparse_posix(struct reparse_posix_data *buf,
317 			       struct cifs_sb_info *cifs_sb,
318 			       struct cifs_open_info_data *data)
319 {
320 	unsigned int len;
321 	u64 type;
322 
323 	switch ((type = le64_to_cpu(buf->InodeType))) {
324 	case NFS_SPECFILE_LNK:
325 		len = le16_to_cpu(buf->ReparseDataLength);
326 		data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer,
327 							       len, true,
328 							       cifs_sb->local_nls);
329 		if (!data->symlink_target)
330 			return -ENOMEM;
331 		convert_delimiter(data->symlink_target, '/');
332 		cifs_dbg(FYI, "%s: target path: %s\n",
333 			 __func__, data->symlink_target);
334 		break;
335 	case NFS_SPECFILE_CHR:
336 	case NFS_SPECFILE_BLK:
337 	case NFS_SPECFILE_FIFO:
338 	case NFS_SPECFILE_SOCK:
339 		break;
340 	default:
341 		cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n",
342 			 __func__, type);
343 		return -EOPNOTSUPP;
344 	}
345 	return 0;
346 }
347 
348 static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym,
349 				 u32 plen, bool unicode,
350 				 struct cifs_sb_info *cifs_sb,
351 				 struct cifs_open_info_data *data)
352 {
353 	unsigned int len;
354 	unsigned int offs;
355 
356 	/* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */
357 
358 	offs = le16_to_cpu(sym->SubstituteNameOffset);
359 	len = le16_to_cpu(sym->SubstituteNameLength);
360 	if (offs + 20 > plen || offs + len + 20 > plen) {
361 		cifs_dbg(VFS, "srv returned malformed symlink buffer\n");
362 		return -EIO;
363 	}
364 
365 	data->symlink_target = cifs_strndup_from_utf16(sym->PathBuffer + offs,
366 						       len, unicode,
367 						       cifs_sb->local_nls);
368 	if (!data->symlink_target)
369 		return -ENOMEM;
370 
371 	convert_delimiter(data->symlink_target, '/');
372 	cifs_dbg(FYI, "%s: target path: %s\n", __func__, data->symlink_target);
373 
374 	return 0;
375 }
376 
377 int parse_reparse_point(struct reparse_data_buffer *buf,
378 			u32 plen, struct cifs_sb_info *cifs_sb,
379 			bool unicode, struct cifs_open_info_data *data)
380 {
381 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
382 
383 	data->reparse.buf = buf;
384 
385 	/* See MS-FSCC 2.1.2 */
386 	switch (le32_to_cpu(buf->ReparseTag)) {
387 	case IO_REPARSE_TAG_NFS:
388 		return parse_reparse_posix((struct reparse_posix_data *)buf,
389 					   cifs_sb, data);
390 	case IO_REPARSE_TAG_SYMLINK:
391 		return parse_reparse_symlink(
392 			(struct reparse_symlink_data_buffer *)buf,
393 			plen, unicode, cifs_sb, data);
394 	case IO_REPARSE_TAG_LX_SYMLINK:
395 	case IO_REPARSE_TAG_AF_UNIX:
396 	case IO_REPARSE_TAG_LX_FIFO:
397 	case IO_REPARSE_TAG_LX_CHR:
398 	case IO_REPARSE_TAG_LX_BLK:
399 		break;
400 	default:
401 		cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n",
402 			      le32_to_cpu(buf->ReparseTag));
403 		break;
404 	}
405 	return 0;
406 }
407 
408 int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
409 			     struct kvec *rsp_iov,
410 			     struct cifs_open_info_data *data)
411 {
412 	struct reparse_data_buffer *buf;
413 	struct smb2_ioctl_rsp *io = rsp_iov->iov_base;
414 	u32 plen = le32_to_cpu(io->OutputCount);
415 
416 	buf = (struct reparse_data_buffer *)((u8 *)io +
417 					     le32_to_cpu(io->OutputOffset));
418 	return parse_reparse_point(buf, plen, cifs_sb, true, data);
419 }
420 
421 static void wsl_to_fattr(struct cifs_open_info_data *data,
422 			 struct cifs_sb_info *cifs_sb,
423 			 u32 tag, struct cifs_fattr *fattr)
424 {
425 	struct smb2_file_full_ea_info *ea;
426 	u32 next = 0;
427 
428 	switch (tag) {
429 	case IO_REPARSE_TAG_LX_SYMLINK:
430 		fattr->cf_mode |= S_IFLNK;
431 		break;
432 	case IO_REPARSE_TAG_LX_FIFO:
433 		fattr->cf_mode |= S_IFIFO;
434 		break;
435 	case IO_REPARSE_TAG_AF_UNIX:
436 		fattr->cf_mode |= S_IFSOCK;
437 		break;
438 	case IO_REPARSE_TAG_LX_CHR:
439 		fattr->cf_mode |= S_IFCHR;
440 		break;
441 	case IO_REPARSE_TAG_LX_BLK:
442 		fattr->cf_mode |= S_IFBLK;
443 		break;
444 	}
445 
446 	if (!data->wsl.eas_len)
447 		goto out;
448 
449 	ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
450 	do {
451 		const char *name;
452 		void *v;
453 		u8 nlen;
454 
455 		ea = (void *)((u8 *)ea + next);
456 		next = le32_to_cpu(ea->next_entry_offset);
457 		if (!le16_to_cpu(ea->ea_value_length))
458 			continue;
459 
460 		name = ea->ea_data;
461 		nlen = ea->ea_name_length;
462 		v = (void *)((u8 *)ea->ea_data + ea->ea_name_length + 1);
463 
464 		if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen))
465 			fattr->cf_uid = wsl_make_kuid(cifs_sb, v);
466 		else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen))
467 			fattr->cf_gid = wsl_make_kgid(cifs_sb, v);
468 		else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen))
469 			fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v);
470 		else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen))
471 			fattr->cf_rdev = wsl_mkdev(v);
472 	} while (next);
473 out:
474 	fattr->cf_dtype = S_DT(fattr->cf_mode);
475 }
476 
477 bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
478 				 struct cifs_fattr *fattr,
479 				 struct cifs_open_info_data *data)
480 {
481 	struct reparse_posix_data *buf = data->reparse.posix;
482 	u32 tag = data->reparse.tag;
483 
484 	if (tag == IO_REPARSE_TAG_NFS && buf) {
485 		switch (le64_to_cpu(buf->InodeType)) {
486 		case NFS_SPECFILE_CHR:
487 			fattr->cf_mode |= S_IFCHR;
488 			fattr->cf_rdev = reparse_nfs_mkdev(buf);
489 			break;
490 		case NFS_SPECFILE_BLK:
491 			fattr->cf_mode |= S_IFBLK;
492 			fattr->cf_rdev = reparse_nfs_mkdev(buf);
493 			break;
494 		case NFS_SPECFILE_FIFO:
495 			fattr->cf_mode |= S_IFIFO;
496 			break;
497 		case NFS_SPECFILE_SOCK:
498 			fattr->cf_mode |= S_IFSOCK;
499 			break;
500 		case NFS_SPECFILE_LNK:
501 			fattr->cf_mode |= S_IFLNK;
502 			break;
503 		default:
504 			WARN_ON_ONCE(1);
505 			return false;
506 		}
507 		goto out;
508 	}
509 
510 	switch (tag) {
511 	case IO_REPARSE_TAG_INTERNAL:
512 		if (!(fattr->cf_cifsattrs & ATTR_DIRECTORY))
513 			return false;
514 		fallthrough;
515 	case IO_REPARSE_TAG_DFS:
516 	case IO_REPARSE_TAG_DFSR:
517 	case IO_REPARSE_TAG_MOUNT_POINT:
518 		/* See cifs_create_junction_fattr() */
519 		fattr->cf_mode = S_IFDIR | 0711;
520 		break;
521 	case IO_REPARSE_TAG_LX_SYMLINK:
522 	case IO_REPARSE_TAG_LX_FIFO:
523 	case IO_REPARSE_TAG_AF_UNIX:
524 	case IO_REPARSE_TAG_LX_CHR:
525 	case IO_REPARSE_TAG_LX_BLK:
526 		wsl_to_fattr(data, cifs_sb, tag, fattr);
527 		break;
528 	case 0: /* SMB1 symlink */
529 	case IO_REPARSE_TAG_SYMLINK:
530 	case IO_REPARSE_TAG_NFS:
531 		fattr->cf_mode |= S_IFLNK;
532 		break;
533 	default:
534 		return false;
535 	}
536 out:
537 	fattr->cf_dtype = S_DT(fattr->cf_mode);
538 	return true;
539 }
540