diff options
Diffstat (limited to 'drivers/connector')
| -rw-r--r-- | drivers/connector/cn_proc.c | 92 | ||||
| -rw-r--r-- | drivers/connector/connector.c | 36 | 
2 files changed, 79 insertions, 49 deletions
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index c73fc2b74de..ccdd4c7e748 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -32,11 +32,23 @@  #include <linux/atomic.h>  #include <linux/pid_namespace.h> -#include <asm/unaligned.h> -  #include <linux/cn_proc.h> -#define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event)) +/* + * Size of a cn_msg followed by a proc_event structure.  Since the + * sizeof struct cn_msg is a multiple of 4 bytes, but not 8 bytes, we + * add one 4-byte word to the size here, and then start the actual + * cn_msg structure 4 bytes into the stack buffer.  The result is that + * the immediately following proc_event structure is aligned to 8 bytes. + */ +#define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event) + 4) + +/* See comment above; we test our assumption about sizeof struct cn_msg here. */ +static inline struct cn_msg *buffer_to_cn_msg(__u8 *buffer) +{ +	BUILD_BUG_ON(sizeof(struct cn_msg) != 20); +	return (struct cn_msg *)(buffer + 4); +}  static atomic_t proc_event_num_listeners = ATOMIC_INIT(0);  static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC }; @@ -56,19 +68,19 @@ void proc_fork_connector(struct task_struct *task)  {  	struct cn_msg *msg;  	struct proc_event *ev; -	__u8 buffer[CN_PROC_MSG_SIZE]; +	__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);  	struct timespec ts;  	struct task_struct *parent;  	if (atomic_read(&proc_event_num_listeners) < 1)  		return; -	msg = (struct cn_msg *)buffer; +	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 */ -	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); +	ev->timestamp_ns = timespec_to_ns(&ts);  	ev->what = PROC_EVENT_FORK;  	rcu_read_lock();  	parent = rcu_dereference(task->real_parent); @@ -83,7 +95,7 @@ void proc_fork_connector(struct task_struct *task)  	msg->len = sizeof(*ev);  	msg->flags = 0; /* not used */  	/*  If cn_netlink_send() failed, the data is not sent */ -	cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +	cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);  }  void proc_exec_connector(struct task_struct *task) @@ -91,17 +103,17 @@ 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]; +	__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);  	if (atomic_read(&proc_event_num_listeners) < 1)  		return; -	msg = (struct cn_msg *)buffer; +	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 */ -	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); +	ev->timestamp_ns = timespec_to_ns(&ts);  	ev->what = PROC_EVENT_EXEC;  	ev->event_data.exec.process_pid = task->pid;  	ev->event_data.exec.process_tgid = task->tgid; @@ -110,21 +122,21 @@ void proc_exec_connector(struct task_struct *task)  	msg->ack = 0; /* not used */  	msg->len = sizeof(*ev);  	msg->flags = 0; /* not used */ -	cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +	cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);  }  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]; +	__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 = (struct cn_msg *)buffer; +	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; @@ -145,13 +157,13 @@ void proc_id_connector(struct task_struct *task, int which_id)  	rcu_read_unlock();  	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->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); +	cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);  }  void proc_sid_connector(struct task_struct *task) @@ -159,17 +171,17 @@ void proc_sid_connector(struct task_struct *task)  	struct cn_msg *msg;  	struct proc_event *ev;  	struct timespec ts; -	__u8 buffer[CN_PROC_MSG_SIZE]; +	__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);  	if (atomic_read(&proc_event_num_listeners) < 1)  		return; -	msg = (struct cn_msg *)buffer; +	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 */ -	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); +	ev->timestamp_ns = timespec_to_ns(&ts);  	ev->what = PROC_EVENT_SID;  	ev->event_data.sid.process_pid = task->pid;  	ev->event_data.sid.process_tgid = task->tgid; @@ -178,7 +190,7 @@ void proc_sid_connector(struct task_struct *task)  	msg->ack = 0; /* not used */  	msg->len = sizeof(*ev);  	msg->flags = 0; /* not used */ -	cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +	cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);  }  void proc_ptrace_connector(struct task_struct *task, int ptrace_id) @@ -186,17 +198,17 @@ 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]; +	__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);  	if (atomic_read(&proc_event_num_listeners) < 1)  		return; -	msg = (struct cn_msg *)buffer; +	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 */ -	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); +	ev->timestamp_ns = timespec_to_ns(&ts);  	ev->what = PROC_EVENT_PTRACE;  	ev->event_data.ptrace.process_pid  = task->pid;  	ev->event_data.ptrace.process_tgid = task->tgid; @@ -213,7 +225,7 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)  	msg->ack = 0; /* not used */  	msg->len = sizeof(*ev);  	msg->flags = 0; /* not used */ -	cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +	cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);  }  void proc_comm_connector(struct task_struct *task) @@ -221,17 +233,17 @@ void proc_comm_connector(struct task_struct *task)  	struct cn_msg *msg;  	struct proc_event *ev;  	struct timespec ts; -	__u8 buffer[CN_PROC_MSG_SIZE]; +	__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);  	if (atomic_read(&proc_event_num_listeners) < 1)  		return; -	msg = (struct cn_msg *)buffer; +	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 */ -	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); +	ev->timestamp_ns = timespec_to_ns(&ts);  	ev->what = PROC_EVENT_COMM;  	ev->event_data.comm.process_pid  = task->pid;  	ev->event_data.comm.process_tgid = task->tgid; @@ -241,25 +253,25 @@ void proc_comm_connector(struct task_struct *task)  	msg->ack = 0; /* not used */  	msg->len = sizeof(*ev);  	msg->flags = 0; /* not used */ -	cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +	cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);  }  void proc_coredump_connector(struct task_struct *task)  {  	struct cn_msg *msg;  	struct proc_event *ev; -	__u8 buffer[CN_PROC_MSG_SIZE]; +	__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);  	struct timespec ts;  	if (atomic_read(&proc_event_num_listeners) < 1)  		return; -	msg = (struct cn_msg *)buffer; +	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 */ -	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); +	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; @@ -268,25 +280,25 @@ void proc_coredump_connector(struct task_struct *task)  	msg->ack = 0; /* not used */  	msg->len = sizeof(*ev);  	msg->flags = 0; /* not used */ -	cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +	cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);  }  void proc_exit_connector(struct task_struct *task)  {  	struct cn_msg *msg;  	struct proc_event *ev; -	__u8 buffer[CN_PROC_MSG_SIZE]; +	__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);  	struct timespec ts;  	if (atomic_read(&proc_event_num_listeners) < 1)  		return; -	msg = (struct cn_msg *)buffer; +	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 */ -	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); +	ev->timestamp_ns = timespec_to_ns(&ts);  	ev->what = PROC_EVENT_EXIT;  	ev->event_data.exit.process_pid = task->pid;  	ev->event_data.exit.process_tgid = task->tgid; @@ -297,7 +309,7 @@ void proc_exit_connector(struct task_struct *task)  	msg->ack = 0; /* not used */  	msg->len = sizeof(*ev);  	msg->flags = 0; /* not used */ -	cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +	cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);  }  /* @@ -312,18 +324,18 @@ 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]; +	__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);  	struct timespec ts;  	if (atomic_read(&proc_event_num_listeners) < 1)  		return; -	msg = (struct cn_msg *)buffer; +	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 */ -	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); +	ev->timestamp_ns = timespec_to_ns(&ts);  	ev->cpu = -1;  	ev->what = PROC_EVENT_NONE;  	ev->event_data.ack.err = err; @@ -331,7 +343,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)  	msg->ack = rcvd_ack + 1;  	msg->len = sizeof(*ev);  	msg->flags = 0; /* not used */ -	cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +	cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);  }  /** @@ -357,7 +369,7 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,  		return;  	/* Can only change if privileged. */ -	if (!capable(CAP_NET_ADMIN)) { +	if (!__netlink_ns_capable(nsp, &init_user_ns, CAP_NET_ADMIN)) {  		err = EPERM;  		goto out;  	} diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index a36749f1e44..f612d68629d 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -43,6 +43,8 @@ static struct cn_dev cdev;  static int cn_already_initialized;  /* + * Sends mult (multiple) cn_msg at a time. + *   * msg->seq and msg->ack are used to determine message genealogy.   * When someone sends message it puts there locally unique sequence   * and random acknowledge numbers.  Sequence number may be copied into @@ -50,7 +52,7 @@ static int cn_already_initialized;   *   * Sequence number is incremented with each message to be sent.   * - * If we expect reply to our message then the sequence number in + * If we expect a reply to our message then the sequence number in   * received message MUST be the same as in original message, and   * acknowledge number MUST be the same + 1.   * @@ -62,8 +64,14 @@ static int cn_already_initialized;   * the acknowledgement number in the original message + 1, then it is   * a new message.   * + * If msg->len != len, then additional cn_msg messages are expected following + * the first msg. + * + * The message is sent to, the portid if given, the group if given, both if + * both, or if both are zero then the group is looked up and sent there.   */ -int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask) +int cn_netlink_send_mult(struct cn_msg *msg, u16 len, u32 portid, u32 __group, +	gfp_t gfp_mask)  {  	struct cn_callback_entry *__cbq;  	unsigned int size; @@ -74,7 +82,9 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)  	u32 group = 0;  	int found = 0; -	if (!__group) { +	if (portid || __group) { +		group = __group; +	} else {  		spin_lock_bh(&dev->cbdev->queue_lock);  		list_for_each_entry(__cbq, &dev->cbdev->queue_list,  				    callback_entry) { @@ -88,14 +98,12 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)  		if (!found)  			return -ENODEV; -	} else { -		group = __group;  	} -	if (!netlink_has_listeners(dev->nls, group)) +	if (!portid && !netlink_has_listeners(dev->nls, group))  		return -ESRCH; -	size = sizeof(*msg) + msg->len; +	size = sizeof(*msg) + len;  	skb = nlmsg_new(size, gfp_mask);  	if (!skb) @@ -113,7 +121,18 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)  	NETLINK_CB(skb).dst_group = group; -	return netlink_broadcast(dev->nls, skb, 0, group, gfp_mask); +	if (group) +		return netlink_broadcast(dev->nls, skb, portid, group, +					 gfp_mask); +	return netlink_unicast(dev->nls, skb, portid, !(gfp_mask&__GFP_WAIT)); +} +EXPORT_SYMBOL_GPL(cn_netlink_send_mult); + +/* same as cn_netlink_send_mult except msg->len is used for len */ +int cn_netlink_send(struct cn_msg *msg, u32 portid, u32 __group, +	gfp_t gfp_mask) +{ +	return cn_netlink_send_mult(msg, msg->len, portid, __group, gfp_mask);  }  EXPORT_SYMBOL_GPL(cn_netlink_send); @@ -139,7 +158,6 @@ static int cn_call_callback(struct sk_buff *skb)  	spin_unlock_bh(&dev->cbdev->queue_lock);  	if (cbq != NULL) { -		err = 0;  		cbq->callback(msg, nsp);  		kfree_skb(skb);  		cn_queue_release_callback(cbq);  | 
