Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag '5.15-rc2-ksmbd-fixes' of git://git.samba.org/ksmbd

Pull ksmbd fixes from Steve French:
"Five fixes for the ksmbd kernel server, including three security
fixes:

- remove follow symlinks support

- use LOOKUP_BENEATH to prevent out of share access

- SMB3 compounding security fix

- fix for returning the default streams correctly, fixing a bug when
writing ppt or doc files from some clients

- logging more clearly that ksmbd is experimental (at module load
time)"

* tag '5.15-rc2-ksmbd-fixes' of git://git.samba.org/ksmbd:
ksmbd: use LOOKUP_BENEATH to prevent the out of share access
ksmbd: remove follow symlinks support
ksmbd: check protocol id in ksmbd_verify_smb_message()
ksmbd: add default data stream name in FILE_STREAM_INFORMATION
ksmbd: log that server is experimental at module load

+169 -265
+19 -81
fs/ksmbd/misc.c
··· 158 158 * Return : windows path string or error 159 159 */ 160 160 161 - char *convert_to_nt_pathname(char *filename, char *sharepath) 161 + char *convert_to_nt_pathname(char *filename) 162 162 { 163 163 char *ab_pathname; 164 - int len, name_len; 165 164 166 - name_len = strlen(filename); 167 - ab_pathname = kmalloc(name_len, GFP_KERNEL); 168 - if (!ab_pathname) 169 - return NULL; 165 + if (strlen(filename) == 0) { 166 + ab_pathname = kmalloc(2, GFP_KERNEL); 167 + ab_pathname[0] = '\\'; 168 + ab_pathname[1] = '\0'; 169 + } else { 170 + ab_pathname = kstrdup(filename, GFP_KERNEL); 171 + if (!ab_pathname) 172 + return NULL; 170 173 171 - ab_pathname[0] = '\\'; 172 - ab_pathname[1] = '\0'; 173 - 174 - len = strlen(sharepath); 175 - if (!strncmp(filename, sharepath, len) && name_len != len) { 176 - strscpy(ab_pathname, &filename[len], name_len); 177 174 ksmbd_conv_path_to_windows(ab_pathname); 178 175 } 179 - 180 176 return ab_pathname; 181 177 } 182 178 ··· 187 191 return nlink; 188 192 } 189 193 190 - char *ksmbd_conv_path_to_unix(char *path) 194 + void ksmbd_conv_path_to_unix(char *path) 191 195 { 192 - size_t path_len, remain_path_len, out_path_len; 193 - char *out_path, *out_next; 194 - int i, pre_dotdot_cnt = 0, slash_cnt = 0; 195 - bool is_last; 196 - 197 196 strreplace(path, '\\', '/'); 198 - path_len = strlen(path); 199 - remain_path_len = path_len; 200 - if (path_len == 0) 201 - return ERR_PTR(-EINVAL); 197 + } 202 198 203 - out_path = kzalloc(path_len + 2, GFP_KERNEL); 204 - if (!out_path) 205 - return ERR_PTR(-ENOMEM); 206 - out_path_len = 0; 207 - out_next = out_path; 199 + void ksmbd_strip_last_slash(char *path) 200 + { 201 + int len = strlen(path); 208 202 209 - do { 210 - char *name = path + path_len - remain_path_len; 211 - char *next = strchrnul(name, '/'); 212 - size_t name_len = next - name; 213 - 214 - is_last = !next[0]; 215 - if (name_len == 2 && name[0] == '.' && name[1] == '.') { 216 - pre_dotdot_cnt++; 217 - /* handle the case that path ends with "/.." */ 218 - if (is_last) 219 - goto follow_dotdot; 220 - } else { 221 - if (pre_dotdot_cnt) { 222 - follow_dotdot: 223 - slash_cnt = 0; 224 - for (i = out_path_len - 1; i >= 0; i--) { 225 - if (out_path[i] == '/' && 226 - ++slash_cnt == pre_dotdot_cnt + 1) 227 - break; 228 - } 229 - 230 - if (i < 0 && 231 - slash_cnt != pre_dotdot_cnt) { 232 - kfree(out_path); 233 - return ERR_PTR(-EINVAL); 234 - } 235 - 236 - out_next = &out_path[i+1]; 237 - *out_next = '\0'; 238 - out_path_len = i + 1; 239 - 240 - } 241 - 242 - if (name_len != 0 && 243 - !(name_len == 1 && name[0] == '.') && 244 - !(name_len == 2 && name[0] == '.' && name[1] == '.')) { 245 - next[0] = '\0'; 246 - sprintf(out_next, "%s/", name); 247 - out_next += name_len + 1; 248 - out_path_len += name_len + 1; 249 - next[0] = '/'; 250 - } 251 - pre_dotdot_cnt = 0; 252 - } 253 - 254 - remain_path_len -= name_len + 1; 255 - } while (!is_last); 256 - 257 - if (out_path_len > 0) 258 - out_path[out_path_len-1] = '\0'; 259 - path[path_len] = '\0'; 260 - return out_path; 203 + while (len && path[len - 1] == '/') { 204 + path[len - 1] = '\0'; 205 + len--; 206 + } 261 207 } 262 208 263 209 void ksmbd_conv_path_to_windows(char *path) ··· 236 298 * 237 299 * Return: converted name on success, otherwise NULL 238 300 */ 239 - char *convert_to_unix_name(struct ksmbd_share_config *share, char *name) 301 + char *convert_to_unix_name(struct ksmbd_share_config *share, const char *name) 240 302 { 241 303 int no_slash = 0, name_len, path_len; 242 304 char *new_name;
+4 -3
fs/ksmbd/misc.h
··· 14 14 int match_pattern(const char *str, size_t len, const char *pattern); 15 15 int ksmbd_validate_filename(char *filename); 16 16 int parse_stream_name(char *filename, char **stream_name, int *s_type); 17 - char *convert_to_nt_pathname(char *filename, char *sharepath); 17 + char *convert_to_nt_pathname(char *filename); 18 18 int get_nlink(struct kstat *st); 19 - char *ksmbd_conv_path_to_unix(char *path); 19 + void ksmbd_conv_path_to_unix(char *path); 20 + void ksmbd_strip_last_slash(char *path); 20 21 void ksmbd_conv_path_to_windows(char *path); 21 22 char *ksmbd_extract_sharename(char *treename); 22 - char *convert_to_unix_name(struct ksmbd_share_config *share, char *name); 23 + char *convert_to_unix_name(struct ksmbd_share_config *share, const char *name); 23 24 24 25 #define KSMBD_DIR_INFO_ALIGNMENT 8 25 26 struct ksmbd_dir_info;
+3
fs/ksmbd/server.c
··· 584 584 ret = ksmbd_workqueue_init(); 585 585 if (ret) 586 586 goto err_crypto_destroy; 587 + 588 + pr_warn_once("The ksmbd server is experimental, use at your own risk.\n"); 589 + 587 590 return 0; 588 591 589 592 err_crypto_destroy:
+38 -81
fs/ksmbd/smb2pdu.c
··· 433 433 work->compound_pfid = KSMBD_NO_FID; 434 434 } 435 435 memset((char *)rsp_hdr + 4, 0, sizeof(struct smb2_hdr) + 2); 436 - rsp_hdr->ProtocolId = rcv_hdr->ProtocolId; 436 + rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; 437 437 rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; 438 438 rsp_hdr->Command = rcv_hdr->Command; 439 439 ··· 634 634 smb2_get_name(struct ksmbd_share_config *share, const char *src, 635 635 const int maxlen, struct nls_table *local_nls) 636 636 { 637 - char *name, *norm_name, *unixname; 637 + char *name; 638 638 639 639 name = smb_strndup_from_utf16(src, maxlen, 1, local_nls); 640 640 if (IS_ERR(name)) { ··· 642 642 return name; 643 643 } 644 644 645 - /* change it to absolute unix name */ 646 - norm_name = ksmbd_conv_path_to_unix(name); 647 - if (IS_ERR(norm_name)) { 648 - kfree(name); 649 - return norm_name; 650 - } 651 - kfree(name); 652 - 653 - unixname = convert_to_unix_name(share, norm_name); 654 - kfree(norm_name); 655 - if (!unixname) { 656 - pr_err("can not convert absolute name\n"); 657 - return ERR_PTR(-ENOMEM); 658 - } 659 - 660 - ksmbd_debug(SMB, "absolute name = %s\n", unixname); 661 - return unixname; 645 + ksmbd_conv_path_to_unix(name); 646 + ksmbd_strip_last_slash(name); 647 + return name; 662 648 } 663 649 664 650 int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg) ··· 2338 2352 return rc; 2339 2353 } 2340 2354 2341 - rc = ksmbd_vfs_kern_path(name, 0, path, 0); 2355 + rc = ksmbd_vfs_kern_path(work, name, 0, path, 0); 2342 2356 if (rc) { 2343 2357 pr_err("cannot get linux path (%s), err = %d\n", 2344 2358 name, rc); ··· 2413 2427 struct oplock_info *opinfo; 2414 2428 __le32 *next_ptr = NULL; 2415 2429 int req_op_level = 0, open_flags = 0, may_flags = 0, file_info = 0; 2416 - int rc = 0, len = 0; 2430 + int rc = 0; 2417 2431 int contxt_cnt = 0, query_disk_id = 0; 2418 2432 int maximal_access_ctxt = 0, posix_ctxt = 0; 2419 2433 int s_type = 0; ··· 2485 2499 goto err_out1; 2486 2500 } 2487 2501 } else { 2488 - len = strlen(share->path); 2489 - ksmbd_debug(SMB, "share path len %d\n", len); 2490 - name = kmalloc(len + 1, GFP_KERNEL); 2502 + name = kstrdup("", GFP_KERNEL); 2491 2503 if (!name) { 2492 - rsp->hdr.Status = STATUS_NO_MEMORY; 2493 2504 rc = -ENOMEM; 2494 2505 goto err_out1; 2495 2506 } 2496 - 2497 - memcpy(name, share->path, len); 2498 - *(name + len) = '\0'; 2499 2507 } 2500 2508 2501 2509 req_op_level = req->RequestedOplockLevel; ··· 2612 2632 goto err_out1; 2613 2633 } 2614 2634 2615 - if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) { 2616 - /* 2617 - * On delete request, instead of following up, need to 2618 - * look the current entity 2619 - */ 2620 - rc = ksmbd_vfs_kern_path(name, 0, &path, 1); 2621 - if (!rc) { 2635 + rc = ksmbd_vfs_kern_path(work, name, LOOKUP_NO_SYMLINKS, &path, 1); 2636 + if (!rc) { 2637 + if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) { 2622 2638 /* 2623 2639 * If file exists with under flags, return access 2624 2640 * denied error. ··· 2633 2657 path_put(&path); 2634 2658 goto err_out; 2635 2659 } 2636 - } 2637 - } else { 2638 - if (test_share_config_flag(work->tcon->share_conf, 2639 - KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS)) { 2640 - /* 2641 - * Use LOOKUP_FOLLOW to follow the path of 2642 - * symlink in path buildup 2643 - */ 2644 - rc = ksmbd_vfs_kern_path(name, LOOKUP_FOLLOW, &path, 1); 2645 - if (rc) { /* Case for broken link ?*/ 2646 - rc = ksmbd_vfs_kern_path(name, 0, &path, 1); 2647 - } 2648 - } else { 2649 - rc = ksmbd_vfs_kern_path(name, 0, &path, 1); 2650 - if (!rc && d_is_symlink(path.dentry)) { 2651 - rc = -EACCES; 2652 - path_put(&path); 2653 - goto err_out; 2654 - } 2660 + } else if (d_is_symlink(path.dentry)) { 2661 + rc = -EACCES; 2662 + path_put(&path); 2663 + goto err_out; 2655 2664 } 2656 2665 } 2657 2666 2658 2667 if (rc) { 2659 - if (rc == -EACCES) { 2660 - ksmbd_debug(SMB, 2661 - "User does not have right permission\n"); 2668 + if (rc != -ENOENT) 2662 2669 goto err_out; 2663 - } 2664 2670 ksmbd_debug(SMB, "can not get linux path for %s, rc = %d\n", 2665 2671 name, rc); 2666 2672 rc = 0; ··· 3138 3180 rsp->hdr.Status = STATUS_INVALID_PARAMETER; 3139 3181 else if (rc == -EOPNOTSUPP) 3140 3182 rsp->hdr.Status = STATUS_NOT_SUPPORTED; 3141 - else if (rc == -EACCES || rc == -ESTALE) 3183 + else if (rc == -EACCES || rc == -ESTALE || rc == -EXDEV) 3142 3184 rsp->hdr.Status = STATUS_ACCESS_DENIED; 3143 3185 else if (rc == -ENOENT) 3144 3186 rsp->hdr.Status = STATUS_OBJECT_NAME_INVALID; ··· 4254 4296 return -EACCES; 4255 4297 } 4256 4298 4257 - filename = convert_to_nt_pathname(fp->filename, 4258 - work->tcon->share_conf->path); 4299 + filename = convert_to_nt_pathname(fp->filename); 4259 4300 if (!filename) 4260 4301 return -ENOMEM; 4261 4302 ··· 4385 4428 file_info->NextEntryOffset = cpu_to_le32(next); 4386 4429 } 4387 4430 4388 - if (nbytes) { 4431 + if (!S_ISDIR(stat.mode)) { 4389 4432 file_info = (struct smb2_file_stream_info *) 4390 4433 &rsp->Buffer[nbytes]; 4391 4434 streamlen = smbConvertToUTF16((__le16 *)file_info->StreamName, 4392 4435 "::$DATA", 7, conn->local_nls, 0); 4393 4436 streamlen *= 2; 4394 4437 file_info->StreamNameLength = cpu_to_le32(streamlen); 4395 - file_info->StreamSize = S_ISDIR(stat.mode) ? 0 : 4396 - cpu_to_le64(stat.size); 4397 - file_info->StreamAllocationSize = S_ISDIR(stat.mode) ? 0 : 4398 - cpu_to_le64(stat.size); 4438 + file_info->StreamSize = 0; 4439 + file_info->StreamAllocationSize = 0; 4399 4440 nbytes += sizeof(struct smb2_file_stream_info) + streamlen; 4400 4441 } 4401 4442 ··· 4708 4753 struct path path; 4709 4754 int rc = 0, len; 4710 4755 int fs_infoclass_size = 0; 4711 - int lookup_flags = 0; 4712 4756 4713 - if (test_share_config_flag(share, KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS)) 4714 - lookup_flags = LOOKUP_FOLLOW; 4715 - 4716 - rc = ksmbd_vfs_kern_path(share->path, lookup_flags, &path, 0); 4757 + rc = kern_path(share->path, LOOKUP_NO_SYMLINKS, &path); 4717 4758 if (rc) { 4718 4759 pr_err("cannot create vfs path\n"); 4719 4760 return -EIO; ··· 5258 5307 goto out; 5259 5308 5260 5309 len = strlen(new_name); 5261 - if (new_name[len - 1] != '/') { 5310 + if (len > 0 && new_name[len - 1] != '/') { 5262 5311 pr_err("not allow base filename in rename\n"); 5263 5312 rc = -ESHARE; 5264 5313 goto out; ··· 5286 5335 } 5287 5336 5288 5337 ksmbd_debug(SMB, "new name %s\n", new_name); 5289 - rc = ksmbd_vfs_kern_path(new_name, 0, &path, 1); 5290 - if (rc) 5338 + rc = ksmbd_vfs_kern_path(work, new_name, LOOKUP_NO_SYMLINKS, &path, 1); 5339 + if (rc) { 5340 + if (rc != -ENOENT) 5341 + goto out; 5291 5342 file_present = false; 5292 - else 5343 + } else { 5293 5344 path_put(&path); 5345 + } 5294 5346 5295 5347 if (ksmbd_share_veto_filename(share, new_name)) { 5296 5348 rc = -ENOENT; ··· 5363 5409 } 5364 5410 5365 5411 ksmbd_debug(SMB, "target name is %s\n", target_name); 5366 - rc = ksmbd_vfs_kern_path(link_name, 0, &path, 0); 5367 - if (rc) 5412 + rc = ksmbd_vfs_kern_path(work, link_name, LOOKUP_NO_SYMLINKS, &path, 0); 5413 + if (rc) { 5414 + if (rc != -ENOENT) 5415 + goto out; 5368 5416 file_present = false; 5369 - else 5417 + } else { 5370 5418 path_put(&path); 5419 + } 5371 5420 5372 5421 if (file_info->ReplaceIfExists) { 5373 5422 if (file_present) { ··· 5530 5573 * inode size is retained by backup inode size. 5531 5574 */ 5532 5575 size = i_size_read(inode); 5533 - rc = ksmbd_vfs_truncate(work, NULL, fp, alloc_blks * 512); 5576 + rc = ksmbd_vfs_truncate(work, fp, alloc_blks * 512); 5534 5577 if (rc) { 5535 5578 pr_err("truncate failed! filename : %s, err %d\n", 5536 5579 fp->filename, rc); ··· 5567 5610 if (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC) { 5568 5611 ksmbd_debug(SMB, "filename : %s truncated to newsize %lld\n", 5569 5612 fp->filename, newsize); 5570 - rc = ksmbd_vfs_truncate(work, NULL, fp, newsize); 5613 + rc = ksmbd_vfs_truncate(work, fp, newsize); 5571 5614 if (rc) { 5572 5615 ksmbd_debug(SMB, "truncate failed! filename : %s err %d\n", 5573 5616 fp->filename, rc); ··· 5844 5887 return 0; 5845 5888 5846 5889 err_out: 5847 - if (rc == -EACCES || rc == -EPERM) 5890 + if (rc == -EACCES || rc == -EPERM || rc == -EXDEV) 5848 5891 rsp->hdr.Status = STATUS_ACCESS_DENIED; 5849 5892 else if (rc == -EINVAL) 5850 5893 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
+9 -4
fs/ksmbd/smb_common.c
··· 129 129 * 130 130 * check for valid smb signature and packet direction(request/response) 131 131 * 132 - * Return: 0 on success, otherwise 1 132 + * Return: 0 on success, otherwise -EINVAL 133 133 */ 134 134 int ksmbd_verify_smb_message(struct ksmbd_work *work) 135 135 { 136 - struct smb2_hdr *smb2_hdr = work->request_buf; 136 + struct smb2_hdr *smb2_hdr = work->request_buf + work->next_smb2_rcv_hdr_off; 137 + struct smb_hdr *hdr; 137 138 138 139 if (smb2_hdr->ProtocolId == SMB2_PROTO_NUMBER) 139 140 return ksmbd_smb2_check_message(work); 140 141 141 - return 0; 142 + hdr = work->request_buf; 143 + if (*(__le32 *)hdr->Protocol == SMB1_PROTO_NUMBER && 144 + hdr->Command == SMB_COM_NEGOTIATE) 145 + return 0; 146 + 147 + return -EINVAL; 142 148 } 143 149 144 150 /** ··· 271 265 return BAD_PROT_ID; 272 266 } 273 267 274 - #define SMB_COM_NEGOTIATE 0x72 275 268 int ksmbd_init_smb_server(struct ksmbd_work *work) 276 269 { 277 270 struct ksmbd_conn *conn = work->conn;
+1
fs/ksmbd/smb_common.h
··· 210 210 FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES) 211 211 212 212 #define SMB1_PROTO_NUMBER cpu_to_le32(0x424d53ff) 213 + #define SMB_COM_NEGOTIATE 0x72 213 214 214 215 #define SMB1_CLIENT_GUID_SIZE (16) 215 216 struct smb_hdr {
+88 -94
fs/ksmbd/vfs.c
··· 19 19 #include <linux/sched/xacct.h> 20 20 #include <linux/crc32c.h> 21 21 22 + #include "../internal.h" /* for vfs_path_lookup */ 23 + 22 24 #include "glob.h" 23 25 #include "oplock.h" 24 26 #include "connection.h" ··· 46 44 p++; 47 45 } else { 48 46 p = NULL; 49 - pr_err("Invalid path %s\n", path); 50 47 } 51 48 return p; 52 49 } ··· 156 155 /** 157 156 * ksmbd_vfs_create() - vfs helper for smb create file 158 157 * @work: work 159 - * @name: file name 158 + * @name: file name that is relative to share 160 159 * @mode: file create mode 161 160 * 162 161 * Return: 0 on success, otherwise error ··· 167 166 struct dentry *dentry; 168 167 int err; 169 168 170 - dentry = kern_path_create(AT_FDCWD, name, &path, 0); 169 + dentry = ksmbd_vfs_kern_path_create(work, name, 170 + LOOKUP_NO_SYMLINKS, &path); 171 171 if (IS_ERR(dentry)) { 172 172 err = PTR_ERR(dentry); 173 173 if (err != -ENOENT) ··· 193 191 /** 194 192 * ksmbd_vfs_mkdir() - vfs helper for smb create directory 195 193 * @work: work 196 - * @name: directory name 194 + * @name: directory name that is relative to share 197 195 * @mode: directory create mode 198 196 * 199 197 * Return: 0 on success, otherwise error ··· 205 203 struct dentry *dentry; 206 204 int err; 207 205 208 - dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_DIRECTORY); 206 + dentry = ksmbd_vfs_kern_path_create(work, name, 207 + LOOKUP_NO_SYMLINKS | LOOKUP_DIRECTORY, 208 + &path); 209 209 if (IS_ERR(dentry)) { 210 210 err = PTR_ERR(dentry); 211 211 if (err != -EEXIST) ··· 582 578 583 579 /** 584 580 * ksmbd_vfs_remove_file() - vfs helper for smb rmdir or unlink 585 - * @name: absolute directory or file name 581 + * @name: directory or file name that is relative to share 586 582 * 587 583 * Return: 0 on success, otherwise error 588 584 */ ··· 592 588 struct path path; 593 589 struct dentry *parent; 594 590 int err; 595 - int flags = 0; 596 591 597 592 if (ksmbd_override_fsids(work)) 598 593 return -ENOMEM; 599 594 600 - if (test_share_config_flag(work->tcon->share_conf, 601 - KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS)) 602 - flags = LOOKUP_FOLLOW; 603 - 604 - err = kern_path(name, flags, &path); 595 + err = ksmbd_vfs_kern_path(work, name, LOOKUP_NO_SYMLINKS, &path, false); 605 596 if (err) { 606 597 ksmbd_debug(VFS, "can't get %s, err %d\n", name, err); 607 598 ksmbd_revert_fsids(work); ··· 641 642 /** 642 643 * ksmbd_vfs_link() - vfs helper for creating smb hardlink 643 644 * @oldname: source file name 644 - * @newname: hardlink name 645 + * @newname: hardlink name that is relative to share 645 646 * 646 647 * Return: 0 on success, otherwise error 647 648 */ ··· 651 652 struct path oldpath, newpath; 652 653 struct dentry *dentry; 653 654 int err; 654 - int flags = 0; 655 655 656 656 if (ksmbd_override_fsids(work)) 657 657 return -ENOMEM; 658 658 659 - if (test_share_config_flag(work->tcon->share_conf, 660 - KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS)) 661 - flags = LOOKUP_FOLLOW; 662 - 663 - err = kern_path(oldname, flags, &oldpath); 659 + err = kern_path(oldname, LOOKUP_NO_SYMLINKS, &oldpath); 664 660 if (err) { 665 661 pr_err("cannot get linux path for %s, err = %d\n", 666 662 oldname, err); 667 663 goto out1; 668 664 } 669 665 670 - dentry = kern_path_create(AT_FDCWD, newname, &newpath, 671 - flags | LOOKUP_REVAL); 666 + dentry = ksmbd_vfs_kern_path_create(work, newname, 667 + LOOKUP_NO_SYMLINKS | LOOKUP_REVAL, 668 + &newpath); 672 669 if (IS_ERR(dentry)) { 673 670 err = PTR_ERR(dentry); 674 671 pr_err("path create err for %s, err %d\n", newname, err); ··· 783 788 struct dentry *src_dent, *trap_dent, *src_child; 784 789 char *dst_name; 785 790 int err; 786 - int flags; 787 791 788 792 dst_name = extract_last_component(newname); 789 - if (!dst_name) 790 - return -EINVAL; 793 + if (!dst_name) { 794 + dst_name = newname; 795 + newname = ""; 796 + } 791 797 792 798 src_dent_parent = dget_parent(fp->filp->f_path.dentry); 793 799 src_dent = fp->filp->f_path.dentry; 794 800 795 - flags = LOOKUP_DIRECTORY; 796 - if (test_share_config_flag(work->tcon->share_conf, 797 - KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS)) 798 - flags |= LOOKUP_FOLLOW; 799 - 800 - err = kern_path(newname, flags, &dst_path); 801 + err = ksmbd_vfs_kern_path(work, newname, 802 + LOOKUP_NO_SYMLINKS | LOOKUP_DIRECTORY, 803 + &dst_path, false); 801 804 if (err) { 802 805 ksmbd_debug(VFS, "Cannot get path for %s [%d]\n", newname, err); 803 806 goto out; ··· 841 848 /** 842 849 * ksmbd_vfs_truncate() - vfs helper for smb file truncate 843 850 * @work: work 844 - * @name: old filename 845 851 * @fid: file id of old file 846 852 * @size: truncate to given size 847 853 * 848 854 * Return: 0 on success, otherwise error 849 855 */ 850 - int ksmbd_vfs_truncate(struct ksmbd_work *work, const char *name, 856 + int ksmbd_vfs_truncate(struct ksmbd_work *work, 851 857 struct ksmbd_file *fp, loff_t size) 852 858 { 853 - struct path path; 854 859 int err = 0; 860 + struct file *filp; 855 861 856 - if (name) { 857 - err = kern_path(name, 0, &path); 862 + filp = fp->filp; 863 + 864 + /* Do we need to break any of a levelII oplock? */ 865 + smb_break_all_levII_oplock(work, fp, 1); 866 + 867 + if (!work->tcon->posix_extensions) { 868 + struct inode *inode = file_inode(filp); 869 + 870 + if (size < inode->i_size) { 871 + err = check_lock_range(filp, size, 872 + inode->i_size - 1, WRITE); 873 + } else { 874 + err = check_lock_range(filp, inode->i_size, 875 + size - 1, WRITE); 876 + } 877 + 858 878 if (err) { 859 - pr_err("cannot get linux path for %s, err %d\n", 860 - name, err); 861 - return err; 879 + pr_err("failed due to lock\n"); 880 + return -EAGAIN; 862 881 } 863 - err = vfs_truncate(&path, size); 864 - if (err) 865 - pr_err("truncate failed for %s err %d\n", 866 - name, err); 867 - path_put(&path); 868 - } else { 869 - struct file *filp; 870 - 871 - filp = fp->filp; 872 - 873 - /* Do we need to break any of a levelII oplock? */ 874 - smb_break_all_levII_oplock(work, fp, 1); 875 - 876 - if (!work->tcon->posix_extensions) { 877 - struct inode *inode = file_inode(filp); 878 - 879 - if (size < inode->i_size) { 880 - err = check_lock_range(filp, size, 881 - inode->i_size - 1, WRITE); 882 - } else { 883 - err = check_lock_range(filp, inode->i_size, 884 - size - 1, WRITE); 885 - } 886 - 887 - if (err) { 888 - pr_err("failed due to lock\n"); 889 - return -EAGAIN; 890 - } 891 - } 892 - 893 - err = vfs_truncate(&filp->f_path, size); 894 - if (err) 895 - pr_err("truncate failed for filename : %s err %d\n", 896 - fp->filename, err); 897 882 } 898 883 884 + err = vfs_truncate(&filp->f_path, size); 885 + if (err) 886 + pr_err("truncate failed for filename : %s err %d\n", 887 + fp->filename, err); 899 888 return err; 900 889 } 901 890 ··· 1195 1220 1196 1221 /** 1197 1222 * ksmbd_vfs_kern_path() - lookup a file and get path info 1198 - * @name: name of file for lookup 1223 + * @name: file path that is relative to share 1199 1224 * @flags: lookup flags 1200 1225 * @path: if lookup succeed, return path info 1201 1226 * @caseless: caseless filename lookup 1202 1227 * 1203 1228 * Return: 0 on success, otherwise error 1204 1229 */ 1205 - int ksmbd_vfs_kern_path(char *name, unsigned int flags, struct path *path, 1206 - bool caseless) 1230 + int ksmbd_vfs_kern_path(struct ksmbd_work *work, char *name, 1231 + unsigned int flags, struct path *path, bool caseless) 1207 1232 { 1233 + struct ksmbd_share_config *share_conf = work->tcon->share_conf; 1208 1234 int err; 1209 1235 1210 - if (name[0] != '/') 1211 - return -EINVAL; 1212 - 1213 - err = kern_path(name, flags, path); 1236 + flags |= LOOKUP_BENEATH; 1237 + err = vfs_path_lookup(share_conf->vfs_path.dentry, 1238 + share_conf->vfs_path.mnt, 1239 + name, 1240 + flags, 1241 + path); 1214 1242 if (!err) 1215 1243 return 0; 1216 1244 ··· 1227 1249 return -ENOMEM; 1228 1250 1229 1251 path_len = strlen(filepath); 1230 - remain_len = path_len - 1; 1252 + remain_len = path_len; 1231 1253 1232 - err = kern_path("/", flags, &parent); 1233 - if (err) 1234 - goto out; 1254 + parent = share_conf->vfs_path; 1255 + path_get(&parent); 1235 1256 1236 1257 while (d_can_lookup(parent.dentry)) { 1237 1258 char *filename = filepath + path_len - remain_len; ··· 1243 1266 1244 1267 err = ksmbd_vfs_lookup_in_dir(&parent, filename, 1245 1268 filename_len); 1246 - if (err) { 1247 - path_put(&parent); 1248 - goto out; 1249 - } 1250 - 1251 1269 path_put(&parent); 1252 - next[0] = '\0'; 1253 - 1254 - err = kern_path(filepath, flags, &parent); 1255 1270 if (err) 1256 1271 goto out; 1257 1272 1258 - if (is_last) { 1259 - path->mnt = parent.mnt; 1260 - path->dentry = parent.dentry; 1273 + next[0] = '\0'; 1274 + 1275 + err = vfs_path_lookup(share_conf->vfs_path.dentry, 1276 + share_conf->vfs_path.mnt, 1277 + filepath, 1278 + flags, 1279 + &parent); 1280 + if (err) 1281 + goto out; 1282 + else if (is_last) { 1283 + *path = parent; 1261 1284 goto out; 1262 1285 } 1263 1286 ··· 1271 1294 kfree(filepath); 1272 1295 } 1273 1296 return err; 1297 + } 1298 + 1299 + struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, 1300 + const char *name, 1301 + unsigned int flags, 1302 + struct path *path) 1303 + { 1304 + char *abs_name; 1305 + struct dentry *dent; 1306 + 1307 + abs_name = convert_to_unix_name(work->tcon->share_conf, name); 1308 + if (!abs_name) 1309 + return ERR_PTR(-ENOMEM); 1310 + 1311 + dent = kern_path_create(AT_FDCWD, abs_name, path, flags); 1312 + kfree(abs_name); 1313 + return dent; 1274 1314 } 1275 1315 1276 1316 int ksmbd_vfs_remove_acl_xattrs(struct user_namespace *user_ns,
+7 -2
fs/ksmbd/vfs.h
··· 126 126 int ksmbd_vfs_getattr(struct path *path, struct kstat *stat); 127 127 int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp, 128 128 char *newname); 129 - int ksmbd_vfs_truncate(struct ksmbd_work *work, const char *name, 129 + int ksmbd_vfs_truncate(struct ksmbd_work *work, 130 130 struct ksmbd_file *fp, loff_t size); 131 131 struct srv_copychunk; 132 132 int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work, ··· 152 152 size_t *xattr_stream_name_size, int s_type); 153 153 int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns, 154 154 struct dentry *dentry, char *attr_name); 155 - int ksmbd_vfs_kern_path(char *name, unsigned int flags, struct path *path, 155 + int ksmbd_vfs_kern_path(struct ksmbd_work *work, 156 + char *name, unsigned int flags, struct path *path, 156 157 bool caseless); 158 + struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, 159 + const char *name, 160 + unsigned int flags, 161 + struct path *path); 157 162 int ksmbd_vfs_empty_dir(struct ksmbd_file *fp); 158 163 void ksmbd_vfs_set_fadvise(struct file *filp, __le32 option); 159 164 int ksmbd_vfs_zero_data(struct ksmbd_work *work, struct ksmbd_file *fp,