xref: /openbmc/linux/fs/smb/client/reparse.c (revision d1100aca)
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 	len = le16_to_cpu(buf->ReparseDataLength);
324 	if (len < sizeof(buf->InodeType)) {
325 		cifs_dbg(VFS, "srv returned malformed nfs buffer\n");
326 		return -EIO;
327 	}
328 
329 	len -= sizeof(buf->InodeType);
330 
331 	switch ((type = le64_to_cpu(buf->InodeType))) {
332 	case NFS_SPECFILE_LNK:
333 		if (len == 0 || (len % 2)) {
334 			cifs_dbg(VFS, "srv returned malformed nfs symlink buffer\n");
335 			return -EIO;
336 		}
337 		/*
338 		 * Check that buffer does not contain UTF-16 null codepoint
339 		 * because Linux cannot process symlink with null byte.
340 		 */
341 		if (UniStrnlen((wchar_t *)buf->DataBuffer, len/2) != len/2) {
342 			cifs_dbg(VFS, "srv returned null byte in nfs symlink target location\n");
343 			return -EIO;
344 		}
345 		data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer,
346 							       len, true,
347 							       cifs_sb->local_nls);
348 		if (!data->symlink_target)
349 			return -ENOMEM;
350 		cifs_dbg(FYI, "%s: target path: %s\n",
351 			 __func__, data->symlink_target);
352 		break;
353 	case NFS_SPECFILE_CHR:
354 	case NFS_SPECFILE_BLK:
355 		/* DataBuffer for block and char devices contains two 32-bit numbers */
356 		if (len != 8) {
357 			cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);
358 			return -EIO;
359 		}
360 		break;
361 	case NFS_SPECFILE_FIFO:
362 	case NFS_SPECFILE_SOCK:
363 		/* DataBuffer for fifos and sockets is empty */
364 		if (len != 0) {
365 			cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);
366 			return -EIO;
367 		}
368 		break;
369 	default:
370 		cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n",
371 			 __func__, type);
372 		return -EOPNOTSUPP;
373 	}
374 	return 0;
375 }
376 
377 static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym,
378 				 u32 plen, bool unicode,
379 				 struct cifs_sb_info *cifs_sb,
380 				 struct cifs_open_info_data *data)
381 {
382 	unsigned int len;
383 	unsigned int offs;
384 
385 	/* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */
386 
387 	offs = le16_to_cpu(sym->SubstituteNameOffset);
388 	len = le16_to_cpu(sym->SubstituteNameLength);
389 	if (offs + 20 > plen || offs + len + 20 > plen) {
390 		cifs_dbg(VFS, "srv returned malformed symlink buffer\n");
391 		return -EIO;
392 	}
393 
394 	data->symlink_target = cifs_strndup_from_utf16(sym->PathBuffer + offs,
395 						       len, unicode,
396 						       cifs_sb->local_nls);
397 	if (!data->symlink_target)
398 		return -ENOMEM;
399 
400 	convert_delimiter(data->symlink_target, '/');
401 	cifs_dbg(FYI, "%s: target path: %s\n", __func__, data->symlink_target);
402 
403 	return 0;
404 }
405 
406 int parse_reparse_point(struct reparse_data_buffer *buf,
407 			u32 plen, struct cifs_sb_info *cifs_sb,
408 			bool unicode, struct cifs_open_info_data *data)
409 {
410 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
411 
412 	data->reparse.buf = buf;
413 
414 	/* See MS-FSCC 2.1.2 */
415 	switch (le32_to_cpu(buf->ReparseTag)) {
416 	case IO_REPARSE_TAG_NFS:
417 		return parse_reparse_posix((struct reparse_posix_data *)buf,
418 					   cifs_sb, data);
419 	case IO_REPARSE_TAG_SYMLINK:
420 		return parse_reparse_symlink(
421 			(struct reparse_symlink_data_buffer *)buf,
422 			plen, unicode, cifs_sb, data);
423 	case IO_REPARSE_TAG_LX_SYMLINK:
424 	case IO_REPARSE_TAG_AF_UNIX:
425 	case IO_REPARSE_TAG_LX_FIFO:
426 	case IO_REPARSE_TAG_LX_CHR:
427 	case IO_REPARSE_TAG_LX_BLK:
428 		break;
429 	default:
430 		cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n",
431 			      le32_to_cpu(buf->ReparseTag));
432 		break;
433 	}
434 	return 0;
435 }
436 
437 int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
438 			     struct kvec *rsp_iov,
439 			     struct cifs_open_info_data *data)
440 {
441 	struct reparse_data_buffer *buf;
442 	struct smb2_ioctl_rsp *io = rsp_iov->iov_base;
443 	u32 plen = le32_to_cpu(io->OutputCount);
444 
445 	buf = (struct reparse_data_buffer *)((u8 *)io +
446 					     le32_to_cpu(io->OutputOffset));
447 	return parse_reparse_point(buf, plen, cifs_sb, true, data);
448 }
449 
450 static void wsl_to_fattr(struct cifs_open_info_data *data,
451 			 struct cifs_sb_info *cifs_sb,
452 			 u32 tag, struct cifs_fattr *fattr)
453 {
454 	struct smb2_file_full_ea_info *ea;
455 	u32 next = 0;
456 
457 	switch (tag) {
458 	case IO_REPARSE_TAG_LX_SYMLINK:
459 		fattr->cf_mode |= S_IFLNK;
460 		break;
461 	case IO_REPARSE_TAG_LX_FIFO:
462 		fattr->cf_mode |= S_IFIFO;
463 		break;
464 	case IO_REPARSE_TAG_AF_UNIX:
465 		fattr->cf_mode |= S_IFSOCK;
466 		break;
467 	case IO_REPARSE_TAG_LX_CHR:
468 		fattr->cf_mode |= S_IFCHR;
469 		break;
470 	case IO_REPARSE_TAG_LX_BLK:
471 		fattr->cf_mode |= S_IFBLK;
472 		break;
473 	}
474 
475 	if (!data->wsl.eas_len)
476 		goto out;
477 
478 	ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
479 	do {
480 		const char *name;
481 		void *v;
482 		u8 nlen;
483 
484 		ea = (void *)((u8 *)ea + next);
485 		next = le32_to_cpu(ea->next_entry_offset);
486 		if (!le16_to_cpu(ea->ea_value_length))
487 			continue;
488 
489 		name = ea->ea_data;
490 		nlen = ea->ea_name_length;
491 		v = (void *)((u8 *)ea->ea_data + ea->ea_name_length + 1);
492 
493 		if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen))
494 			fattr->cf_uid = wsl_make_kuid(cifs_sb, v);
495 		else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen))
496 			fattr->cf_gid = wsl_make_kgid(cifs_sb, v);
497 		else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen))
498 			fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v);
499 		else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen))
500 			fattr->cf_rdev = wsl_mkdev(v);
501 	} while (next);
502 out:
503 	fattr->cf_dtype = S_DT(fattr->cf_mode);
504 }
505 
506 bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
507 				 struct cifs_fattr *fattr,
508 				 struct cifs_open_info_data *data)
509 {
510 	struct reparse_posix_data *buf = data->reparse.posix;
511 	u32 tag = data->reparse.tag;
512 
513 	if (tag == IO_REPARSE_TAG_NFS && buf) {
514 		if (le16_to_cpu(buf->ReparseDataLength) < sizeof(buf->InodeType))
515 			return false;
516 		switch (le64_to_cpu(buf->InodeType)) {
517 		case NFS_SPECFILE_CHR:
518 			if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8)
519 				return false;
520 			fattr->cf_mode |= S_IFCHR;
521 			fattr->cf_rdev = reparse_nfs_mkdev(buf);
522 			break;
523 		case NFS_SPECFILE_BLK:
524 			if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8)
525 				return false;
526 			fattr->cf_mode |= S_IFBLK;
527 			fattr->cf_rdev = reparse_nfs_mkdev(buf);
528 			break;
529 		case NFS_SPECFILE_FIFO:
530 			fattr->cf_mode |= S_IFIFO;
531 			break;
532 		case NFS_SPECFILE_SOCK:
533 			fattr->cf_mode |= S_IFSOCK;
534 			break;
535 		case NFS_SPECFILE_LNK:
536 			fattr->cf_mode |= S_IFLNK;
537 			break;
538 		default:
539 			WARN_ON_ONCE(1);
540 			return false;
541 		}
542 		goto out;
543 	}
544 
545 	switch (tag) {
546 	case IO_REPARSE_TAG_INTERNAL:
547 		if (!(fattr->cf_cifsattrs & ATTR_DIRECTORY))
548 			return false;
549 		fallthrough;
550 	case IO_REPARSE_TAG_DFS:
551 	case IO_REPARSE_TAG_DFSR:
552 	case IO_REPARSE_TAG_MOUNT_POINT:
553 		/* See cifs_create_junction_fattr() */
554 		fattr->cf_mode = S_IFDIR | 0711;
555 		break;
556 	case IO_REPARSE_TAG_LX_SYMLINK:
557 	case IO_REPARSE_TAG_LX_FIFO:
558 	case IO_REPARSE_TAG_AF_UNIX:
559 	case IO_REPARSE_TAG_LX_CHR:
560 	case IO_REPARSE_TAG_LX_BLK:
561 		wsl_to_fattr(data, cifs_sb, tag, fattr);
562 		break;
563 	case 0: /* SMB1 symlink */
564 	case IO_REPARSE_TAG_SYMLINK:
565 	case IO_REPARSE_TAG_NFS:
566 		fattr->cf_mode |= S_IFLNK;
567 		break;
568 	default:
569 		return false;
570 	}
571 out:
572 	fattr->cf_dtype = S_DT(fattr->cf_mode);
573 	return true;
574 }
575