• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libudev - interface to udev device information
3  *
4  * Copyright (C) 2008 Kay Sievers <kay@vrfy.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  */
11 
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stddef.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <poll.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 
24 #include "socket-util.h"
25 #include "udev.h"
26 
27 /* wire protocol magic must match */
28 #define UDEV_CTRL_MAGIC                                0xdead1dea
29 
30 enum udev_ctrl_msg_type {
31         UDEV_CTRL_UNKNOWN,
32         UDEV_CTRL_SET_LOG_LEVEL,
33         UDEV_CTRL_STOP_EXEC_QUEUE,
34         UDEV_CTRL_START_EXEC_QUEUE,
35         UDEV_CTRL_RELOAD,
36         UDEV_CTRL_SET_ENV,
37         UDEV_CTRL_SET_CHILDREN_MAX,
38         UDEV_CTRL_PING,
39         UDEV_CTRL_EXIT,
40 };
41 
42 struct udev_ctrl_msg_wire {
43         char version[16];
44         unsigned int magic;
45         enum udev_ctrl_msg_type type;
46         union {
47                 int intval;
48                 char buf[256];
49         };
50 };
51 
52 struct udev_ctrl_msg {
53         int refcount;
54         struct udev_ctrl_connection *conn;
55         struct udev_ctrl_msg_wire ctrl_msg_wire;
56 };
57 
58 struct udev_ctrl {
59         int refcount;
60         struct udev *udev;
61         int sock;
62         union sockaddr_union saddr;
63         socklen_t addrlen;
64         bool bound;
65         bool cleanup_socket;
66         bool connected;
67 };
68 
69 struct udev_ctrl_connection {
70         int refcount;
71         struct udev_ctrl *uctrl;
72         int sock;
73 };
74 
udev_ctrl_new_from_fd(struct udev * udev,int fd)75 struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) {
76         struct udev_ctrl *uctrl;
77         const int on = 1;
78         int r;
79 
80         uctrl = new0(struct udev_ctrl, 1);
81         if (uctrl == NULL)
82                 return NULL;
83         uctrl->refcount = 1;
84         uctrl->udev = udev;
85 
86         if (fd < 0) {
87                 uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
88                 if (uctrl->sock < 0) {
89                         log_error_errno(errno, "error getting socket: %m");
90                         udev_ctrl_unref(uctrl);
91                         return NULL;
92                 }
93         } else {
94                 uctrl->bound = true;
95                 uctrl->sock = fd;
96         }
97         r = setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
98         if (r < 0)
99                 log_warning_errno(errno, "could not set SO_PASSCRED: %m");
100 
101         uctrl->saddr.un.sun_family = AF_LOCAL;
102         strscpy(uctrl->saddr.un.sun_path, sizeof(uctrl->saddr.un.sun_path), UDEV_ROOT_RUN "/udev/control");
103         uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.un.sun_path);
104         return uctrl;
105 }
106 
udev_ctrl_new(struct udev * udev)107 struct udev_ctrl *udev_ctrl_new(struct udev *udev) {
108         return udev_ctrl_new_from_fd(udev, -1);
109 }
110 
udev_ctrl_enable_receiving(struct udev_ctrl * uctrl)111 int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
112         int err;
113 
114         if (!uctrl->bound) {
115                 err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen);
116                 if (err < 0 && errno == EADDRINUSE) {
117                         unlink(uctrl->saddr.un.sun_path);
118                         err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen);
119                 }
120 
121                 if (err < 0) {
122                         err = -errno;
123                         log_error_errno(errno, "bind failed: %m");
124                         return err;
125                 }
126 
127                 err = listen(uctrl->sock, 0);
128                 if (err < 0) {
129                         err = -errno;
130                         log_error_errno(errno, "listen failed: %m");
131                         return err;
132                 }
133 
134                 uctrl->bound = true;
135                 uctrl->cleanup_socket = true;
136         }
137         return 0;
138 }
139 
udev_ctrl_get_udev(struct udev_ctrl * uctrl)140 struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl) {
141         return uctrl->udev;
142 }
143 
udev_ctrl_ref(struct udev_ctrl * uctrl)144 static struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl) {
145         if (uctrl)
146                 uctrl->refcount++;
147 
148         return uctrl;
149 }
150 
udev_ctrl_unref(struct udev_ctrl * uctrl)151 struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl) {
152         if (uctrl && -- uctrl->refcount == 0) {
153                 if (uctrl->sock >= 0)
154                         close(uctrl->sock);
155                 free(uctrl);
156         }
157 
158         return NULL;
159 }
160 
udev_ctrl_cleanup(struct udev_ctrl * uctrl)161 int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
162         if (uctrl == NULL)
163                 return 0;
164         if (uctrl->cleanup_socket)
165                 unlink(uctrl->saddr.un.sun_path);
166         return 0;
167 }
168 
udev_ctrl_get_fd(struct udev_ctrl * uctrl)169 int udev_ctrl_get_fd(struct udev_ctrl *uctrl) {
170         if (uctrl == NULL)
171                 return -EINVAL;
172         return uctrl->sock;
173 }
174 
accept4_fallback(int sockfd)175 static inline int accept4_fallback(int sockfd) {
176         int fd;
177 
178         /* This is racey, but what can we do without accept4? */
179         if ((fd = accept(sockfd, NULL, NULL)) >= 0) {
180                 fcntl(fd, F_SETFL, O_NONBLOCK);
181                 fcntl(fd, F_SETFD, FD_CLOEXEC);
182         }
183 
184         return fd;
185 }
186 
udev_ctrl_get_connection(struct udev_ctrl * uctrl)187 struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl) {
188         struct udev_ctrl_connection *conn;
189         struct ucred ucred = {};
190         const int on = 1;
191         int r;
192 
193         conn = new(struct udev_ctrl_connection, 1);
194         if (conn == NULL)
195                 return NULL;
196         conn->refcount = 1;
197         conn->uctrl = uctrl;
198 
199 #if HAVE_DECL_ACCEPT4
200         conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
201 
202         /* Fallback path when accept4() is unavailable */
203         if ( conn->sock < 0 && (errno == ENOSYS || errno == EOPNOTSUPP) )
204                 conn->sock = accept4_fallback(uctrl->sock);
205 #else
206         conn->sock = accept4_fallback(uctrl->sock);
207 #endif
208 
209         if (conn->sock < 0) {
210                 if (errno != EINTR)
211                         log_error_errno(errno, "unable to receive ctrl connection: %m");
212                 goto err;
213         }
214 
215         /* check peer credential of connection */
216         r = getpeercred(conn->sock, &ucred);
217         if (r < 0) {
218                 log_error_errno(r, "unable to receive credentials of ctrl connection: %m");
219                 goto err;
220         }
221         if (ucred.uid > 0) {
222                 log_error("sender uid="UID_FMT", message ignored", ucred.uid);
223                 goto err;
224         }
225 
226         /* enable receiving of the sender credentials in the messages */
227         r = setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
228         if (r < 0)
229                 log_warning_errno(errno, "could not set SO_PASSCRED: %m");
230 
231         udev_ctrl_ref(uctrl);
232         return conn;
233 err:
234         if (conn->sock >= 0)
235                 close(conn->sock);
236         free(conn);
237         return NULL;
238 }
239 
udev_ctrl_connection_ref(struct udev_ctrl_connection * conn)240 struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn) {
241         if (conn == NULL)
242                 return NULL;
243         conn->refcount++;
244         return conn;
245 }
246 
udev_ctrl_connection_unref(struct udev_ctrl_connection * conn)247 struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn) {
248         if (conn && -- conn->refcount == 0) {
249                 if (conn->sock >= 0)
250                         close(conn->sock);
251 
252                 udev_ctrl_unref(conn->uctrl);
253 
254                 free(conn);
255         }
256 
257         return NULL;
258 }
259 
ctrl_send(struct udev_ctrl * uctrl,enum udev_ctrl_msg_type type,int intval,const char * buf,int timeout)260 static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout) {
261         struct udev_ctrl_msg_wire ctrl_msg_wire;
262         int err = 0;
263 
264         memzero(&ctrl_msg_wire, sizeof(struct udev_ctrl_msg_wire));
265         strcpy(ctrl_msg_wire.version, "udev-" VERSION);
266         ctrl_msg_wire.magic = UDEV_CTRL_MAGIC;
267         ctrl_msg_wire.type = type;
268 
269         if (buf != NULL)
270                 strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf);
271         else
272                 ctrl_msg_wire.intval = intval;
273 
274         if (!uctrl->connected) {
275                 if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0) {
276                         err = -errno;
277                         goto out;
278                 }
279                 uctrl->connected = true;
280         }
281         if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) {
282                 err = -errno;
283                 goto out;
284         }
285 
286         /* wait for peer message handling or disconnect */
287         for (;;) {
288                 struct pollfd pfd[1];
289                 int r;
290 
291                 pfd[0].fd = uctrl->sock;
292                 pfd[0].events = POLLIN;
293                 r = poll(pfd, 1, timeout * MSEC_PER_SEC);
294                 if (r  < 0) {
295                         if (errno == EINTR)
296                                 continue;
297                         err = -errno;
298                         break;
299                 }
300 
301                 if (r > 0 && pfd[0].revents & POLLERR) {
302                         err = -EIO;
303                         break;
304                 }
305 
306                 if (r == 0)
307                         err = -ETIMEDOUT;
308                 break;
309         }
310 out:
311         return err;
312 }
313 
udev_ctrl_send_set_log_level(struct udev_ctrl * uctrl,int priority,int timeout)314 int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout) {
315         return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout);
316 }
317 
udev_ctrl_send_stop_exec_queue(struct udev_ctrl * uctrl,int timeout)318 int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout) {
319         return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout);
320 }
321 
udev_ctrl_send_start_exec_queue(struct udev_ctrl * uctrl,int timeout)322 int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout) {
323         return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout);
324 }
325 
udev_ctrl_send_reload(struct udev_ctrl * uctrl,int timeout)326 int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout) {
327         return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout);
328 }
329 
udev_ctrl_send_set_env(struct udev_ctrl * uctrl,const char * key,int timeout)330 int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout) {
331         return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout);
332 }
333 
udev_ctrl_send_set_children_max(struct udev_ctrl * uctrl,int count,int timeout)334 int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout) {
335         return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout);
336 }
337 
udev_ctrl_send_ping(struct udev_ctrl * uctrl,int timeout)338 int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout) {
339         return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout);
340 }
341 
udev_ctrl_send_exit(struct udev_ctrl * uctrl,int timeout)342 int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout) {
343         return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout);
344 }
345 
udev_ctrl_receive_msg(struct udev_ctrl_connection * conn)346 struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn) {
347         struct udev_ctrl_msg *uctrl_msg;
348         ssize_t size;
349         struct cmsghdr *cmsg;
350         struct iovec iov;
351         char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
352         struct msghdr smsg = {
353                 .msg_iov = &iov,
354                 .msg_iovlen = 1,
355                 .msg_control = cred_msg,
356                 .msg_controllen = sizeof(cred_msg),
357         };
358         struct ucred *cred;
359 
360         uctrl_msg = new0(struct udev_ctrl_msg, 1);
361         if (uctrl_msg == NULL)
362                 return NULL;
363         uctrl_msg->refcount = 1;
364         uctrl_msg->conn = conn;
365         udev_ctrl_connection_ref(conn);
366 
367         /* wait for the incoming message */
368         for (;;) {
369                 struct pollfd pfd[1];
370                 int r;
371 
372                 pfd[0].fd = conn->sock;
373                 pfd[0].events = POLLIN;
374 
375                 r = poll(pfd, 1, 10000);
376                 if (r  < 0) {
377                         if (errno == EINTR)
378                                 continue;
379                         goto err;
380                 } else if (r == 0) {
381                         log_error("timeout waiting for ctrl message");
382                         goto err;
383                 } else {
384                         if (!(pfd[0].revents & POLLIN)) {
385                                 log_error_errno(errno, "ctrl connection error: %m");
386                                 goto err;
387                         }
388                 }
389 
390                 break;
391         }
392 
393         iov.iov_base = &uctrl_msg->ctrl_msg_wire;
394         iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
395 
396         size = recvmsg(conn->sock, &smsg, 0);
397         if (size <  0) {
398                 log_error_errno(errno, "unable to receive ctrl message: %m");
399                 goto err;
400         }
401 
402         cmsg_close_all(&smsg);
403 
404         cmsg = CMSG_FIRSTHDR(&smsg);
405         cred = (struct ucred *) CMSG_DATA(cmsg);
406 
407         if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
408                 log_error("no sender credentials received, message ignored");
409                 goto err;
410         }
411 
412         if (cred->uid != 0) {
413                 log_error("sender uid="UID_FMT", message ignored", cred->uid);
414                 goto err;
415         }
416 
417         if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
418                 log_error("message magic 0x%08x doesn't match, ignore it", uctrl_msg->ctrl_msg_wire.magic);
419                 goto err;
420         }
421 
422         return uctrl_msg;
423 err:
424         udev_ctrl_msg_unref(uctrl_msg);
425         return NULL;
426 }
427 
udev_ctrl_msg_unref(struct udev_ctrl_msg * ctrl_msg)428 struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg) {
429         if (ctrl_msg && -- ctrl_msg->refcount == 0) {
430                 udev_ctrl_connection_unref(ctrl_msg->conn);
431                 free(ctrl_msg);
432         }
433 
434         return NULL;
435 }
436 
udev_ctrl_get_set_log_level(struct udev_ctrl_msg * ctrl_msg)437 int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg) {
438         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL)
439                 return ctrl_msg->ctrl_msg_wire.intval;
440         return -1;
441 }
442 
udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg * ctrl_msg)443 int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg) {
444         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE)
445                 return 1;
446         return -1;
447 }
448 
udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg * ctrl_msg)449 int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg) {
450         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE)
451                 return 1;
452         return -1;
453 }
454 
udev_ctrl_get_reload(struct udev_ctrl_msg * ctrl_msg)455 int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg) {
456         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD)
457                 return 1;
458         return -1;
459 }
460 
udev_ctrl_get_set_env(struct udev_ctrl_msg * ctrl_msg)461 const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg) {
462         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV)
463                 return ctrl_msg->ctrl_msg_wire.buf;
464         return NULL;
465 }
466 
udev_ctrl_get_set_children_max(struct udev_ctrl_msg * ctrl_msg)467 int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg) {
468         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_CHILDREN_MAX)
469                 return ctrl_msg->ctrl_msg_wire.intval;
470         return -1;
471 }
472 
udev_ctrl_get_ping(struct udev_ctrl_msg * ctrl_msg)473 int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg) {
474         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING)
475                 return 1;
476         return -1;
477 }
478 
udev_ctrl_get_exit(struct udev_ctrl_msg * ctrl_msg)479 int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg) {
480         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_EXIT)
481                 return 1;
482         return -1;
483 }
484