void proc_coredump_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; msg = buffer_to_cn_msg(buffer); ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = timespec_to_ns(&ts); ev->what = PROC_EVENT_COREDUMP; ev->event_data.coredump.process_pid = task->pid; ev->event_data.coredump.process_tgid = task->tgid; memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ msg->len = sizeof(*ev); msg->flags = 0; /* not used */ cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); }
void proc_ptrace_connector(struct task_struct *task, int ptrace_id) { struct cn_msg *msg; struct proc_event *ev; struct timespec ts; __u8 buffer[CN_PROC_MSG_SIZE]; if (atomic_read(&proc_event_num_listeners) < 1) return; msg = (struct cn_msg *)buffer; ev = (struct proc_event *)msg->data; get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ev->what = PROC_EVENT_PTRACE; ev->event_data.ptrace.process_pid = task->pid; ev->event_data.ptrace.process_tgid = task->tgid; if (ptrace_id == PTRACE_ATTACH) { ev->event_data.ptrace.tracer_pid = current->pid; ev->event_data.ptrace.tracer_tgid = current->tgid; } else if (ptrace_id == PTRACE_DETACH) { ev->event_data.ptrace.tracer_pid = 0; ev->event_data.ptrace.tracer_tgid = 0; } else return; memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ msg->len = sizeof(*ev); cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); }
static void cn_test_timer_func(unsigned long __data) { struct cn_msg *m; char data[32]; pr_debug("%s: timer fired with data %lu\n", __func__, __data); m = kzalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC); if (m) { memcpy(&m->id, &cn_test_id, sizeof(m->id)); m->seq = cn_test_timer_counter; m->len = sizeof(data); m->len = scnprintf(data, sizeof(data), "counter = %u", cn_test_timer_counter) + 1; memcpy(m + 1, data, m->len); cn_netlink_send(m, 0, GFP_ATOMIC); kfree(m); } cn_test_timer_counter++; mod_timer(&cn_test_timer, jiffies + msecs_to_jiffies(1000)); }
void proc_exit_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ev->what = PROC_EVENT_EXIT; ev->event_data.exit.process_pid = task->pid; ev->event_data.exit.process_tgid = task->tgid; ev->event_data.exit.exit_code = task->exit_code; ev->event_data.exit.exit_signal = task->exit_signal; memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ msg->len = sizeof(*ev); cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); }
void proc_exec_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; struct timespec ts; __u8 buffer[CN_PROC_MSG_SIZE]; const struct cred *cred; if (atomic_read(&proc_event_num_listeners) < 1) return; msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ev->what = PROC_EVENT_EXEC; ev->event_data.exec.process_pid = task->pid; ev->event_data.exec.process_tgid = task->tgid; rcu_read_lock(); cred = __task_cred(task); ev->event_data.exec.process_euid = cred->euid; ev->event_data.exec.process_egid = cred->egid; rcu_read_unlock(); proc_get_exe(task, ev->event_data.exec.exe); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ msg->len = sizeof(*ev); cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); }
void proc_fork_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; struct timespec ts; struct task_struct *parent; if (atomic_read(&proc_event_num_listeners) < 1) return; msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ev->what = PROC_EVENT_FORK; rcu_read_lock(); parent = rcu_dereference(task->real_parent); ev->event_data.fork.parent_pid = parent->pid; ev->event_data.fork.parent_tgid = parent->tgid; rcu_read_unlock(); ev->event_data.fork.child_pid = task->pid; ev->event_data.fork.child_tgid = task->tgid; memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ msg->len = sizeof(*ev); /* If cn_netlink_send() failed, the data is not sent */ cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); }
static void cn_test_timer_func(unsigned long __data) { struct cn_msg *m; char data[32]; m = kzalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC); if (m) { memcpy(&m->id, &cn_test_id, sizeof(m->id)); m->seq = cn_test_timer_counter; m->len = sizeof(data); m->len = scnprintf(data, sizeof(data), "counter = %u", cn_test_timer_counter) + 1; memcpy(m + 1, data, m->len); cn_netlink_send(m, 0, gfp_any()); kfree(m); } cn_test_timer_counter++; mod_timer(&cn_test_timer, jiffies + HZ); }
static void vss_send_op(struct work_struct *dummy) { int op = vss_transaction.msg->vss_hdr.operation; int rc; struct cn_msg *msg; struct hv_vss_msg *vss_msg; msg = kzalloc(sizeof(*msg) + sizeof(*vss_msg), GFP_ATOMIC); if (!msg) return; vss_msg = (struct hv_vss_msg *)msg->data; msg->id.idx = CN_VSS_IDX; msg->id.val = CN_VSS_VAL; vss_msg->vss_hdr.operation = op; msg->len = sizeof(struct hv_vss_msg); rc = cn_netlink_send(msg, 0, 0, GFP_ATOMIC); if (rc) { pr_warn("VSS: failed to communicate to the daemon: %d\n", rc); if (cancel_delayed_work_sync(&vss_timeout_work)) vss_respond_to_host(HV_E_FAIL); } kfree(msg); return; }
/* * Send an acknowledgement message to userspace * * Use 0 for success, EFOO otherwise. * Note: this is the negative of conventional kernel error * values because it's not being returned via syscall return * mechanisms. */ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) { struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; msg = buffer_to_cn_msg(buffer); ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); msg->seq = rcvd_seq; ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = timespec_to_ns(&ts); ev->cpu = -1; ev->what = PROC_EVENT_NONE; ev->event_data.ack.err = err; memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = rcvd_ack + 1; msg->len = sizeof(*ev); msg->flags = 0; /* not used */ cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); }
static inline void send_msg(struct cn_msg *msg) { preempt_disable(); msg->seq = __this_cpu_inc_return(proc_event_counts) - 1; ((struct proc_event *)msg->data)->cpu = smp_processor_id(); /* * Preemption remains disabled during send to ensure the messages are * ordered according to their sequence numbers. * * If cn_netlink_send() fails, the data is not sent. */ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_NOWAIT); preempt_enable(); }
static void kvp_register(void) { struct cn_msg *msg; msg = kzalloc(sizeof(*msg) + strlen(HV_DRV_VERSION) + 1 , GFP_ATOMIC); if (msg) { msg->id.idx = CN_KVP_IDX; msg->id.val = CN_KVP_VAL; msg->seq = KVP_REGISTER; strcpy(msg->data, HV_DRV_VERSION); msg->len = strlen(HV_DRV_VERSION) + 1; cn_netlink_send(msg, 0, GFP_ATOMIC); kfree(msg); } }
static int kvp_send_key(int index) { struct cn_msg *msg; msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC); if (msg) { msg->id.idx = CN_KVP_IDX; msg->id.val = CN_KVP_VAL; msg->seq = KVP_KERNEL_GET; ((struct hv_ku_msg *)msg->data)->kvp_index = index; msg->len = sizeof(struct hv_ku_msg); cn_netlink_send(msg, 0, GFP_ATOMIC); kfree(msg); return 0; } return 1; }
static void kvp_send_key(struct work_struct *dummy) { struct cn_msg *msg; int index = kvp_transaction.index; msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC); if (msg) { msg->id.idx = CN_KVP_IDX; msg->id.val = CN_KVP_VAL; msg->seq = KVP_KERNEL_GET; ((struct hv_ku_msg *)msg->data)->kvp_index = index; msg->len = sizeof(struct hv_ku_msg); cn_netlink_send(msg, 0, GFP_ATOMIC); kfree(msg); } return; }
void proc_id_connector(struct task_struct *task, int which_id) { struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); struct timespec ts; const struct cred *cred; if (atomic_read(&proc_event_num_listeners) < 1) return; msg = buffer_to_cn_msg(buffer); ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); ev->what = which_id; ev->event_data.id.process_pid = task->pid; ev->event_data.id.process_tgid = task->tgid; rcu_read_lock(); cred = __task_cred(task); if (which_id == PROC_EVENT_UID) { ev->event_data.id.r.ruid = from_kuid_munged(&init_user_ns, cred->uid); ev->event_data.id.e.euid = from_kuid_munged(&init_user_ns, cred->euid); } else if (which_id == PROC_EVENT_GID) { ev->event_data.id.r.rgid = from_kgid_munged(&init_user_ns, cred->gid); ev->event_data.id.e.egid = from_kgid_munged(&init_user_ns, cred->egid); } else { rcu_read_unlock(); return; } rcu_read_unlock(); get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = timespec_to_ns(&ts); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ msg->len = sizeof(*ev); msg->flags = 0; /* not used */ cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); }
static void vss_send_op(struct work_struct *dummy) { int op = vss_transaction.msg->vss_hdr.operation; struct cn_msg *msg; struct hv_vss_msg *vss_msg; msg = kzalloc(sizeof(*msg) + sizeof(*vss_msg), GFP_ATOMIC); if (!msg) return; vss_msg = (struct hv_vss_msg *)msg->data; msg->id.idx = CN_VSS_IDX; msg->id.val = CN_VSS_VAL; vss_msg->vss_hdr.operation = op; msg->len = sizeof(struct hv_vss_msg); cn_netlink_send(msg, 0, 0, GFP_ATOMIC); kfree(msg); return; }
static void kvp_register(int reg_value) { struct cn_msg *msg; struct hv_kvp_msg *kvp_msg; char *version; msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg), GFP_ATOMIC); if (msg) { kvp_msg = (struct hv_kvp_msg *)msg->data; version = kvp_msg->body.kvp_register.version; msg->id.idx = CN_KVP_IDX; msg->id.val = CN_KVP_VAL; kvp_msg->kvp_hdr.operation = reg_value; strcpy(version, HV_DRV_VERSION); msg->len = sizeof(struct hv_kvp_msg); cn_netlink_send(msg, 0, GFP_ATOMIC); kfree(msg); } }
static void kvp_send_key(struct work_struct *dummy) { struct cn_msg *msg; struct hv_kvp_msg *message; struct hv_kvp_msg *in_msg; __u8 operation = kvp_transaction.kvp_msg->kvp_hdr.operation; __u8 pool = kvp_transaction.kvp_msg->kvp_hdr.pool; __u32 val32; __u64 val64; msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC); if (!msg) return; msg->id.idx = CN_KVP_IDX; msg->id.val = CN_KVP_VAL; message = (struct hv_kvp_msg *)msg->data; message->kvp_hdr.operation = operation; message->kvp_hdr.pool = pool; in_msg = kvp_transaction.kvp_msg; /* * The key/value strings sent from the host are encoded in * in utf16; convert it to utf8 strings. * The host assures us that the utf16 strings will not exceed * the max lengths specified. We will however, reserve room * for the string terminating character - in the utf16s_utf8s() * function we limit the size of the buffer where the converted * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to gaurantee * that the strings can be properly terminated! */ switch (message->kvp_hdr.operation) { case KVP_OP_SET_IP_INFO: process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO); break; case KVP_OP_GET_IP_INFO: process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO); break; case KVP_OP_SET: switch (in_msg->body.kvp_set.data.value_type) { case REG_SZ: /* * The value is a string - utf16 encoding. */ message->body.kvp_set.data.value_size = utf16s_to_utf8s( (wchar_t *)in_msg->body.kvp_set.data.value, in_msg->body.kvp_set.data.value_size, UTF16_LITTLE_ENDIAN, message->body.kvp_set.data.value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1) + 1; break; case REG_U32: /* * The value is a 32 bit scalar. * We save this as a utf8 string. */ val32 = in_msg->body.kvp_set.data.value_u32; message->body.kvp_set.data.value_size = sprintf(message->body.kvp_set.data.value, "%d", val32) + 1; break; case REG_U64: /* * The value is a 64 bit scalar. * We save this as a utf8 string. */ val64 = in_msg->body.kvp_set.data.value_u64; message->body.kvp_set.data.value_size = sprintf(message->body.kvp_set.data.value, "%llu", val64) + 1; break; } case KVP_OP_GET: message->body.kvp_set.data.key_size = utf16s_to_utf8s( (wchar_t *)in_msg->body.kvp_set.data.key, in_msg->body.kvp_set.data.key_size, UTF16_LITTLE_ENDIAN, message->body.kvp_set.data.key, HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1; break; case KVP_OP_DELETE: message->body.kvp_delete.key_size = utf16s_to_utf8s( (wchar_t *)in_msg->body.kvp_delete.key, in_msg->body.kvp_delete.key_size, UTF16_LITTLE_ENDIAN, message->body.kvp_delete.key, HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1; break; case KVP_OP_ENUMERATE: message->body.kvp_enum_data.index = in_msg->body.kvp_enum_data.index; break; } msg->len = sizeof(struct hv_kvp_msg); cn_netlink_send(msg, 0, GFP_ATOMIC); kfree(msg); return; }