• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/procd/jail/netifd.c

  1 /*
  2  * Copyright (C) 2021 Daniel Golle <daniel@makrotopia.org>
  3  *
  4  * This program is free software; you can redistribute it and/or modify
  5  * it under the terms of the GNU Lesser General Public License version 2.1
  6  * as published by the Free Software Foundation
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11  * GNU General Public License for more details.
 12  *
 13  * launch private ubus and netifd instances for containers with managed
 14  * network namespace.
 15  */
 16 
 17 #define _GNU_SOURCE         /* See feature_test_macros(7) */
 18 #include <stdio.h>
 19 
 20 #include <sys/inotify.h>
 21 #include <sys/stat.h>
 22 #include <sys/types.h>
 23 
 24 #include <pwd.h>
 25 
 26 #include <linux/limits.h>
 27 
 28 #include <libubox/uloop.h>
 29 #include <libubox/utils.h>
 30 #include <libubus.h>
 31 #include <libubox/blobmsg.h>
 32 #include <libubox/blobmsg_json.h>
 33 
 34 #include "netifd.h"
 35 #include "log.h"
 36 
 37 #define INOTIFY_SZ (sizeof(struct inotify_event) + PATH_MAX + 1)
 38 
 39 static char ubusd_path[] = "/sbin/ubusd";
 40 static char netifd_path[] = "/sbin/netifd";
 41 
 42 static char *jail_name, *ubus_sock_path, *ubus_sock_dir;
 43 
 44 static char *inotify_buffer;
 45 static struct uloop_fd fd_inotify_read;
 46 struct ubus_context *ctx;
 47 static struct passwd *ubus_pw;
 48 static pid_t ns_pid;
 49 
 50 static void run_ubusd(struct uloop_timeout *t)
 51 {
 52         static struct blob_buf req;
 53         void *ins, *in, *cmd;
 54         uint32_t id;
 55 
 56         blob_buf_init(&req, 0);
 57         blobmsg_add_string(&req, "name", jail_name);
 58         ins = blobmsg_open_table(&req, "instances");
 59         in = blobmsg_open_table(&req, "ubus");
 60         cmd = blobmsg_open_array(&req, "command");
 61         blobmsg_add_string(&req, "", ubusd_path);
 62         blobmsg_add_string(&req, "", "-s");
 63         blobmsg_add_string(&req, "", ubus_sock_path);
 64         blobmsg_close_array(&req, cmd);
 65 
 66         if (ubus_pw) {
 67                 blobmsg_add_string(&req, "user", "ubus");
 68                 blobmsg_add_string(&req, "group", "ubus");
 69         }
 70 
 71         blobmsg_close_table(&req, in);
 72         blobmsg_close_table(&req, ins);
 73 
 74         if (!ubus_lookup_id(ctx, "container", &id))
 75                 ubus_invoke(ctx, id, "add", req.head, NULL, NULL, 3000);
 76 
 77         blob_buf_free(&req);
 78 }
 79 
 80 
 81 static void run_netifd(struct uloop_timeout *t)
 82 {
 83         static struct blob_buf req;
 84         void *ins, *in, *cmd, *jail, *setns, *setnso, *namespaces, *mount;
 85         char *resolvconf_dir, *resolvconf;
 86         uint32_t id;
 87 
 88         uloop_fd_delete(&fd_inotify_read);
 89         close(fd_inotify_read.fd);
 90 
 91         if (asprintf(&resolvconf_dir, "/tmp/resolv.conf-%s.d", jail_name) == -1)
 92                 return;
 93 
 94         if (asprintf(&resolvconf, "%s/resolv.conf.auto", resolvconf_dir) == -1) {
 95                 free(resolvconf_dir);
 96                 return;
 97         }
 98 
 99         blob_buf_init(&req, 0);
100         blobmsg_add_string(&req, "name", jail_name);
101         ins = blobmsg_open_table(&req, "instances");
102         in = blobmsg_open_table(&req, "netifd");
103 
104         cmd = blobmsg_open_array(&req, "command");
105         blobmsg_add_string(&req, "", netifd_path);
106         blobmsg_add_string(&req, "", "-r");
107         blobmsg_add_string(&req, "", resolvconf);
108         blobmsg_add_string(&req, "", "-s");
109         blobmsg_add_string(&req, "", ubus_sock_path);
110         blobmsg_close_array(&req, cmd);
111 
112         jail = blobmsg_open_table(&req, "jail");
113 
114         setns = blobmsg_open_array(&req, "setns");
115         setnso = blobmsg_open_table(&req, "");
116         blobmsg_add_u32(&req, "pid", ns_pid);
117         namespaces = blobmsg_open_array(&req, "namespaces");
118         blobmsg_add_string(&req, "", "net");
119         blobmsg_add_string(&req, "", "ipc");
120         blobmsg_add_string(&req, "", "uts");
121         blobmsg_close_array(&req, namespaces);
122         blobmsg_close_table(&req, setnso);
123         blobmsg_close_array(&req, setns);
124 
125         mount = blobmsg_open_table(&req, "mount");
126         blobmsg_add_string(&req, ubus_sock_dir, "1");
127         blobmsg_add_string(&req, resolvconf_dir, "1");
128         blobmsg_add_string(&req, "/etc/hotplug.d", "");
129         blobmsg_add_string(&req, "/lib/functions.sh", "");
130         blobmsg_add_string(&req, "/lib/netifd", "");
131         blobmsg_add_string(&req, "/lib/network", "");
132         blobmsg_add_string(&req, "/usr/bin/logger", "");
133         blobmsg_add_string(&req, "/usr/bin/jshn", "");
134         blobmsg_add_string(&req, "/usr/share/libubox/jshn.sh", "");
135         blobmsg_add_string(&req, "/sbin/hotplug-call", "");
136         blobmsg_add_string(&req, "/sbin/udhcpc", "");
137         blobmsg_close_table(&req, mount);
138 
139         blobmsg_add_u8(&req, "log", 1);
140         blobmsg_add_u8(&req, "procfs", 1);
141         blobmsg_add_u8(&req, "sysfs", 1);
142 
143         blobmsg_add_u8(&req, "requirejail", 1);
144 
145         blobmsg_close_table(&req, jail);
146 
147         blobmsg_add_u8(&req, "stdout", 1);
148         blobmsg_add_u8(&req, "stderr", 1);
149 
150         blobmsg_close_table(&req, in);
151         blobmsg_close_table(&req, ins);
152 
153         if (!ubus_lookup_id(ctx, "container", &id))
154                 ubus_invoke(ctx, id, "add", req.head, NULL, NULL, 3000);
155 
156         blob_buf_free(&req);
157         free(resolvconf_dir);
158         free(resolvconf);
159 
160         uloop_end();
161 }
162 
163 static int kill_jail_instance(char *instance)
164 {
165         static struct blob_buf req;
166         uint32_t id;
167         int ret = 0;
168 
169         blob_buf_init(&req, 0);
170         blobmsg_add_string(&req, "name", jail_name);
171         blobmsg_add_string(&req, "instance", instance);
172 
173         if (ubus_lookup_id(ctx, "container", &id) ||
174                 ubus_invoke(ctx, id, "delete", req.head, NULL, NULL, 3000)) {
175                 ret = EIO;
176         }
177 
178         blob_buf_free(&req);
179 
180         return ret;
181 }
182 
183 static struct uloop_timeout netifd_start_timeout = { .cb = run_netifd, };
184 
185 static void inotify_read_handler(struct uloop_fd *u, unsigned int events)
186 {
187         int rc;
188         char *p;
189         struct inotify_event *in;
190 
191         /* read inotify events */
192         while ((rc = read(u->fd, inotify_buffer, INOTIFY_SZ)) == -1 && errno == EINTR);
193 
194         if (rc <= 0)
195                 return;
196 
197         /* process events from buffer */
198         for (p = inotify_buffer;
199             rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event);
200             p += sizeof(struct inotify_event) + in->len) {
201                 in = (struct inotify_event*)p;
202 
203                 if (in->len < 4)
204                         continue;
205 
206                 if (!strncmp("ubus", in->name, in->len))
207                         uloop_timeout_add(&netifd_start_timeout);
208         }
209 }
210 
211 static struct uloop_timeout ubus_start_timeout = { .cb = run_ubusd, };
212 
213 int jail_network_start(struct ubus_context *new_ctx, char *new_jail_name, pid_t new_ns_pid)
214 {
215         ubus_pw = getpwnam("ubus");
216         int ret = 0;
217 
218         ctx = new_ctx;
219         ns_pid = new_ns_pid;
220         jail_name = new_jail_name;
221 
222         asprintf(&ubus_sock_dir, "/var/containers/ubus-%s", jail_name);
223         if (!ubus_sock_dir) {
224                 ret = ENOMEM;
225                 goto errout_dir;
226         }
227 
228         asprintf(&ubus_sock_path, "%s/ubus", ubus_sock_dir);
229         if (!ubus_sock_path) {
230                 ret = ENOMEM;
231                 goto errout_path;
232         }
233 
234         mkdir_p(ubus_sock_dir, 0755);
235         if (ubus_pw) {
236                 ret = chown(ubus_sock_dir, ubus_pw->pw_uid, ubus_pw->pw_gid);
237                 if (ret) {
238                         ret = errno;
239                         goto errout;
240                 }
241         }
242 
243         fd_inotify_read.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
244         fd_inotify_read.cb = inotify_read_handler;
245         if (fd_inotify_read.fd == -1) {
246                 ERROR("failed to initialize inotify handler\n");
247                 ret = EIO;
248                 goto errout;
249         }
250         uloop_fd_add(&fd_inotify_read, ULOOP_READ);
251 
252         inotify_buffer = calloc(1, INOTIFY_SZ);
253         if (!inotify_buffer) {
254                 ret = ENOMEM;
255                 goto errout_inotify;
256         }
257 
258         if (inotify_add_watch(fd_inotify_read.fd, ubus_sock_dir, IN_CREATE) == -1) {
259                 ERROR("failed to add inotify watch on %s\n", ubus_sock_dir);
260                 free(inotify_buffer);
261                 ret = EIO;
262                 goto errout_inotify;
263         }
264 
265         uloop_timeout_add(&ubus_start_timeout);
266         uloop_run();
267 
268         return 0;
269 
270 errout_inotify:
271         close(fd_inotify_read.fd);
272 errout:
273         free(ubus_sock_path);
274 errout_path:
275         free(ubus_sock_dir);
276 errout_dir:
277         return ret;
278 }
279 
280 int jail_network_stop(void)
281 {
282         int ret;
283 
284         ret = kill_jail_instance("netifd");
285         if (ret)
286                 return ret;
287 
288         ret = kill_jail_instance("ubus");
289         if (ret)
290                 return ret;
291 
292         return 0;
293 }
294 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt