summaryrefslogtreecommitdiffstats
path: root/fs/smb/server/vfs.h
diff options
context:
space:
mode:
authorJinke Han <jinkehan@didiglobal.com>2026-09-08 15:37:42 +0800
committerIngo Molnar <mingo@kernel.org>2026-09-17 09:48:42 +0200
commita5f7a5bb3b7f28ba7e4fa246775b29a0e5537255 (patch)
tree73fef824f9a846cf935869d0dbc5070ef6e2f741 /fs/smb/server/vfs.h
downloadlinux-stable-a5f7a5bb3b7f28ba7e4fa246775b29a0e5537255.tar.gz
linux-stable-a5f7a5bb3b7f28ba7e4fa246775b29a0e5537255.zip
x86/kprobes: Fix crash when probing CS CALL instructionsgrafted
When using eBPF to probe CS CALL instructions within a function, a crash can be triggered. The eBPF tool probes offset 257 of the __hrtimer_run_queues() function: <__hrtimer_run_queues+249>: nopl 0x0(%rax,%rax,1) <__hrtimer_run_queues+254>: mov %r14,%rdi <__hrtimer_run_queues+257>: cs call <__x86_indirect_thunk_r12> <__hrtimer_run_queues+263>: mov %eax,%r12d <__hrtimer_run_queues+266>: xchg %ax,%ax <__hrtimer_run_queues+268>: mov %r13,%rdi Which triggers this crash: BUG: unable to handle page fault for address: 00000000000f41c9 #PF: supervisor write access in kernel mode #PF: error_code(0x0002) - not-present page PGD 0 P4D 0 Oops: 0002 [#1] SMP NOPTI CPU: 1 PID: 0 Comm: swapper/1 Kdump: loaded Tainted: P RIP: 0010:__hrtimer_run_queues+0x106/0x230 Note that __hrtimer_run_queues+0x106 is __hrtimer_run_queues+262, which is at the 6th byte of the above CS CALL instruction. Since the CS CALL instruction occupies 6 bytes, the exception occurred in the middle of that call instruction. The root cause is that when using eBPF tools to probe in the middle of a function, a kprobe with INT3 is used as the underlying implementation. During single-step emulation of the original CALL instruction, int3_emulate_call() assumes that the probed CALL instruction is 5 bytes long. However, the actual CS-prefixed CALL instruction occupies 6 bytes, so it constructs an incorrect exception return address. When the CPU returns from the kprobe handler, the next instruction to be executed is at the address of the last byte of that CS CALL instruction. Coincidentally, starting from that address, the CPU fetches and decodes a completely different instruction, which ultimately triggers a kernel crash. Fix the issue by using the actual instruction length obtained from the instruction decoder when constructing the exception return address, rather than relying on the hardcoded CALL_INSN_SIZE macro. [ mingo: Refined the changelog ] Fixes: 6256e668b7af ("x86/kprobes: Use int3 instead of debug trap for single-step") Suggested-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Signed-off-by: Jinke Han <jinkehan@didiglobal.com> Signed-off-by: Ingo Molnar <mingo@kernel.org> Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Acked-by: Yafang Shao <laoar.shao@gmail.com> Acked-by: Borislav Petkov <bp@alien8.de> Cc: Peter Zijlstra <peterz@infradead.org> Link: https://patch.msgid.link/20260908073742.GA10517@didi-ThinkCentre-M920t-N000
Diffstat (limited to 'fs/smb/server/vfs.h')
-rw-r--r--fs/smb/server/vfs.h184
1 files changed, 184 insertions, 0 deletions
diff --git a/fs/smb/server/vfs.h b/fs/smb/server/vfs.h
new file mode 100644
index 000000000..55d099de7
--- /dev/null
+++ b/fs/smb/server/vfs.h
@@ -0,0 +1,184 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org>
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
+ */
+
+#ifndef __KSMBD_VFS_H__
+#define __KSMBD_VFS_H__
+
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <uapi/linux/xattr.h>
+#include <linux/posix_acl.h>
+#include <linux/unicode.h>
+
+#include "smbacl.h"
+#include "xattr.h"
+
+/*
+ * Enumeration for stream type.
+ */
+enum {
+ DATA_STREAM = 1, /* type $DATA */
+ DIR_STREAM /* type $INDEX_ALLOCATION */
+};
+
+/* CreateOptions */
+#define CREATE_TREE_CONNECTION cpu_to_le32(0x00000080)
+#define FILE_RESERVE_OPFILTER_LE cpu_to_le32(0x00100000)
+
+#define CREATE_OPTION_READONLY 0x10000000
+/* system. NB not sent over wire */
+#define CREATE_OPTION_SPECIAL 0x20000000
+
+struct ksmbd_work;
+struct ksmbd_file;
+struct ksmbd_conn;
+
+struct ksmbd_dir_info {
+ const char *name;
+ char *wptr;
+ char *rptr;
+ int name_len;
+ int out_buf_len;
+ int num_scan;
+ int num_entry;
+ int data_count;
+ int last_entry_offset;
+ bool hide_dot_file;
+ int flags;
+ int last_entry_off_align;
+};
+
+struct ksmbd_readdir_data {
+ struct dir_context ctx;
+ union {
+ void *private;
+ char *dirent;
+ };
+
+ unsigned int used;
+ unsigned int dirent_count;
+ unsigned int file_attr;
+ struct unicode_map *um;
+};
+
+/* ksmbd kstat wrapper to get valid create time when reading dir entry */
+struct ksmbd_kstat {
+ struct kstat *kstat;
+ unsigned long long create_time;
+ __le32 file_attributes;
+ bool has_ads_stream; /* AAPL READDIR_ATTR V2 xattr-presence flag */
+};
+
+int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child);
+void ksmbd_vfs_query_maximal_access(struct mnt_idmap *idmap,
+ struct dentry *dentry, __le32 *daccess);
+int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode);
+int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode);
+int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count,
+ loff_t *pos, char *rbuf);
+int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp,
+ char *buf, size_t count, loff_t *pos, bool sync,
+ ssize_t *written);
+int ksmbd_vfs_fsync(struct ksmbd_work *work, u64 fid, u64 p_id);
+int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path);
+int ksmbd_vfs_link(struct ksmbd_work *work,
+ const char *oldname, const char *newname);
+int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat);
+int ksmbd_vfs_rename(struct ksmbd_work *work, struct ksmbd_file *old_fp,
+ char *newname, int flags);
+int ksmbd_vfs_check_rename_share(struct ksmbd_work *work,
+ const struct path *old_path);
+int ksmbd_vfs_truncate(struct ksmbd_work *work,
+ struct ksmbd_file *fp, loff_t size);
+struct srv_copychunk;
+int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
+ struct ksmbd_file *src_fp,
+ struct ksmbd_file *dst_fp,
+ struct srv_copychunk *chunks,
+ unsigned int chunk_count,
+ unsigned int *chunk_count_written,
+ unsigned int *chunk_size_written,
+ loff_t *total_size_written);
+ssize_t ksmbd_vfs_listxattr(struct dentry *dentry, char **list);
+ssize_t ksmbd_vfs_getxattr(struct mnt_idmap *idmap,
+ struct dentry *dentry,
+ char *xattr_name,
+ char **xattr_buf);
+ssize_t ksmbd_vfs_casexattr_len(struct mnt_idmap *idmap,
+ struct dentry *dentry, char *attr_name,
+ int attr_name_len);
+int ksmbd_vfs_setxattr(struct mnt_idmap *idmap,
+ const struct path *path, const char *attr_name,
+ void *attr_value, size_t attr_size, int flags,
+ bool get_write);
+int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name,
+ size_t *xattr_stream_name_size, int s_type);
+int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap,
+ const struct path *path, char *attr_name,
+ bool get_write);
+int ksmbd_vfs_kern_path(struct ksmbd_work *work, char *name,
+ unsigned int flags,
+ struct path *path, bool caseless);
+int ksmbd_vfs_kern_path_start_removing(struct ksmbd_work *work, char *name,
+ unsigned int flags,
+ struct path *path, bool caseless);
+void ksmbd_vfs_kern_path_end_removing(const struct path *path);
+struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work,
+ const char *name,
+ unsigned int flags,
+ struct path *path);
+int ksmbd_vfs_empty_dir(struct ksmbd_file *fp);
+void ksmbd_vfs_set_fadvise(struct file *filp, __le32 option);
+int ksmbd_vfs_zero_data(struct ksmbd_work *work, struct ksmbd_file *fp,
+ loff_t off, loff_t len);
+int ksmbd_vfs_zero_holes(struct ksmbd_file *fp);
+int ksmbd_vfs_trim_data(struct ksmbd_work *work, struct ksmbd_file *fp,
+ loff_t off, loff_t len);
+struct file_allocated_range_buffer;
+int ksmbd_vfs_query_allocated_ranges(struct ksmbd_file *fp, loff_t start,
+ loff_t length,
+ struct file_allocated_range_buffer *ranges,
+ unsigned int in_count,
+ unsigned int *out_count);
+int ksmbd_vfs_unlink(struct file *filp);
+void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat);
+int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work,
+ struct mnt_idmap *idmap,
+ struct dentry *dentry,
+ struct ksmbd_kstat *ksmbd_kstat);
+void ksmbd_vfs_posix_lock_wait(struct file_lock *flock);
+void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock);
+int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,
+ const struct path *path);
+int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap, const struct path *path);
+int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
+ struct mnt_idmap *idmap,
+ const struct path *path,
+ struct smb_ntsd *pntsd, int len,
+ bool get_write);
+int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
+ struct mnt_idmap *idmap,
+ struct dentry *dentry,
+ struct smb_ntsd **pntsd);
+int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
+ const struct path *path,
+ struct xattr_dos_attrib *da,
+ bool get_write);
+int ksmbd_vfs_get_dos_attrib_xattr(struct mnt_idmap *idmap,
+ struct dentry *dentry,
+ struct xattr_dos_attrib *da);
+int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,
+ const struct path *path);
+int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
+ const struct path *path,
+ struct inode *parent_inode);
+void ksmbd_vfs_update_compressed_fattr(struct dentry *dentry, __le32 *fattr);
+int ksmbd_vfs_get_compression(struct ksmbd_file *fp, u16 *fmt);
+int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u16 fmt);
+int ksmbd_vfs_set_compression_create(struct ksmbd_work *work,
+ struct ksmbd_file *fp, u16 fmt);
+#endif /* __KSMBD_VFS_H__ */