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 static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
18 const unsigned int xid,
19 const char *full_path,
20 const char *symname,
21 bool *directory);
22
smb2_create_reparse_symlink(const unsigned int xid,struct inode * inode,struct dentry * dentry,struct cifs_tcon * tcon,const char * full_path,const char * symname)23 int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
24 struct dentry *dentry, struct cifs_tcon *tcon,
25 const char *full_path, const char *symname)
26 {
27 struct reparse_symlink_data_buffer *buf = NULL;
28 struct cifs_open_info_data data;
29 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
30 struct inode *new;
31 struct kvec iov;
32 __le16 *path;
33 bool directory;
34 char *sym, sep = CIFS_DIR_SEP(cifs_sb);
35 u16 len, plen;
36 int rc = 0;
37
38 if (strlen(symname) > REPARSE_SYM_PATH_MAX)
39 return -ENAMETOOLONG;
40
41 sym = kstrdup(symname, GFP_KERNEL);
42 if (!sym)
43 return -ENOMEM;
44
45 data = (struct cifs_open_info_data) {
46 .reparse_point = true,
47 .reparse = { .tag = IO_REPARSE_TAG_SYMLINK, },
48 .symlink_target = sym,
49 };
50
51 convert_delimiter(sym, sep);
52 path = cifs_convert_path_to_utf16(sym, cifs_sb);
53 if (!path) {
54 rc = -ENOMEM;
55 goto out;
56 }
57
58 /*
59 * SMB distinguish between symlink to directory and symlink to file.
60 * They cannot be exchanged (symlink of file type which points to
61 * directory cannot be resolved and vice-versa). Try to detect if
62 * the symlink target could be a directory or not. When detection
63 * fails then treat symlink as a file (non-directory) symlink.
64 */
65 directory = false;
66 rc = detect_directory_symlink_target(cifs_sb, xid, full_path, symname, &directory);
67 if (rc < 0)
68 goto out;
69
70 plen = 2 * UniStrnlen((wchar_t *)path, REPARSE_SYM_PATH_MAX);
71 len = sizeof(*buf) + plen * 2;
72 buf = kzalloc(len, GFP_KERNEL);
73 if (!buf) {
74 rc = -ENOMEM;
75 goto out;
76 }
77
78 buf->ReparseTag = cpu_to_le32(IO_REPARSE_TAG_SYMLINK);
79 buf->ReparseDataLength = cpu_to_le16(len - sizeof(struct reparse_data_buffer));
80 buf->SubstituteNameOffset = cpu_to_le16(plen);
81 buf->SubstituteNameLength = cpu_to_le16(plen);
82 memcpy(&buf->PathBuffer[plen], path, plen);
83 buf->PrintNameOffset = 0;
84 buf->PrintNameLength = cpu_to_le16(plen);
85 memcpy(buf->PathBuffer, path, plen);
86 buf->Flags = cpu_to_le32(*symname != '/' ? SYMLINK_FLAG_RELATIVE : 0);
87 if (*sym != sep)
88 buf->Flags = cpu_to_le32(SYMLINK_FLAG_RELATIVE);
89
90 convert_delimiter(sym, '/');
91 iov.iov_base = buf;
92 iov.iov_len = len;
93 new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
94 tcon, full_path, directory,
95 &iov, NULL);
96 if (!IS_ERR(new))
97 d_instantiate(dentry, new);
98 else
99 rc = PTR_ERR(new);
100 out:
101 kfree(path);
102 cifs_free_open_info(&data);
103 kfree(buf);
104 return rc;
105 }
106
detect_directory_symlink_target(struct cifs_sb_info * cifs_sb,const unsigned int xid,const char * full_path,const char * symname,bool * directory)107 static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
108 const unsigned int xid,
109 const char *full_path,
110 const char *symname,
111 bool *directory)
112 {
113 char sep = CIFS_DIR_SEP(cifs_sb);
114 struct cifs_open_parms oparms;
115 struct tcon_link *tlink;
116 struct cifs_tcon *tcon;
117 const char *basename;
118 struct cifs_fid fid;
119 char *resolved_path;
120 int full_path_len;
121 int basename_len;
122 int symname_len;
123 char *path_sep;
124 __u32 oplock;
125 int open_rc;
126
127 /*
128 * First do some simple check. If the original Linux symlink target ends
129 * with slash, or last path component is dot or dot-dot then it is for
130 * sure symlink to the directory.
131 */
132 basename = kbasename(symname);
133 basename_len = strlen(basename);
134 if (basename_len == 0 || /* symname ends with slash */
135 (basename_len == 1 && basename[0] == '.') || /* last component is "." */
136 (basename_len == 2 && basename[0] == '.' && basename[1] == '.')) { /* or ".." */
137 *directory = true;
138 return 0;
139 }
140
141 /*
142 * For absolute symlinks it is not possible to determinate
143 * if it should point to directory or file.
144 */
145 if (symname[0] == '/') {
146 cifs_dbg(FYI,
147 "%s: cannot determinate if the symlink target path '%s' "
148 "is directory or not, creating '%s' as file symlink\n",
149 __func__, symname, full_path);
150 return 0;
151 }
152
153 /*
154 * If it was not detected as directory yet and the symlink is relative
155 * then try to resolve the path on the SMB server, check if the path
156 * exists and determinate if it is a directory or not.
157 */
158
159 full_path_len = strlen(full_path);
160 symname_len = strlen(symname);
161
162 tlink = cifs_sb_tlink(cifs_sb);
163 if (IS_ERR(tlink))
164 return PTR_ERR(tlink);
165
166 resolved_path = kzalloc(full_path_len + symname_len + 1, GFP_KERNEL);
167 if (!resolved_path) {
168 cifs_put_tlink(tlink);
169 return -ENOMEM;
170 }
171
172 /*
173 * Compose the resolved SMB symlink path from the SMB full path
174 * and Linux target symlink path.
175 */
176 memcpy(resolved_path, full_path, full_path_len+1);
177 path_sep = strrchr(resolved_path, sep);
178 if (path_sep)
179 path_sep++;
180 else
181 path_sep = resolved_path;
182 memcpy(path_sep, symname, symname_len+1);
183 if (sep == '\\')
184 convert_delimiter(path_sep, sep);
185
186 tcon = tlink_tcon(tlink);
187 oparms = CIFS_OPARMS(cifs_sb, tcon, resolved_path,
188 FILE_READ_ATTRIBUTES, FILE_OPEN, 0, ACL_NO_MODE);
189 oparms.fid = &fid;
190
191 /* Try to open as a directory (NOT_FILE) */
192 oplock = 0;
193 oparms.create_options = cifs_create_options(cifs_sb,
194 CREATE_NOT_FILE | OPEN_REPARSE_POINT);
195 open_rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
196 if (open_rc == 0) {
197 /* Successful open means that the target path is definitely a directory. */
198 *directory = true;
199 tcon->ses->server->ops->close(xid, tcon, &fid);
200 } else if (open_rc == -ENOTDIR) {
201 /* -ENOTDIR means that the target path is definitely a file. */
202 *directory = false;
203 } else if (open_rc == -ENOENT) {
204 /* -ENOENT means that the target path does not exist. */
205 cifs_dbg(FYI,
206 "%s: symlink target path '%s' does not exist, "
207 "creating '%s' as file symlink\n",
208 __func__, symname, full_path);
209 } else {
210 /* Try to open as a file (NOT_DIR) */
211 oplock = 0;
212 oparms.create_options = cifs_create_options(cifs_sb,
213 CREATE_NOT_DIR | OPEN_REPARSE_POINT);
214 open_rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
215 if (open_rc == 0) {
216 /* Successful open means that the target path is definitely a file. */
217 *directory = false;
218 tcon->ses->server->ops->close(xid, tcon, &fid);
219 } else if (open_rc == -EISDIR) {
220 /* -EISDIR means that the target path is definitely a directory. */
221 *directory = true;
222 } else {
223 /*
224 * This code branch is called when we do not have a permission to
225 * open the resolved_path or some other client/process denied
226 * opening the resolved_path.
227 *
228 * TODO: Try to use ops->query_dir_first on the parent directory
229 * of resolved_path, search for basename of resolved_path and
230 * check if the ATTR_DIRECTORY is set in fi.Attributes. In some
231 * case this could work also when opening of the path is denied.
232 */
233 cifs_dbg(FYI,
234 "%s: cannot determinate if the symlink target path '%s' "
235 "is directory or not, creating '%s' as file symlink\n",
236 __func__, symname, full_path);
237 }
238 }
239
240 kfree(resolved_path);
241 cifs_put_tlink(tlink);
242 return 0;
243 }
244
nfs_set_reparse_buf(struct reparse_posix_data * buf,mode_t mode,dev_t dev,struct kvec * iov)245 static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
246 mode_t mode, dev_t dev,
247 struct kvec *iov)
248 {
249 u64 type;
250 u16 len, dlen;
251
252 len = sizeof(*buf);
253
254 switch ((type = reparse_mode_nfs_type(mode))) {
255 case NFS_SPECFILE_BLK:
256 case NFS_SPECFILE_CHR:
257 dlen = sizeof(__le64);
258 break;
259 case NFS_SPECFILE_FIFO:
260 case NFS_SPECFILE_SOCK:
261 dlen = 0;
262 break;
263 default:
264 return -EOPNOTSUPP;
265 }
266
267 buf->ReparseTag = cpu_to_le32(IO_REPARSE_TAG_NFS);
268 buf->Reserved = 0;
269 buf->InodeType = cpu_to_le64(type);
270 buf->ReparseDataLength = cpu_to_le16(len + dlen -
271 sizeof(struct reparse_data_buffer));
272 *(__le64 *)buf->DataBuffer = cpu_to_le64(((u64)MINOR(dev) << 32) |
273 MAJOR(dev));
274 iov->iov_base = buf;
275 iov->iov_len = len + dlen;
276 return 0;
277 }
278
mknod_nfs(unsigned int xid,struct inode * inode,struct dentry * dentry,struct cifs_tcon * tcon,const char * full_path,umode_t mode,dev_t dev)279 static int mknod_nfs(unsigned int xid, struct inode *inode,
280 struct dentry *dentry, struct cifs_tcon *tcon,
281 const char *full_path, umode_t mode, dev_t dev)
282 {
283 struct cifs_open_info_data data;
284 struct reparse_posix_data *p;
285 struct inode *new;
286 struct kvec iov;
287 __u8 buf[sizeof(*p) + sizeof(__le64)];
288 int rc;
289
290 p = (struct reparse_posix_data *)buf;
291 rc = nfs_set_reparse_buf(p, mode, dev, &iov);
292 if (rc)
293 return rc;
294
295 data = (struct cifs_open_info_data) {
296 .reparse_point = true,
297 .reparse = { .tag = IO_REPARSE_TAG_NFS, .posix = p, },
298 };
299
300 new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
301 tcon, full_path, false, &iov, NULL);
302 if (!IS_ERR(new))
303 d_instantiate(dentry, new);
304 else
305 rc = PTR_ERR(new);
306 cifs_free_open_info(&data);
307 return rc;
308 }
309
wsl_set_reparse_buf(struct reparse_data_buffer * buf,mode_t mode,struct kvec * iov)310 static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
311 mode_t mode, struct kvec *iov)
312 {
313 u32 tag;
314
315 switch ((tag = reparse_mode_wsl_tag(mode))) {
316 case IO_REPARSE_TAG_LX_BLK:
317 case IO_REPARSE_TAG_LX_CHR:
318 case IO_REPARSE_TAG_LX_FIFO:
319 case IO_REPARSE_TAG_AF_UNIX:
320 break;
321 default:
322 return -EOPNOTSUPP;
323 }
324
325 buf->ReparseTag = cpu_to_le32(tag);
326 buf->Reserved = 0;
327 buf->ReparseDataLength = 0;
328 iov->iov_base = buf;
329 iov->iov_len = sizeof(*buf);
330 return 0;
331 }
332
ea_create_context(u32 dlen,size_t * cc_len)333 static struct smb2_create_ea_ctx *ea_create_context(u32 dlen, size_t *cc_len)
334 {
335 struct smb2_create_ea_ctx *cc;
336
337 *cc_len = round_up(sizeof(*cc) + dlen, 8);
338 cc = kzalloc(*cc_len, GFP_KERNEL);
339 if (!cc)
340 return ERR_PTR(-ENOMEM);
341
342 cc->ctx.NameOffset = cpu_to_le16(offsetof(struct smb2_create_ea_ctx,
343 name));
344 cc->ctx.NameLength = cpu_to_le16(4);
345 memcpy(cc->name, SMB2_CREATE_EA_BUFFER, strlen(SMB2_CREATE_EA_BUFFER));
346 cc->ctx.DataOffset = cpu_to_le16(offsetof(struct smb2_create_ea_ctx, ea));
347 cc->ctx.DataLength = cpu_to_le32(dlen);
348 return cc;
349 }
350
351 struct wsl_xattr {
352 const char *name;
353 __le64 value;
354 u16 size;
355 u32 next;
356 };
357
wsl_set_xattrs(struct inode * inode,umode_t _mode,dev_t _dev,struct kvec * iov)358 static int wsl_set_xattrs(struct inode *inode, umode_t _mode,
359 dev_t _dev, struct kvec *iov)
360 {
361 struct smb2_file_full_ea_info *ea;
362 struct smb2_create_ea_ctx *cc;
363 struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
364 __le64 uid = cpu_to_le64(from_kuid(current_user_ns(), ctx->linux_uid));
365 __le64 gid = cpu_to_le64(from_kgid(current_user_ns(), ctx->linux_gid));
366 __le64 dev = cpu_to_le64(((u64)MINOR(_dev) << 32) | MAJOR(_dev));
367 __le64 mode = cpu_to_le64(_mode);
368 struct wsl_xattr xattrs[] = {
369 { .name = SMB2_WSL_XATTR_UID, .value = uid, .size = SMB2_WSL_XATTR_UID_SIZE, },
370 { .name = SMB2_WSL_XATTR_GID, .value = gid, .size = SMB2_WSL_XATTR_GID_SIZE, },
371 { .name = SMB2_WSL_XATTR_MODE, .value = mode, .size = SMB2_WSL_XATTR_MODE_SIZE, },
372 { .name = SMB2_WSL_XATTR_DEV, .value = dev, .size = SMB2_WSL_XATTR_DEV_SIZE, },
373 };
374 size_t cc_len;
375 u32 dlen = 0, next = 0;
376 int i, num_xattrs;
377 u8 name_size = SMB2_WSL_XATTR_NAME_LEN + 1;
378
379 memset(iov, 0, sizeof(*iov));
380
381 /* Exclude $LXDEV xattr for non-device files */
382 if (!S_ISBLK(_mode) && !S_ISCHR(_mode))
383 num_xattrs = ARRAY_SIZE(xattrs) - 1;
384 else
385 num_xattrs = ARRAY_SIZE(xattrs);
386
387 for (i = 0; i < num_xattrs; i++) {
388 xattrs[i].next = ALIGN(sizeof(*ea) + name_size +
389 xattrs[i].size, 4);
390 dlen += xattrs[i].next;
391 }
392
393 cc = ea_create_context(dlen, &cc_len);
394 if (IS_ERR(cc))
395 return PTR_ERR(cc);
396
397 ea = &cc->ea;
398 for (i = 0; i < num_xattrs; i++) {
399 ea = (void *)((u8 *)ea + next);
400 next = xattrs[i].next;
401 ea->next_entry_offset = cpu_to_le32(next);
402
403 ea->ea_name_length = name_size - 1;
404 ea->ea_value_length = cpu_to_le16(xattrs[i].size);
405 memcpy(ea->ea_data, xattrs[i].name, name_size);
406 memcpy(&ea->ea_data[name_size],
407 &xattrs[i].value, xattrs[i].size);
408 }
409 ea->next_entry_offset = 0;
410
411 iov->iov_base = cc;
412 iov->iov_len = cc_len;
413 return 0;
414 }
415
mknod_wsl(unsigned int xid,struct inode * inode,struct dentry * dentry,struct cifs_tcon * tcon,const char * full_path,umode_t mode,dev_t dev)416 static int mknod_wsl(unsigned int xid, struct inode *inode,
417 struct dentry *dentry, struct cifs_tcon *tcon,
418 const char *full_path, umode_t mode, dev_t dev)
419 {
420 struct cifs_open_info_data data;
421 struct reparse_data_buffer buf;
422 struct smb2_create_ea_ctx *cc;
423 struct inode *new;
424 unsigned int len;
425 struct kvec reparse_iov, xattr_iov;
426 int rc;
427
428 rc = wsl_set_reparse_buf(&buf, mode, &reparse_iov);
429 if (rc)
430 return rc;
431
432 rc = wsl_set_xattrs(inode, mode, dev, &xattr_iov);
433 if (rc)
434 return rc;
435
436 data = (struct cifs_open_info_data) {
437 .reparse_point = true,
438 .reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, },
439 };
440
441 cc = xattr_iov.iov_base;
442 len = le32_to_cpu(cc->ctx.DataLength);
443 memcpy(data.wsl.eas, &cc->ea, len);
444 data.wsl.eas_len = len;
445
446 new = smb2_get_reparse_inode(&data, inode->i_sb,
447 xid, tcon, full_path, false,
448 &reparse_iov, &xattr_iov);
449 if (!IS_ERR(new))
450 d_instantiate(dentry, new);
451 else
452 rc = PTR_ERR(new);
453 cifs_free_open_info(&data);
454 kfree(xattr_iov.iov_base);
455 return rc;
456 }
457
smb2_mknod_reparse(unsigned int xid,struct inode * inode,struct dentry * dentry,struct cifs_tcon * tcon,const char * full_path,umode_t mode,dev_t dev)458 int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
459 struct dentry *dentry, struct cifs_tcon *tcon,
460 const char *full_path, umode_t mode, dev_t dev)
461 {
462 struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
463 int rc = -EOPNOTSUPP;
464
465 switch (ctx->reparse_type) {
466 case CIFS_REPARSE_TYPE_NFS:
467 rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev);
468 break;
469 case CIFS_REPARSE_TYPE_WSL:
470 rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev);
471 break;
472 }
473 return rc;
474 }
475
476 /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */
parse_reparse_posix(struct reparse_posix_data * buf,struct cifs_sb_info * cifs_sb,struct cifs_open_info_data * data)477 static int parse_reparse_posix(struct reparse_posix_data *buf,
478 struct cifs_sb_info *cifs_sb,
479 struct cifs_open_info_data *data)
480 {
481 unsigned int len;
482 u64 type;
483
484 len = le16_to_cpu(buf->ReparseDataLength);
485 if (len < sizeof(buf->InodeType)) {
486 cifs_dbg(VFS, "srv returned malformed nfs buffer\n");
487 return -EIO;
488 }
489
490 len -= sizeof(buf->InodeType);
491
492 switch ((type = le64_to_cpu(buf->InodeType))) {
493 case NFS_SPECFILE_LNK:
494 if (len == 0 || (len % 2)) {
495 cifs_dbg(VFS, "srv returned malformed nfs symlink buffer\n");
496 return -EIO;
497 }
498 /*
499 * Check that buffer does not contain UTF-16 null codepoint
500 * because Linux cannot process symlink with null byte.
501 */
502 if (UniStrnlen((wchar_t *)buf->DataBuffer, len/2) != len/2) {
503 cifs_dbg(VFS, "srv returned null byte in nfs symlink target location\n");
504 return -EIO;
505 }
506 data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer,
507 len, true,
508 cifs_sb->local_nls);
509 if (!data->symlink_target)
510 return -ENOMEM;
511 cifs_dbg(FYI, "%s: target path: %s\n",
512 __func__, data->symlink_target);
513 break;
514 case NFS_SPECFILE_CHR:
515 case NFS_SPECFILE_BLK:
516 /* DataBuffer for block and char devices contains two 32-bit numbers */
517 if (len != 8) {
518 cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);
519 return -EIO;
520 }
521 break;
522 case NFS_SPECFILE_FIFO:
523 case NFS_SPECFILE_SOCK:
524 /* DataBuffer for fifos and sockets is empty */
525 if (len != 0) {
526 cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);
527 return -EIO;
528 }
529 break;
530 default:
531 cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n",
532 __func__, type);
533 return -EOPNOTSUPP;
534 }
535 return 0;
536 }
537
smb2_parse_native_symlink(char ** target,const char * buf,unsigned int len,bool unicode,bool relative,const char * full_path,struct cifs_sb_info * cifs_sb)538 int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
539 bool unicode, bool relative,
540 const char *full_path,
541 struct cifs_sb_info *cifs_sb)
542 {
543 char sep = CIFS_DIR_SEP(cifs_sb);
544 char *linux_target = NULL;
545 char *smb_target = NULL;
546 int levels;
547 int rc;
548 int i;
549
550 /* Check that length it valid for unicode/non-unicode mode */
551 if (!len || (unicode && (len % 2))) {
552 cifs_dbg(VFS, "srv returned malformed symlink buffer\n");
553 rc = -EIO;
554 goto out;
555 }
556
557 /*
558 * Check that buffer does not contain UTF-16 null codepoint in unicode
559 * mode or null byte in non-unicode mode because Linux cannot process
560 * symlink with null byte.
561 */
562 if ((unicode && UniStrnlen((wchar_t *)buf, len/2) != len/2) ||
563 (!unicode && strnlen(buf, len) != len)) {
564 cifs_dbg(VFS, "srv returned null byte in native symlink target location\n");
565 rc = -EIO;
566 goto out;
567 }
568
569 smb_target = cifs_strndup_from_utf16(buf, len, unicode, cifs_sb->local_nls);
570 if (!smb_target) {
571 rc = -ENOMEM;
572 goto out;
573 }
574
575 if (smb_target[0] == sep && relative) {
576 /*
577 * This is a relative SMB symlink from the top of the share,
578 * which is the top level directory of the Linux mount point.
579 * Linux does not support such relative symlinks, so convert
580 * it to the relative symlink from the current directory.
581 * full_path is the SMB path to the symlink (from which is
582 * extracted current directory) and smb_target is the SMB path
583 * where symlink points, therefore full_path must always be on
584 * the SMB share.
585 */
586 int smb_target_len = strlen(smb_target)+1;
587 levels = 0;
588 for (i = 1; full_path[i]; i++) { /* i=1 to skip leading sep */
589 if (full_path[i] == sep)
590 levels++;
591 }
592 linux_target = kmalloc(levels*3 + smb_target_len, GFP_KERNEL);
593 if (!linux_target) {
594 rc = -ENOMEM;
595 goto out;
596 }
597 for (i = 0; i < levels; i++) {
598 linux_target[i*3 + 0] = '.';
599 linux_target[i*3 + 1] = '.';
600 linux_target[i*3 + 2] = sep;
601 }
602 memcpy(linux_target + levels*3, smb_target+1, smb_target_len); /* +1 to skip leading sep */
603 } else {
604 linux_target = smb_target;
605 smb_target = NULL;
606 }
607
608 if (sep == '\\')
609 convert_delimiter(linux_target, '/');
610
611 rc = 0;
612 *target = linux_target;
613
614 cifs_dbg(FYI, "%s: symlink target: %s\n", __func__, *target);
615
616 out:
617 if (rc != 0)
618 kfree(linux_target);
619 kfree(smb_target);
620 return rc;
621 }
622
parse_reparse_symlink(struct reparse_symlink_data_buffer * sym,u32 plen,bool unicode,struct cifs_sb_info * cifs_sb,const char * full_path,struct cifs_open_info_data * data)623 static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym,
624 u32 plen, bool unicode,
625 struct cifs_sb_info *cifs_sb,
626 const char *full_path,
627 struct cifs_open_info_data *data)
628 {
629 unsigned int len;
630 unsigned int offs;
631
632 /* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */
633
634 offs = le16_to_cpu(sym->SubstituteNameOffset);
635 len = le16_to_cpu(sym->SubstituteNameLength);
636 if (offs + 20 > plen || offs + len + 20 > plen) {
637 cifs_dbg(VFS, "srv returned malformed symlink buffer\n");
638 return -EIO;
639 }
640
641 return smb2_parse_native_symlink(&data->symlink_target,
642 sym->PathBuffer + offs,
643 len,
644 unicode,
645 le32_to_cpu(sym->Flags) & SYMLINK_FLAG_RELATIVE,
646 full_path,
647 cifs_sb);
648 }
649
parse_reparse_wsl_symlink(struct reparse_wsl_symlink_data_buffer * buf,struct cifs_sb_info * cifs_sb,struct cifs_open_info_data * data)650 static int parse_reparse_wsl_symlink(struct reparse_wsl_symlink_data_buffer *buf,
651 struct cifs_sb_info *cifs_sb,
652 struct cifs_open_info_data *data)
653 {
654 int len = le16_to_cpu(buf->ReparseDataLength);
655 int symname_utf8_len;
656 __le16 *symname_utf16;
657 int symname_utf16_len;
658
659 if (len <= sizeof(buf->Flags)) {
660 cifs_dbg(VFS, "srv returned malformed wsl symlink buffer\n");
661 return -EIO;
662 }
663
664 /* PathBuffer is in UTF-8 but without trailing null-term byte */
665 symname_utf8_len = len - sizeof(buf->Flags);
666 /*
667 * Check that buffer does not contain null byte
668 * because Linux cannot process symlink with null byte.
669 */
670 if (strnlen(buf->PathBuffer, symname_utf8_len) != symname_utf8_len) {
671 cifs_dbg(VFS, "srv returned null byte in wsl symlink target location\n");
672 return -EIO;
673 }
674 symname_utf16 = kzalloc(symname_utf8_len * 2, GFP_KERNEL);
675 if (!symname_utf16)
676 return -ENOMEM;
677 symname_utf16_len = utf8s_to_utf16s(buf->PathBuffer, symname_utf8_len,
678 UTF16_LITTLE_ENDIAN,
679 (wchar_t *) symname_utf16, symname_utf8_len * 2);
680 if (symname_utf16_len < 0) {
681 kfree(symname_utf16);
682 return symname_utf16_len;
683 }
684 symname_utf16_len *= 2; /* utf8s_to_utf16s() returns number of u16 items, not byte length */
685
686 data->symlink_target = cifs_strndup_from_utf16((u8 *)symname_utf16,
687 symname_utf16_len, true,
688 cifs_sb->local_nls);
689 kfree(symname_utf16);
690 if (!data->symlink_target)
691 return -ENOMEM;
692
693 return 0;
694 }
695
parse_reparse_point(struct reparse_data_buffer * buf,u32 plen,struct cifs_sb_info * cifs_sb,const char * full_path,bool unicode,struct cifs_open_info_data * data)696 int parse_reparse_point(struct reparse_data_buffer *buf,
697 u32 plen, struct cifs_sb_info *cifs_sb,
698 const char *full_path,
699 bool unicode, struct cifs_open_info_data *data)
700 {
701 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
702
703 data->reparse.buf = buf;
704
705 /* See MS-FSCC 2.1.2 */
706 switch (le32_to_cpu(buf->ReparseTag)) {
707 case IO_REPARSE_TAG_NFS:
708 return parse_reparse_posix((struct reparse_posix_data *)buf,
709 cifs_sb, data);
710 case IO_REPARSE_TAG_SYMLINK:
711 return parse_reparse_symlink(
712 (struct reparse_symlink_data_buffer *)buf,
713 plen, unicode, cifs_sb, full_path, data);
714 case IO_REPARSE_TAG_LX_SYMLINK:
715 return parse_reparse_wsl_symlink(
716 (struct reparse_wsl_symlink_data_buffer *)buf,
717 cifs_sb, data);
718 case IO_REPARSE_TAG_AF_UNIX:
719 case IO_REPARSE_TAG_LX_FIFO:
720 case IO_REPARSE_TAG_LX_CHR:
721 case IO_REPARSE_TAG_LX_BLK:
722 if (le16_to_cpu(buf->ReparseDataLength) != 0) {
723 cifs_dbg(VFS, "srv returned malformed buffer for reparse point: 0x%08x\n",
724 le32_to_cpu(buf->ReparseTag));
725 return -EIO;
726 }
727 break;
728 default:
729 cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n",
730 le32_to_cpu(buf->ReparseTag));
731 break;
732 }
733 return 0;
734 }
735
smb2_parse_reparse_point(struct cifs_sb_info * cifs_sb,const char * full_path,struct kvec * rsp_iov,struct cifs_open_info_data * data)736 int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
737 const char *full_path,
738 struct kvec *rsp_iov,
739 struct cifs_open_info_data *data)
740 {
741 struct reparse_data_buffer *buf;
742 struct smb2_ioctl_rsp *io = rsp_iov->iov_base;
743 u32 plen = le32_to_cpu(io->OutputCount);
744
745 buf = (struct reparse_data_buffer *)((u8 *)io +
746 le32_to_cpu(io->OutputOffset));
747 return parse_reparse_point(buf, plen, cifs_sb, full_path, true, data);
748 }
749
wsl_to_fattr(struct cifs_open_info_data * data,struct cifs_sb_info * cifs_sb,u32 tag,struct cifs_fattr * fattr)750 static void wsl_to_fattr(struct cifs_open_info_data *data,
751 struct cifs_sb_info *cifs_sb,
752 u32 tag, struct cifs_fattr *fattr)
753 {
754 struct smb2_file_full_ea_info *ea;
755 u32 next = 0;
756
757 switch (tag) {
758 case IO_REPARSE_TAG_LX_SYMLINK:
759 fattr->cf_mode |= S_IFLNK;
760 break;
761 case IO_REPARSE_TAG_LX_FIFO:
762 fattr->cf_mode |= S_IFIFO;
763 break;
764 case IO_REPARSE_TAG_AF_UNIX:
765 fattr->cf_mode |= S_IFSOCK;
766 break;
767 case IO_REPARSE_TAG_LX_CHR:
768 fattr->cf_mode |= S_IFCHR;
769 break;
770 case IO_REPARSE_TAG_LX_BLK:
771 fattr->cf_mode |= S_IFBLK;
772 break;
773 }
774
775 if (!data->wsl.eas_len)
776 goto out;
777
778 ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
779 do {
780 const char *name;
781 void *v;
782 u8 nlen;
783
784 ea = (void *)((u8 *)ea + next);
785 next = le32_to_cpu(ea->next_entry_offset);
786 if (!le16_to_cpu(ea->ea_value_length))
787 continue;
788
789 name = ea->ea_data;
790 nlen = ea->ea_name_length;
791 v = (void *)((u8 *)ea->ea_data + ea->ea_name_length + 1);
792
793 if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen))
794 fattr->cf_uid = wsl_make_kuid(cifs_sb, v);
795 else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen))
796 fattr->cf_gid = wsl_make_kgid(cifs_sb, v);
797 else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen))
798 fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v);
799 else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen))
800 fattr->cf_rdev = reparse_mkdev(v);
801 } while (next);
802 out:
803 fattr->cf_dtype = S_DT(fattr->cf_mode);
804 }
805
posix_reparse_to_fattr(struct cifs_sb_info * cifs_sb,struct cifs_fattr * fattr,struct cifs_open_info_data * data)806 static bool posix_reparse_to_fattr(struct cifs_sb_info *cifs_sb,
807 struct cifs_fattr *fattr,
808 struct cifs_open_info_data *data)
809 {
810 struct reparse_posix_data *buf = data->reparse.posix;
811
812
813 if (buf == NULL)
814 return true;
815
816 if (le16_to_cpu(buf->ReparseDataLength) < sizeof(buf->InodeType)) {
817 WARN_ON_ONCE(1);
818 return false;
819 }
820
821 switch (le64_to_cpu(buf->InodeType)) {
822 case NFS_SPECFILE_CHR:
823 if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8) {
824 WARN_ON_ONCE(1);
825 return false;
826 }
827 fattr->cf_mode |= S_IFCHR;
828 fattr->cf_rdev = reparse_mkdev(buf->DataBuffer);
829 break;
830 case NFS_SPECFILE_BLK:
831 if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8) {
832 WARN_ON_ONCE(1);
833 return false;
834 }
835 fattr->cf_mode |= S_IFBLK;
836 fattr->cf_rdev = reparse_mkdev(buf->DataBuffer);
837 break;
838 case NFS_SPECFILE_FIFO:
839 fattr->cf_mode |= S_IFIFO;
840 break;
841 case NFS_SPECFILE_SOCK:
842 fattr->cf_mode |= S_IFSOCK;
843 break;
844 case NFS_SPECFILE_LNK:
845 fattr->cf_mode |= S_IFLNK;
846 break;
847 default:
848 WARN_ON_ONCE(1);
849 return false;
850 }
851 return true;
852 }
853
cifs_reparse_point_to_fattr(struct cifs_sb_info * cifs_sb,struct cifs_fattr * fattr,struct cifs_open_info_data * data)854 bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
855 struct cifs_fattr *fattr,
856 struct cifs_open_info_data *data)
857 {
858 u32 tag = data->reparse.tag;
859 bool ok;
860
861 switch (tag) {
862 case IO_REPARSE_TAG_INTERNAL:
863 if (!(fattr->cf_cifsattrs & ATTR_DIRECTORY))
864 return false;
865 fallthrough;
866 case IO_REPARSE_TAG_DFS:
867 case IO_REPARSE_TAG_DFSR:
868 case IO_REPARSE_TAG_MOUNT_POINT:
869 /* See cifs_create_junction_fattr() */
870 fattr->cf_mode = S_IFDIR | 0711;
871 break;
872 case IO_REPARSE_TAG_LX_SYMLINK:
873 case IO_REPARSE_TAG_LX_FIFO:
874 case IO_REPARSE_TAG_AF_UNIX:
875 case IO_REPARSE_TAG_LX_CHR:
876 case IO_REPARSE_TAG_LX_BLK:
877 wsl_to_fattr(data, cifs_sb, tag, fattr);
878 break;
879 case IO_REPARSE_TAG_NFS:
880 ok = posix_reparse_to_fattr(cifs_sb, fattr, data);
881 if (!ok)
882 return false;
883 break;
884 case 0: /* SMB1 symlink */
885 case IO_REPARSE_TAG_SYMLINK:
886 fattr->cf_mode |= S_IFLNK;
887 break;
888 default:
889 return false;
890 }
891
892 fattr->cf_dtype = S_DT(fattr->cf_mode);
893 return true;
894 }
895