shell bypass 403
/** @file @brief kernel/userspace transport messages @details Copyright (c) 2017-2021 Acronis International GmbH @author Mikhail Krivtsov ([email protected]) @since $Id: $ */ #include "message.h" #include "compat.h" #include "debug.h" #include "file_path_tools.h" #include "ftrace_hooks/ftrace_events.h" #include "lsm_hooks/lsm_common.h" #include "memory.h" #include "path_tools.h" #include "si_templates.h" #include "si_writer.h" #include "si_writer_common.h" #include "task_info_map.h" #include "task_tools.h" #include <linux/file.h> // fput() #include <linux/fs_struct.h> #include <linux/mm.h> // get_task_exe_file() #include <linux/rcupdate.h> const char* msg_type_to_string(msg_type_t type) { switch (type) { #define FP_SI_MSG_TYPE(x) case FP_SI_OT_##x: return #x; #include "transport_message_types_x.h" #undef FP_SI_MSG_TYPE } return "?"; } const char* action_type_to_string(action_type_t type) { switch (type) { #define CASE_AT_RETURN(t) case AT_##t: return #t CASE_AT_RETURN(PING); CASE_AT_RETURN(GET_VERSION); CASE_AT_RETURN(OPEN_FILE_FROM_MSG); CASE_AT_RETURN(OPEN_FILE_BY_PATH); CASE_AT_RETURN(INIT_SHARED_DATA_QUEUE); CASE_AT_RETURN(WAIT_SHARED_DATA_QUEUE); CASE_AT_RETURN(FILE_CONTEXT_ADD); CASE_AT_RETURN(GET_MNT_ID_OFFSET); CASE_AT_RETURN(SET_LISTENING_MASK_GLOBAL); CASE_AT_RETURN(SET_LISTENING_MASK_PROCESS); CASE_AT_RETURN(GET_PROCESS_INFO); CASE_AT_RETURN(GET_PROCESS_PID_VERSION); CASE_AT_RETURN(SET_LISTENING_SUBTYPE_INCLUSION_MASK); CASE_AT_RETURN(SET_LISTENING_SUBTYPE_EXCLUSION_MASK); CASE_AT_RETURN(SET_TRANSPORT_CLIENT_TYPE); CASE_AT_RETURN(LAST); #undef CASE_AT_RETURN } return "?"; } const char* return_type_to_string(return_type_t type) { switch (type) { #define CASE_RT_RETURN(t) case RT_##t: return #t CASE_RT_RETURN(ERROR); CASE_RT_RETURN(OPENED_FILE); CASE_RT_RETURN(VERSION_INFO); CASE_RT_RETURN(DATA_QUEUE_OFFSETS); CASE_RT_RETURN(GET_MNT_ID_OFFSET); CASE_RT_RETURN(GET_PROCESS_INFO); CASE_RT_RETURN(GET_PROCESS_PID_VERSION); #undef CASE_RT_RETURN } return "?"; } static void msg_free(msg_t * msg) { DPRINTF("msg=%p id=%llX", msg, msg->id); if (msg->task_info) { task_info_put(msg->task_info); } atomic64_sub(msg->msg_size, &g_memory_metrics->total_msgs_size); atomic64_sub(1, &g_memory_metrics->total_msgs); kvfree_compat(msg); } msg_t *msg_ref(msg_t *msg) { atomic_inc(&msg->ref_cnt); DPRINTF("msg=%p ref_cnt=%i", msg, atomic_read(&msg->ref_cnt)); return msg; } void msg_unref(msg_t *msg) { DPRINTF("msg=%p ref_cnt=%i", msg, atomic_read(&msg->ref_cnt)); if (atomic_dec_and_test(&msg->ref_cnt)) { msg_free(msg); } } msg_t *msg_reply_wait_count_inc(msg_t *msg) { msg_ref(msg); atomic_inc(&msg->reply_wait_count); DPRINTF("msg=%p reply_wait_count=%i", msg, atomic_read(&msg->reply_wait_count)); return msg; } void msg_reply_wait_count_dec(msg_t *msg) { DPRINTF("msg=%p reply_wait_count=%i", msg, atomic_read(&msg->reply_wait_count)); if (atomic_dec_and_test(&msg->reply_wait_count)) { wake_up(&msg->wait_queue); } msg_unref(msg); } msg_sized_t* msg_varsized_init(msg_varsized_t *msg, size_t msg_img_size) { msg_sized_t* smsg; msg->on_heap = msg_img_size > MSG_MAX_SMALL_PAYLOAD_SIZE; if (msg->on_heap) { msg->data.heap.ptr = msg_sized_new(msg_img_size); } smsg = MSG_VARSIZED_GET_SIZED(msg); if (smsg) { smsg->img_size = msg_img_size; } return smsg; } void msg_varsized_uninit(msg_varsized_t *msg) { if (msg->on_heap) { atomic64_sub(msg->data.heap.ptr->img_size + sizeof(msg_sized_t), &g_memory_metrics->total_sized_msgs_size); atomic64_sub(1, &g_memory_metrics->total_sized_msgs); msg_sized_free(msg->data.heap.ptr); } } static msg_t *msg_init(msg_t *msg, uint16_t operation, SUBTYPE_MASK_TYPE subtype, uint16_t callback_type, uint64_t process_uid, size_t msg_size) { atomic_set(&msg->ref_cnt, 1); atomic_set(&msg->reply_wait_count, 0); init_waitqueue_head(&msg->wait_queue); msg->interrupted = false; msg->block = false; msg->subtype_mask = subtype; thread_safe_path_init(&msg->path); thread_safe_path_init(&msg->path2); msg->task_info = NULL; msg->file_context_msg_info = (file_context_msg_info_t) {0}; msg->id = 0; msg->msg_size = msg_size; msg->event.Size = 0; msg->event.Operation = operation; msg->event.CallbackType = callback_type; msg->event.ProcessUID = process_uid; msg->event.PropertiesNumber = 0; return msg; } msg_sized_t *msg_sized_new(size_t msg_img_size) { size_t msg_size = sizeof(msg_sized_t) + msg_img_size; msg_sized_t *msg = mem_alloc(msg_size); if (msg) { msg->img_size = msg_img_size; atomic64_add(msg_size, &g_memory_metrics->total_sized_msgs_size); atomic64_add(1, &g_memory_metrics->total_sized_msgs); } return msg; } msg_t *msg_new(uint16_t operation, SUBTYPE_MASK_TYPE subtype_mask, uint16_t callback_type, uint64_t process_uid, size_t props_size) { size_t msg_size = sizeof(msg_t) + props_size; msg_t *msg = mem_alloc(msg_size); if (msg) { msg_init(msg, operation, subtype_mask, callback_type, process_uid, msg_size); atomic64_add(msg_size, &g_memory_metrics->total_msgs_size); atomic64_add(1, &g_memory_metrics->total_msgs); } DPRINTF("msg=%p msg_size=%zu props_size=%zu", msg, msg_size, props_size); return msg; } msg_t *msg_new_with_alloc_flags(uint16_t operation, SUBTYPE_MASK_TYPE subtype_mask, uint16_t callback_type, uint64_t process_uid, size_t props_size, bool nowait) { size_t msg_size = sizeof(msg_t) + props_size; msg_t *msg; if (nowait) { msg = mem_alloc_nowait(msg_size); } else { msg = kvmalloc_compat(msg_size, GFP_KERNEL); } if (msg) { msg_init(msg, operation, subtype_mask, callback_type, process_uid, msg_size); atomic64_add(msg_size, &g_memory_metrics->total_msgs_size); atomic64_add(1, &g_memory_metrics->total_msgs); } DPRINTF("msg=%p msg_size=%zu props_size=%zu", msg, msg_size, props_size); return msg; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static const uint8_t k_hello_fields[] = { FP_SI_PI_OBJECT_NAME, }; msg_t *hello_msg_new(void) { static const char hello[] = "hello"; si_property_writer_t writer; SiSizedString hello_str; uint32_t event_size; msg_t* msg; hello_str.value = hello; hello_str.length = sizeof(hello) - 1; event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_hello_fields) + hello_str.length; msg = msg_new(FP_SI_OT_HELLO, 0, SI_CT_PRE_CALLBACK, 0, event_size); if (!msg) { return NULL; } si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_object_name(&writer, hello_str); si_event_writer_finalize(&msg->event, &writer); DPRINTF("msg=%p", msg); return msg; } // assuming correct 'ping_msg' msg_t *pong_msg_new(msg_sized_t *ping_msg, uint64_t event_uid) { request_msg_img_t *ping_msg_img = (request_msg_img_t*) MSG_IMG(ping_msg); ping_img_t *ping_img = IMG_PAYLOAD(ping_msg_img); uint32_t properties_number = ping_img->properties_number + 1; size_t ping_img_size = ping_msg->img_size - sizeof(request_msg_img_t); size_t payload_size = ping_img_size - sizeof(ping_img_t); // For 'pong' we need to add 'event_uid' property size_t img_size = payload_size + sizeof(SiProperty) + sizeof(uint64_t); msg_t* msg = msg_new(FP_SI_OT_PONG, 0, SI_CT_PRE_CALLBACK, ping_img->process_uid, img_size); if (msg) { SiProperty* event_uid_prop; msg->id = event_uid; msg->event.Size = sizeof(SiEvent) + img_size; msg->event.PropertiesNumber = properties_number; memcpy(msg->event.FirstProperty, ping_img->payload, payload_size); event_uid_prop = (SiProperty*) (((uint8_t*) msg->event.FirstProperty) + payload_size); event_uid_prop->Size = sizeof(SiProperty) + sizeof(uint64_t); event_uid_prop->PropertyId = FP_SI_PI_EVENT_UID; event_uid_prop->ValueType = SI_VT_UNSIGNED64_TYPE; *(uint64_t*) event_uid_prop->ValueBuffer = event_uid; } DPRINTF("msg=%p payload_size=%zu", msg, payload_size); return msg; } static const uint8_t k_exec_fields[] = { SI_COMMON_FIELDS, SI_COMMON_CRED_FIELDS, \ FP_SI_PI_PARENT_PROCESS_ID, FP_SI_PI_PARENT_PROCESS_UID, FP_SI_PI_PARENT_THREAD_ID, FP_SI_PI_PARENT_PROCESS_ID_VERSION, FP_SI_PI_PARENT_ARTIFICIAL_PROCESS_START_TIMESTAMP, FP_SI_PI_PARENT_PROCESS_START_TIMESTAMP, FP_SI_PI_PROCESS_START_TIMESTAMP, FP_SI_PI_UNIX_EXEC_TYPE, FP_SI_PI_ARTIFICIAL_PROCESS_START_TIMESTAMP, SI_COMMON_EXE_FILE_FIELDS, }; msg_t *heur_exec_msg_new(task_info_t *task_info, const transport_ids_t *ids) { struct path *exe_path = NULL; struct file *exe_file; bool has_parent = false; pid_t ptgid = 0, ppid = 0; uint64_t pupid = 0; SiTimeMicroseconds parent_start_time = {0}; pid_t tgid, pid; msg_t* msg; uint32_t event_size; path_info_t exe_path_info = (path_info_t){0}; file_handle_info_t exe_file_handle_info = (file_handle_info_t){0}; char comm[TASK_COMM_LEN]; tgid = current->tgid; pid = current->pid; if (!task_info_need_to_make_exec_event(task_info, ids)) return NULL; exe_file = get_task_exe_file_compat(current); // Note: kernel's threads do not have 'exe_file' if (exe_file) { exe_path = &exe_file->f_path; if (!path_is_usable(exe_path)) { exe_path = NULL; } } if (exe_path) { file_handle_info_make(&exe_file_handle_info, exe_path); path_info_make(&exe_path_info, exe_path, false /*dir*/); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_exec_fields) + SI_ESTIMATE_SIZE_PATH_INFO(exe_path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(exe_file_handle_info) + SI_CONTAINER_NAME_LIMIT; } else { get_task_comm(comm, current); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_exec_fields) + TASK_COMM_LEN; } { struct task_struct* parent; rcu_read_lock(); parent = rcu_dereference(current->real_parent); ptgid = parent ? parent->tgid : 0; has_parent = 0 != ptgid; if (has_parent) { ppid = parent->pid; pupid = make_unique_pid(parent); parent_start_time = make_process_start_time(parent); } rcu_read_unlock(); } msg = msg_new(FP_SI_OT_NOTIFY_PROCESS_EXEC, 0, SI_CT_POST_CALLBACK, make_unique_pid(current), event_size); if (msg) { si_property_writer_t writer; uint64_t event_uid = transport_global_sequence_next(); task_info_t *parent_task_info = has_parent ? task_info_map_add(ptgid, pupid, NULL /*no exe update*/, parent_start_time.microseconds) : NULL; msg->exec.pid_version = READ_ONCE(task_info->pid_version); msg->task_info = task_info_get(task_info); si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, pid, tgid, task_info); si_property_writer_write_process_start_timestamp(&writer, make_process_start_time(current)); if (has_parent) { si_property_writer_write_parent_process_id(&writer, ptgid); si_property_writer_write_parent_process_uid(&writer, pupid); si_property_writer_write_parent_thread_id(&writer, ppid); si_property_writer_write_parent_process_id_version(&writer, parent_task_info ? READ_ONCE(parent_task_info->pid_version) : 0); si_property_writer_write_parent_process_start_timestamp(&writer, parent_start_time); } if (exe_path) si_property_writer_write_exe_file(&writer, &exe_path_info, exe_path, &exe_file_handle_info); else si_property_writer_write_exe_comm(&writer, comm); si_property_writer_write_unix_exec_type(&writer, SI_UNIX_EXEC_TYPE_GENERATED); { SiTimeMicroseconds t; t.microseconds = READ_ONCE(task_info->artificial_start_time_us); si_property_writer_write_artificial_process_start_timestamp(&writer, t); } if (parent_task_info) { SiTimeMicroseconds t; t.microseconds = READ_ONCE(parent_task_info->artificial_start_time_us); si_property_writer_write_parent_artificial_process_start_timestamp(&writer, t); task_info_put(parent_task_info); } si_property_writer_write_current_creds(&writer); si_property_writer_write_current_cgroup(&writer, SI_CONTAINER_NAME_LIMIT); si_event_writer_finalize(&msg->event, &writer); } if (exe_file) fput(exe_file); path_info_free(&exe_path_info); file_handle_info_free(&exe_file_handle_info); return msg; } static msg_sized_t* msg_varsized_init_type(msg_varsized_t *msg, size_t msg_img_size, return_type_t type) { msg_sized_t* smsg = msg_varsized_init(msg, msg_img_size); if (smsg) { MSG_TYPE(smsg) = type; } return smsg; } int open_file_return_msg_new(msg_varsized_t *msg, int fd) { size_t msg_img_size; request_msg_img_t *msg_img; opened_file_img_t *open_file_img; msg_sized_t *smsg; msg_img_size = sizeof(request_msg_img_t) + sizeof(opened_file_img_t); smsg = msg_varsized_init_type(msg, msg_img_size, RT_OPENED_FILE); if (!smsg) { return -ENOMEM; } msg_img = MSG_IMG(smsg); open_file_img = IMG_PAYLOAD(msg_img); open_file_img->fd = fd; return 0; } int version_info_return_msg_new(msg_varsized_t *msg) { size_t msg_img_size; request_msg_img_t *msg_img; version_info_img_t *version_info_img; msg_sized_t *smsg; msg_img_size = sizeof(request_msg_img_t) + sizeof(version_info_img_t); smsg = msg_varsized_init_type(msg, msg_img_size, RT_VERSION_INFO); if (!smsg) { return -ENOMEM; } msg_img = MSG_IMG(smsg); version_info_img = IMG_PAYLOAD(msg_img); version_info_img->max_action = AT_LAST; version_info_img->features = DRIVER_FEATURE_CLOSE_EVENT; if (ftrace_post_event_have(FTRACE_POST_EVENT_FSNOTIFY)) { version_info_img->features |= DRIVER_FEATURE_FSNOTIFY_EVENTS; } if (ftrace_post_event_have(FTRACE_POST_EVENT_EXEC) && ftrace_post_event_have(FTRACE_POST_EVENT_EXIT) && ftrace_post_event_have(FTRACE_POST_EVENT_FORK)) { version_info_img->features |= DRIVER_FEATURE_SLEEPABLE_PROCESS_EVENTS; } if (ftrace_post_event_have(FTRACE_POST_EVENT_AUDIT)) { version_info_img->features |= DRIVER_FEATURE_AUDIT_EVENTS; } if (lsm_registered()) { version_info_img->features |= DRIVER_FEATURE_LSM_GENERIC; #ifdef HAVE_MMAP_FILE version_info_img->features |= DRIVER_FEATURE_LSM_FILE_MMAP; #endif } if (lsm_has_open()) { version_info_img->features |= DRIVER_FEATURE_LSM_FILE_OPEN_COMPLEX_CREATE; } if (lsm_has_security_path()) { version_info_img->features |= DRIVER_FEATURE_LSM_SECURITY_PATH_SIMPLE_PRE; } if (lsm_has_complex_post()) { version_info_img->features |= DRIVER_FEATURE_LSM_SECURITY_PATH_COMPLEX_POST; } else { version_info_img->features |= DRIVER_FEATURE_FS_SYSCALL_HOOKS_COMPLEX_POST; } if (ftrace_post_event_have(FTRACE_POST_EVENT_EXEC)) { version_info_img->features |= DRIVER_FEATURE_COMMAND_LINE_IN_EXEC; } if (has_d_absolute_path_compat()) { version_info_img->features |= DRIVER_FEATURE_ABSOLUTE_PATHS; } if (ftrace_post_event_have(FTRACE_PRE_EVENT_RW_VERIFY_AREA)) { version_info_img->features |= DRIVER_FEATURE_RW_VERIFY_AREA_EVENTS; } if (ftrace_post_event_have(FTRACE_PRE_EVENT_DO_SPLICE_DIRECT)) { version_info_img->features |= DRIVER_FEATURE_COPYFILE_SPLICE; } if (ftrace_post_event_have(FTRACE_PRE_EVENT_CLONE_FILE_RANGE)) { version_info_img->features |= DRIVER_FEATURE_COPYFILE_CLONE; } if (ftrace_post_event_have(FTRACE_PRE_EVENT_COPY_FILE_RANGE)) { version_info_img->features |= DRIVER_FEATURE_COPYFILE_COPY_FILE_RANGE; } return 0; } int data_queue_offsets_return_msg_new(msg_varsized_t *msg, uint32_t size) { size_t msg_img_size; request_msg_img_t *msg_img; data_queue_offsets_t *data_queue_offsets_img; msg_sized_t *smsg; msg_img_size = sizeof(request_msg_img_t) + sizeof(data_queue_offsets_t); smsg = msg_varsized_init_type(msg, msg_img_size, RT_DATA_QUEUE_OFFSETS); if (!smsg) { return -ENOMEM; } msg_img = MSG_IMG(smsg); data_queue_offsets_img = IMG_PAYLOAD(msg_img); data_queue_offsets_img->size = size; data_queue_offsets_img->headOff = offsetof(shared_data_queue_t, head); data_queue_offsets_img->tailOff = offsetof(shared_data_queue_t, tail); data_queue_offsets_img->entriesOff = offsetof(shared_data_queue_t, entries); return 0; } static const uint8_t k_proc_info_fields[] = { FP_SI_PI_PROCESS_ID, FP_SI_PI_PROCESS_UID, FP_SI_PI_PROCESS_ID_VERSION, FP_SI_PI_ARTIFICIAL_PROCESS_START_TIMESTAMP, FP_SI_PI_PARENT_PROCESS_ID, FP_SI_PI_PARENT_PROCESS_UID, FP_SI_PI_PARENT_PROCESS_ID_VERSION, FP_SI_PI_PARENT_ARTIFICIAL_PROCESS_START_TIMESTAMP, FP_SI_PI_PARENT_PROCESS_START_TIMESTAMP, FP_SI_PI_PROCESS_START_TIMESTAMP, // TODO: Size may vary if there is or there is no inode. Use other template when exe_path is NULL SI_COMMON_EXE_FILE_FIELDS, SI_COMMON_CRED_FIELDS, }; int process_info_return_msg_new(msg_varsized_t *msg, pid_t nr) { uint32_t event_size; struct pid *pid; struct task_struct *task; struct path *exe_path = NULL; struct file *exe_file; size_t msg_img_size; msg_sized_t *smsg; int ret; bool has_parent = false; pid_t ptgid = 0; uint64_t pupid = 0; SiTimeMicroseconds parent_start_time = {0}; path_info_t exe_path_info = (path_info_t){0}; file_handle_info_t exe_file_handle_info = (file_handle_info_t){0}; char comm[TASK_COMM_LEN]; task_info_t *task_info = NULL; pid = find_get_pid(nr); task = get_pid_task(pid, PIDTYPE_PID); put_pid(pid); if (!task) { ret = -ENOENT; goto out; } exe_file = get_task_exe_file_compat(task); // Note: kernel's threads do not have 'exe_file' if (exe_file) { exe_path = &exe_file->f_path; if (!path_is_usable(exe_path)) { exe_path = NULL; } } task_info = task_info_map_get_with_exe(task, exe_path); if (exe_path) { file_handle_info_make(&exe_file_handle_info, exe_path); path_info_make(&exe_path_info, exe_path, false /*dir*/); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_proc_info_fields) + SI_ESTIMATE_SIZE_PATH_INFO(exe_path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(exe_file_handle_info); } else { get_task_comm(comm, task); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_proc_info_fields) + TASK_COMM_LEN; } event_size += SI_CONTAINER_NAME_LIMIT; { struct task_struct* parent; rcu_read_lock(); parent = rcu_dereference(task->real_parent); ptgid = parent ? parent->tgid : 0; has_parent = 0 != ptgid; if (has_parent) { pupid = make_unique_pid(parent); parent_start_time = make_process_start_time(parent); } rcu_read_unlock(); } msg_img_size = sizeof(request_msg_img_t) + sizeof(SiInfo) + event_size; smsg = msg_varsized_init_type(msg, msg_img_size, RT_GET_PROCESS_INFO); if (smsg) { request_msg_img_t *msg_img = MSG_IMG(smsg); SiInfo *info = IMG_PAYLOAD(msg_img); { si_property_writer_t writer; task_info_t *parent_task_info = has_parent ? task_info_map_add(ptgid, pupid, NULL /*no exe update*/, parent_start_time.microseconds) : NULL; si_info_writer_init(&writer, info, event_size); si_property_writer_write_process_id(&writer, task->tgid); si_property_writer_write_process_uid(&writer, make_unique_pid(task)); si_property_writer_write_process_id_version(&writer, task_info ? READ_ONCE(task_info->pid_version) : 0); if (task_info) { SiTimeMicroseconds t; t.microseconds = READ_ONCE(task_info->artificial_start_time_us); si_property_writer_write_artificial_process_start_timestamp(&writer, t); } si_property_writer_write_process_start_timestamp(&writer, make_process_start_time(task)); if (has_parent) { si_property_writer_write_parent_process_id(&writer, ptgid); si_property_writer_write_parent_process_uid(&writer, pupid); si_property_writer_write_parent_process_id_version(&writer, parent_task_info ? READ_ONCE(parent_task_info->pid_version) : 0); si_property_writer_write_parent_process_start_timestamp(&writer, parent_start_time); } if (exe_path) si_property_writer_write_exe_file(&writer, &exe_path_info, exe_path, &exe_file_handle_info); else si_property_writer_write_exe_comm(&writer, comm); if (parent_task_info) { SiTimeMicroseconds t; t.microseconds = READ_ONCE(parent_task_info->artificial_start_time_us); si_property_writer_write_parent_artificial_process_start_timestamp(&writer, t); task_info_put(parent_task_info); } si_property_writer_write_task_creds(&writer, task); si_property_writer_write_cgroup(&writer, task, SI_CONTAINER_NAME_LIMIT); si_info_writer_finalize(info, &writer); } ret = 0; } else { ret = -ENOMEM; } if (exe_file) fput(exe_file); if (task_info) task_info_put(task_info); path_info_free(&exe_path_info); file_handle_info_free(&exe_file_handle_info); out: return ret; } int process_pid_version_return_msg_new(msg_varsized_t *msg, pid_t nr) { struct pid *pid; struct task_struct *task; struct path *exe_path = NULL; struct file *exe_file = NULL; int ret; task_info_t *task_info = NULL; size_t msg_img_size; msg_sized_t *smsg; pid = find_get_pid(nr); task = get_pid_task(pid, PIDTYPE_PID); put_pid(pid); if (!task) { ret = -ENOENT; goto out; } exe_file = get_task_exe_file_compat(task); // Note: kernel's threads do not have 'exe_file' if (exe_file) { exe_path = &exe_file->f_path; if (!path_is_usable(exe_path)) { exe_path = NULL; } } task_info = task_info_map_get_with_exe(task, exe_path); if (!task_info) { ret = -ENOMEM; goto out; } msg_img_size = sizeof(request_msg_img_t) + sizeof(process_pid_version_ret_img_t); smsg = msg_varsized_init_type(msg, msg_img_size, RT_GET_PROCESS_PID_VERSION); if (smsg) { request_msg_img_t *msg_img = MSG_IMG(smsg); process_pid_version_ret_img_t *pid_info_img = IMG_PAYLOAD(msg_img); pid_info_img->pid_version = READ_ONCE(task_info->pid_version); pid_info_img->artificial_process_start_timestamp = READ_ONCE(task_info->artificial_start_time_us); ret = 0; } else { ret = -ENOMEM; } out: if (exe_file) fput(exe_file); if (task_info) task_info_put(task_info); return ret; }