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
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)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
nfs_set_reparse_buf(struct reparse_posix_data * buf,mode_t mode,dev_t dev,struct kvec * iov)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
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)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
wsl_set_reparse_buf(struct reparse_data_buffer * buf,mode_t mode,struct kvec * iov)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
ea_create_context(u32 dlen,size_t * cc_len)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
wsl_set_xattrs(struct inode * inode,umode_t _mode,dev_t _dev,struct kvec * iov)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
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)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
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)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 */
parse_reparse_posix(struct reparse_posix_data * buf,struct cifs_sb_info * cifs_sb,struct cifs_open_info_data * data)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
parse_reparse_symlink(struct reparse_symlink_data_buffer * sym,u32 plen,bool unicode,struct cifs_sb_info * cifs_sb,struct cifs_open_info_data * data)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
parse_reparse_point(struct reparse_data_buffer * buf,u32 plen,struct cifs_sb_info * cifs_sb,bool unicode,struct cifs_open_info_data * data)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
smb2_parse_reparse_point(struct cifs_sb_info * cifs_sb,struct kvec * rsp_iov,struct cifs_open_info_data * data)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
wsl_to_fattr(struct cifs_open_info_data * data,struct cifs_sb_info * cifs_sb,u32 tag,struct cifs_fattr * fattr)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
cifs_reparse_point_to_fattr(struct cifs_sb_info * cifs_sb,struct cifs_fattr * fattr,struct cifs_open_info_data * data)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