/** * sys_fsconfig - Set parameters and trigger actions on a context * @fd: The filesystem context to act upon * @cmd: The action to take * @_key: Where appropriate, the parameter key to set * @_value: Where appropriate, the parameter value to set * @aux: Additional information for the value * * This system call is used to set parameters on a context, including * superblock settings, data source and security labelling. * * (*) fsconfig_set_fd: An open file descriptor is specified. @_value must be * NULL and @aux indicates the file descriptor. */
structfs_context { conststructfs_context_operations *ops; structmutexuapi_mutex;/* Userspace access mutex */ structfile_system_type *fs_type; void *fs_private; /* The filesystem's context */ void *sget_key; structdentry *root;/* The root and superblock */ structuser_namespace *user_ns;/* The user namespace for this mount */ structnet *net_ns;/* The network namespace for this mount */ conststructcred *cred;/* The mounter's credentials */ structp_loglog;/* Logging buffer */ constchar *source; /* The source name (eg. dev path) */ void *security; /* Linux S&M options */ void *s_fs_info; /* Proposed s_fs_info */ unsignedint sb_flags; /* Proposed superblock flags (SB_*) */ unsignedint sb_flags_mask; /* Superblock flags that were changed */ unsignedint s_iflags; /* OR'd with sb->s_iflags */ unsignedint lsm_flags; /* Information flags from the fs to the LSM */ enumfs_context_purposepurpose:8; enumfs_context_phasephase:8; /* The phase the context is in */ bool need_free:1; /* Need to call ops->free() */ bool global:1; /* Goes into &init_user_ns */ bool oldapi:1; /* Coming from mount(2) */ };
fs_parameter 结构体
1 2 3 4 5 6 7 8 9 10 11 12
structfs_parameter { constchar *key; /* Parameter name */ enumfs_value_typetype:8; /* The type of value here */ union { char *string; void *blob; structfilename *name; structfile *file; }; size_t size; int dirfd; };
intvfs_parse_fs_param(struct fs_context *fc, struct fs_parameter *param) { int ret;
if (!param->key) return invalf(fc, "Unnamed parameter\n"); ··· if (fc->ops->parse_param) { // 若存在 parse_apram 函数则调用解析 ret = fc->ops->parse_param(fc, param); // 进入 if (ret != -ENOPARAM) return ret; }
/* If the filesystem doesn't take any arguments, give it the * default handling of source. */ if (strcmp(param->key, "source") == 0) { // [!] 注意这里,对 param->type 进行了 string 的判断,是全面的 if (param->type != fs_value_is_string) return invalf(fc, "VFS: Non-string source"); if (fc->source) return invalf(fc, "VFS: Multiple sources"); fc->source = param->string; param->string = NULL; return0; }
/* * Type of parameter value. */ enumfs_value_type { fs_value_is_undefined, fs_value_is_flag, /* Value not given a value */ fs_value_is_string, /* Value is a string */ fs_value_is_blob, /* Value is a binary blob */ fs_value_is_filename, /* Value is a filename* + dirfd */ fs_value_is_file, /* Value is a file* */ };
structfs_parameter { constchar *key; /* Parameter name */ enumfs_value_typetype:8; /* The type of value here */ union { char *string; void *blob; structfilename *name; structfile *file; }; size_t size; int dirfd; };
string 所在的字段是一个联合体,根据 fs_value_type 来确定,而由于之前的设定,此处的 type 为:
所以此时相当于将系统调用传入的最后一个参数指向的 file 结构体的指针赋值给了 fc->context。而正常的逻辑应该是这里只想传递一下字符串。此时将文件结构体认为是字符串,后面在 close 文件系统描述符的时候就会发生非法释放该结构体。
structfile { union { structllist_nodefu_llist; structrcu_headfu_rcuhead; } f_u; structpathf_path; structinode *f_inode;/* cached value */ conststructfile_operations *f_op;
/* * Protects f_ep, f_flags. * Must not be taken from IRQ context. */ spinlock_t f_lock; enumrw_hintf_write_hint; atomic_long_t f_count; unsignedint f_flags; fmode_t f_mode; //读写权限 structmutexf_pos_lock; loff_t f_pos; structfown_structf_owner; conststructcred *f_cred; structfile_ra_statef_ra;
u64 f_version; #ifdef CONFIG_SECURITY void *f_security; #endif /* needed for tty driver, and maybe others */ void *private_data;
#ifdef CONFIG_EPOLL /* Used by fs/eventpoll.c to link all the hooks to this file */ structhlist_head *f_ep; #endif/* #ifdef CONFIG_EPOLL */ structaddress_space *f_mapping; errseq_t f_wb_err; errseq_t f_sb_err; /* for syncfs */ } __randomize_layout __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */