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