Skip to content

Commit ab8ed95

Browse files
aarcampdavem330
authored andcommitted
connector: fix out-of-order cn_proc netlink message delivery
The proc connector messages include a sequence number, allowing userspace programs to detect lost messages. However, performing this detection is currently more difficult than necessary, since netlink messages can be delivered to the application out-of-order. To fix this, leave pre-emption disabled during cn_netlink_send(), and use GFP_NOWAIT. The following was written as a test case. Building the kernel w/ make -j32 proved a reliable way to generate out-of-order cn_proc messages. int main(int argc, char *argv[]) { static uint32_t last_seq[CPU_SETSIZE], seq; int cpu, fd; struct sockaddr_nl sa; struct __attribute__((aligned(NLMSG_ALIGNTO))) { struct nlmsghdr nl_hdr; struct __attribute__((__packed__)) { struct cn_msg cn_msg; struct proc_event cn_proc; }; } rmsg; struct __attribute__((aligned(NLMSG_ALIGNTO))) { struct nlmsghdr nl_hdr; struct __attribute__((__packed__)) { struct cn_msg cn_msg; enum proc_cn_mcast_op cn_mcast; }; } smsg; fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); if (fd < 0) { perror("socket"); } sa.nl_family = AF_NETLINK; sa.nl_groups = CN_IDX_PROC; sa.nl_pid = getpid(); if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { perror("bind"); } memset(&smsg, 0, sizeof(smsg)); smsg.nl_hdr.nlmsg_len = sizeof(smsg); smsg.nl_hdr.nlmsg_pid = getpid(); smsg.nl_hdr.nlmsg_type = NLMSG_DONE; smsg.cn_msg.id.idx = CN_IDX_PROC; smsg.cn_msg.id.val = CN_VAL_PROC; smsg.cn_msg.len = sizeof(enum proc_cn_mcast_op); smsg.cn_mcast = PROC_CN_MCAST_LISTEN; if (send(fd, &smsg, sizeof(smsg), 0) != sizeof(smsg)) { perror("send"); } while (recv(fd, &rmsg, sizeof(rmsg), 0) == sizeof(rmsg)) { cpu = rmsg.cn_proc.cpu; if (cpu < 0) { continue; } seq = rmsg.cn_msg.seq; if ((last_seq[cpu] != 0) && (seq != last_seq[cpu] + 1)) { printf("out-of-order seq=%d on cpu=%d\n", seq, cpu); } last_seq[cpu] = seq; } /* NOTREACHED */ perror("recv"); return -1; } Signed-off-by: Aaron Campbell <aaron@monkey.org> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 0888d5f commit ab8ed95

File tree

1 file changed

+22
-21
lines changed

1 file changed

+22
-21
lines changed

drivers/connector/cn_proc.c

+22-21
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,21 @@ static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC };
5656
/* proc_event_counts is used as the sequence number of the netlink message */
5757
static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 };
5858

59-
static inline void get_seq(__u32 *ts, int *cpu)
59+
static inline void send_msg(struct cn_msg *msg)
6060
{
6161
preempt_disable();
62-
*ts = __this_cpu_inc_return(proc_event_counts) - 1;
63-
*cpu = smp_processor_id();
62+
63+
msg->seq = __this_cpu_inc_return(proc_event_counts) - 1;
64+
((struct proc_event *)msg->data)->cpu = smp_processor_id();
65+
66+
/*
67+
* Preemption remains disabled during send to ensure the messages are
68+
* ordered according to their sequence numbers.
69+
*
70+
* If cn_netlink_send() fails, the data is not sent.
71+
*/
72+
cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_NOWAIT);
73+
6474
preempt_enable();
6575
}
6676

@@ -77,7 +87,6 @@ void proc_fork_connector(struct task_struct *task)
7787
msg = buffer_to_cn_msg(buffer);
7888
ev = (struct proc_event *)msg->data;
7989
memset(&ev->event_data, 0, sizeof(ev->event_data));
80-
get_seq(&msg->seq, &ev->cpu);
8190
ev->timestamp_ns = ktime_get_ns();
8291
ev->what = PROC_EVENT_FORK;
8392
rcu_read_lock();
@@ -92,8 +101,7 @@ void proc_fork_connector(struct task_struct *task)
92101
msg->ack = 0; /* not used */
93102
msg->len = sizeof(*ev);
94103
msg->flags = 0; /* not used */
95-
/* If cn_netlink_send() failed, the data is not sent */
96-
cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
104+
send_msg(msg);
97105
}
98106

99107
void proc_exec_connector(struct task_struct *task)
@@ -108,7 +116,6 @@ void proc_exec_connector(struct task_struct *task)
108116
msg = buffer_to_cn_msg(buffer);
109117
ev = (struct proc_event *)msg->data;
110118
memset(&ev->event_data, 0, sizeof(ev->event_data));
111-
get_seq(&msg->seq, &ev->cpu);
112119
ev->timestamp_ns = ktime_get_ns();
113120
ev->what = PROC_EVENT_EXEC;
114121
ev->event_data.exec.process_pid = task->pid;
@@ -118,7 +125,7 @@ void proc_exec_connector(struct task_struct *task)
118125
msg->ack = 0; /* not used */
119126
msg->len = sizeof(*ev);
120127
msg->flags = 0; /* not used */
121-
cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
128+
send_msg(msg);
122129
}
123130

124131
void proc_id_connector(struct task_struct *task, int which_id)
@@ -150,14 +157,13 @@ void proc_id_connector(struct task_struct *task, int which_id)
150157
return;
151158
}
152159
rcu_read_unlock();
153-
get_seq(&msg->seq, &ev->cpu);
154160
ev->timestamp_ns = ktime_get_ns();
155161

156162
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
157163
msg->ack = 0; /* not used */
158164
msg->len = sizeof(*ev);
159165
msg->flags = 0; /* not used */
160-
cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
166+
send_msg(msg);
161167
}
162168

163169
void proc_sid_connector(struct task_struct *task)
@@ -172,7 +178,6 @@ void proc_sid_connector(struct task_struct *task)
172178
msg = buffer_to_cn_msg(buffer);
173179
ev = (struct proc_event *)msg->data;
174180
memset(&ev->event_data, 0, sizeof(ev->event_data));
175-
get_seq(&msg->seq, &ev->cpu);
176181
ev->timestamp_ns = ktime_get_ns();
177182
ev->what = PROC_EVENT_SID;
178183
ev->event_data.sid.process_pid = task->pid;
@@ -182,7 +187,7 @@ void proc_sid_connector(struct task_struct *task)
182187
msg->ack = 0; /* not used */
183188
msg->len = sizeof(*ev);
184189
msg->flags = 0; /* not used */
185-
cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
190+
send_msg(msg);
186191
}
187192

188193
void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
@@ -197,7 +202,6 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
197202
msg = buffer_to_cn_msg(buffer);
198203
ev = (struct proc_event *)msg->data;
199204
memset(&ev->event_data, 0, sizeof(ev->event_data));
200-
get_seq(&msg->seq, &ev->cpu);
201205
ev->timestamp_ns = ktime_get_ns();
202206
ev->what = PROC_EVENT_PTRACE;
203207
ev->event_data.ptrace.process_pid = task->pid;
@@ -215,7 +219,7 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
215219
msg->ack = 0; /* not used */
216220
msg->len = sizeof(*ev);
217221
msg->flags = 0; /* not used */
218-
cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
222+
send_msg(msg);
219223
}
220224

221225
void proc_comm_connector(struct task_struct *task)
@@ -230,7 +234,6 @@ void proc_comm_connector(struct task_struct *task)
230234
msg = buffer_to_cn_msg(buffer);
231235
ev = (struct proc_event *)msg->data;
232236
memset(&ev->event_data, 0, sizeof(ev->event_data));
233-
get_seq(&msg->seq, &ev->cpu);
234237
ev->timestamp_ns = ktime_get_ns();
235238
ev->what = PROC_EVENT_COMM;
236239
ev->event_data.comm.process_pid = task->pid;
@@ -241,7 +244,7 @@ void proc_comm_connector(struct task_struct *task)
241244
msg->ack = 0; /* not used */
242245
msg->len = sizeof(*ev);
243246
msg->flags = 0; /* not used */
244-
cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
247+
send_msg(msg);
245248
}
246249

247250
void proc_coredump_connector(struct task_struct *task)
@@ -256,7 +259,6 @@ void proc_coredump_connector(struct task_struct *task)
256259
msg = buffer_to_cn_msg(buffer);
257260
ev = (struct proc_event *)msg->data;
258261
memset(&ev->event_data, 0, sizeof(ev->event_data));
259-
get_seq(&msg->seq, &ev->cpu);
260262
ev->timestamp_ns = ktime_get_ns();
261263
ev->what = PROC_EVENT_COREDUMP;
262264
ev->event_data.coredump.process_pid = task->pid;
@@ -266,7 +268,7 @@ void proc_coredump_connector(struct task_struct *task)
266268
msg->ack = 0; /* not used */
267269
msg->len = sizeof(*ev);
268270
msg->flags = 0; /* not used */
269-
cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
271+
send_msg(msg);
270272
}
271273

272274
void proc_exit_connector(struct task_struct *task)
@@ -281,7 +283,6 @@ void proc_exit_connector(struct task_struct *task)
281283
msg = buffer_to_cn_msg(buffer);
282284
ev = (struct proc_event *)msg->data;
283285
memset(&ev->event_data, 0, sizeof(ev->event_data));
284-
get_seq(&msg->seq, &ev->cpu);
285286
ev->timestamp_ns = ktime_get_ns();
286287
ev->what = PROC_EVENT_EXIT;
287288
ev->event_data.exit.process_pid = task->pid;
@@ -293,7 +294,7 @@ void proc_exit_connector(struct task_struct *task)
293294
msg->ack = 0; /* not used */
294295
msg->len = sizeof(*ev);
295296
msg->flags = 0; /* not used */
296-
cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
297+
send_msg(msg);
297298
}
298299

299300
/*
@@ -325,7 +326,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
325326
msg->ack = rcvd_ack + 1;
326327
msg->len = sizeof(*ev);
327328
msg->flags = 0; /* not used */
328-
cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
329+
send_msg(msg);
329330
}
330331

331332
/**

0 commit comments

Comments
 (0)