]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_user_nic.c
2a5c3a43a09f3ac2dedc5d0508a249ed4e03a948
[mirror_lxc.git] / src / lxc / lxc_user_nic.c
1 /*
2 *
3 * Copyright © 2013 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2013 Canonical Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #define _GNU_SOURCE
21 #include <alloca.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <grp.h>
26 #include <pwd.h>
27 #include <sched.h>
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <arpa/inet.h>
34 #include <linux/netlink.h>
35 #include <linux/rtnetlink.h>
36 #include <linux/sockios.h>
37 #include <net/if.h>
38 #include <net/if_arp.h>
39 #include <netinet/in.h>
40 #include <sys/file.h>
41 #include <sys/ioctl.h>
42 #include <sys/mman.h>
43 #include <sys/param.h>
44 #include <sys/socket.h>
45 #include <sys/stat.h>
46 #include <sys/types.h>
47
48 #include "config.h"
49 #include "namespace.h"
50 #include "network.h"
51 #include "utils.h"
52
53 #define usernic_debug_stream(stream, format, ...) \
54 do { \
55 fprintf(stream, "%s: %d: %s: " format, __FILE__, __LINE__, \
56 __func__, __VA_ARGS__); \
57 } while (false)
58
59 #define usernic_error(format, ...) usernic_debug_stream(stderr, format, __VA_ARGS__)
60
61 static void usage(char *me, bool fail)
62 {
63 fprintf(stderr, "Usage: %s create {lxcpath} {name} {pid} {type} "
64 "{bridge} {nicname}\n", me);
65 fprintf(stderr, "Usage: %s delete {lxcpath} {name} "
66 "{/proc/<pid>/ns/net} {type} {bridge} {nicname}\n", me);
67 fprintf(stderr, "{nicname} is the name to use inside the container\n");
68
69 if (fail)
70 exit(EXIT_FAILURE);
71
72 exit(EXIT_SUCCESS);
73 }
74
75 static int open_and_lock(char *path)
76 {
77 int fd, ret;
78 struct flock lk;
79
80 fd = open(path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR);
81 if (fd < 0) {
82 usernic_error("Failed to open \"%s\": %s\n", path,
83 strerror(errno));
84 return -1;
85 }
86
87 lk.l_type = F_WRLCK;
88 lk.l_whence = SEEK_SET;
89 lk.l_start = 0;
90 lk.l_len = 0;
91
92 ret = fcntl(fd, F_SETLKW, &lk);
93 if (ret < 0) {
94 usernic_error("Failed to lock \"%s\": %s\n", path,
95 strerror(errno));
96 close(fd);
97 return -1;
98 }
99
100 return fd;
101 }
102
103 static char *get_username(void)
104 {
105 struct passwd *pwd;
106
107 pwd = getpwuid(getuid());
108 if (!pwd) {
109 usernic_error("Failed to get username: %s\n", strerror(errno));
110 return NULL;
111 }
112
113 return pwd->pw_name;
114 }
115
116 static void free_groupnames(char **groupnames)
117 {
118 int i;
119
120 if (!groupnames)
121 return;
122
123 for (i = 0; groupnames[i]; i++)
124 free(groupnames[i]);
125
126 free(groupnames);
127 }
128
129 static char **get_groupnames(void)
130 {
131 int ngroups;
132 gid_t *group_ids;
133 int ret, i;
134 char **groupnames;
135 struct group *gr;
136
137 ngroups = getgroups(0, NULL);
138 if (ngroups < 0) {
139 usernic_error("Failed to get number of groups the user "
140 "belongs to: %s\n", strerror(errno));
141 return NULL;
142 }
143 if (ngroups == 0)
144 return NULL;
145
146 group_ids = malloc(sizeof(gid_t) * ngroups);
147 if (!group_ids) {
148 usernic_error("Failed to allocate memory while getting groups "
149 "the user belongs to: %s\n",
150 strerror(errno));
151 return NULL;
152 }
153
154 ret = getgroups(ngroups, group_ids);
155 if (ret < 0) {
156 free(group_ids);
157 usernic_error("Failed to get process groups: %s\n",
158 strerror(errno));
159 return NULL;
160 }
161
162 groupnames = malloc(sizeof(char *) * (ngroups + 1));
163 if (!groupnames) {
164 free(group_ids);
165 usernic_error("Failed to allocate memory while getting group "
166 "names: %s\n",
167 strerror(errno));
168 return NULL;
169 }
170
171 memset(groupnames, 0, sizeof(char *) * (ngroups + 1));
172
173 for (i = 0; i < ngroups; i++) {
174 gr = getgrgid(group_ids[i]);
175 if (!gr) {
176 usernic_error("Failed to get group name: %s\n",
177 strerror(errno));
178 free(group_ids);
179 free_groupnames(groupnames);
180 return NULL;
181 }
182
183 groupnames[i] = strdup(gr->gr_name);
184 if (!groupnames[i]) {
185 usernic_error("Failed to copy group name \"%s\"",
186 gr->gr_name);
187 free(group_ids);
188 free_groupnames(groupnames);
189 return NULL;
190 }
191 }
192
193 free(group_ids);
194
195 return groupnames;
196 }
197
198 static bool name_is_in_groupnames(char *name, char **groupnames)
199 {
200 while (groupnames) {
201 if (!strcmp(name, *groupnames))
202 return true;
203 groupnames++;
204 }
205 return false;
206 }
207
208 struct alloted_s {
209 char *name;
210 int allowed;
211 struct alloted_s *next;
212 };
213
214 static struct alloted_s *append_alloted(struct alloted_s **head, char *name,
215 int n)
216 {
217 struct alloted_s *cur, *al;
218
219 if (!head || !name) {
220 /* Sanity check. Parameters should not be null. */
221 usernic_error("%s\n", "Unexpected NULL argument");
222 return NULL;
223 }
224
225 al = malloc(sizeof(struct alloted_s));
226 if (!al) {
227 usernic_error("Failed to allocate memory: %s\n",
228 strerror(errno));
229 return NULL;
230 }
231
232 al->name = strdup(name);
233 if (!al->name) {
234 free(al);
235 return NULL;
236 }
237
238 al->allowed = n;
239 al->next = NULL;
240
241 if (!*head) {
242 *head = al;
243 return al;
244 }
245
246 cur = *head;
247 while (cur->next)
248 cur = cur->next;
249 cur->next = al;
250
251 return al;
252 }
253
254 static void free_alloted(struct alloted_s **head)
255 {
256 struct alloted_s *cur;
257
258 if (!head)
259 return;
260
261 cur = *head;
262 while (cur) {
263 cur = cur->next;
264 free((*head)->name);
265 free(*head);
266 *head = cur;
267 }
268 }
269
270 /* The configuration file consists of lines of the form:
271 *
272 * user type bridge count
273 * or
274 * @group type bridge count
275 *
276 * Return the count entry for the calling user if there is one. Else
277 * return -1.
278 */
279 static int get_alloted(char *me, char *intype, char *link,
280 struct alloted_s **alloted)
281 {
282 int n, ret;
283 char name[100], type[100], br[100];
284 char **groups;
285 FILE *fin;
286
287 int count = 0;
288 size_t len = 0;
289 char *line = NULL;
290
291 fin = fopen(LXC_USERNIC_CONF, "r");
292 if (!fin) {
293 usernic_error("Failed to open \"%s\": %s\n", LXC_USERNIC_CONF,
294 strerror(errno));
295 return -1;
296 }
297
298 groups = get_groupnames();
299 while ((getline(&line, &len, fin)) != -1) {
300 ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name,
301 type, br, &n);
302 if (ret != 4)
303 continue;
304
305 if (strlen(name) == 0)
306 continue;
307
308 if (strcmp(name, me)) {
309 if (name[0] != '@')
310 continue;
311
312 if (!name_is_in_groupnames(name + 1, groups))
313 continue;
314 }
315
316 if (strcmp(type, intype))
317 continue;
318
319 if (strcmp(link, br))
320 continue;
321
322 /* Found the user or group with the appropriate settings,
323 * therefore finish the search. What to do if there are more
324 * than one applicable lines? not specified in the docs. Since
325 * getline is implemented with realloc, we don't need to free
326 * line until exiting func.
327 *
328 * If append_alloted returns NULL, e.g. due to a malloc error,
329 * we set count to 0 and break the loop, allowing cleanup and
330 * then exiting from main().
331 */
332 if (!append_alloted(alloted, name, n)) {
333 count = 0;
334 break;
335 }
336 count += n;
337 }
338
339 free_groupnames(groups);
340 fclose(fin);
341 free(line);
342
343 /* Now return the total number of nics that this user can create. */
344 return count;
345 }
346
347 static char *get_eol(char *s, char *e)
348 {
349 while ((s < e) && *s && (*s != '\n'))
350 s++;
351 return s;
352 }
353
354 static char *get_eow(char *s, char *e)
355 {
356 while ((s < e) && *s && !isblank(*s) && (*s != '\n'))
357 s++;
358 return s;
359 }
360
361 static char *find_line(char *buf_start, char *buf_end, char *name,
362 char *net_type, char *net_link, char *net_dev,
363 bool *owner, bool *found, bool *keep)
364 {
365 char *end_of_line, *end_of_word, *line;
366
367 while (buf_start < buf_end) {
368 size_t len;
369 char netdev_name[IFNAMSIZ];
370
371 *found = false;
372 *keep = true;
373 *owner = false;
374
375 end_of_line = get_eol(buf_start, buf_end);
376 if (end_of_line >= buf_end)
377 return NULL;
378
379 line = buf_start;
380 if (*buf_start == '#')
381 goto next;
382
383 while ((buf_start < buf_end) && isblank(*buf_start))
384 buf_start++;
385
386 /* Check whether the line contains the caller's name. */
387 end_of_word = get_eow(buf_start, buf_end);
388 /* corrupt db */
389 if (!end_of_word)
390 return NULL;
391
392 if (strncmp(buf_start, name, strlen(name)))
393 *found = false;
394
395 *owner = true;
396
397 buf_start = end_of_word + 1;
398 while ((buf_start < buf_end) && isblank(*buf_start))
399 buf_start++;
400
401 /* Check whether line is of the right network type. */
402 end_of_word = get_eow(buf_start, buf_end);
403 /* corrupt db */
404 if (!end_of_word)
405 return NULL;
406
407 if (strncmp(buf_start, net_type, strlen(net_type)))
408 *found = false;
409
410 buf_start = end_of_word + 1;
411 while ((buf_start < buf_end) && isblank(*buf_start))
412 buf_start++;
413
414 /* Check whether line is contains the right link. */
415 end_of_word = get_eow(buf_start, buf_end);
416 /* corrupt db */
417 if (!end_of_word)
418 return NULL;
419
420 if (strncmp(buf_start, net_link, strlen(net_link)))
421 *found = false;
422
423 buf_start = end_of_word + 1;
424 while ((buf_start < buf_end) && isblank(*buf_start))
425 buf_start++;
426
427 /* Check whether line contains the right network device. */
428 end_of_word = get_eow(buf_start, buf_end);
429 /* corrupt db */
430 if (!end_of_word)
431 return NULL;
432
433 len = end_of_word - buf_start;
434 /* corrupt db */
435 if (len >= IFNAMSIZ)
436 return NULL;
437
438 memcpy(netdev_name, buf_start, len);
439 netdev_name[len] = '\0';
440 *keep = lxc_nic_exists(netdev_name);
441
442 if (net_dev && !strcmp(netdev_name, net_dev))
443 *found = true;
444
445 return line;
446
447 next:
448 buf_start = end_of_line + 1;
449 }
450
451 return NULL;
452 }
453
454 static int instantiate_veth(char *veth1, char *veth2)
455 {
456 int ret;
457
458 ret = lxc_veth_create(veth1, veth2);
459 if (ret < 0) {
460 usernic_error("Failed to create %s-%s : %s.\n", veth1, veth2,
461 strerror(-ret));
462 return -1;
463 }
464
465 /* Changing the high byte of the mac address to 0xfe, the bridge
466 * interface will always keep the host's mac address and not take the
467 * mac address of a container. */
468 ret = setup_private_host_hw_addr(veth1);
469 if (ret < 0)
470 usernic_error("Failed to change mac address of host interface "
471 "%s : %s\n", veth1, strerror(-ret));
472
473 return netdev_set_flag(veth1, IFF_UP);
474 }
475
476 static int get_mtu(char *name)
477 {
478 int idx;
479
480 idx = if_nametoindex(name);
481 if (idx < 0)
482 return -1;
483 return netdev_get_mtu(idx);
484 }
485
486 static int create_nic(char *nic, char *br, int pid, char **cnic)
487 {
488 char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
489 int mtu, ret;
490
491 ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic);
492 if (ret < 0 || ret >= IFNAMSIZ) {
493 usernic_error("%s", "Could not create nic name\n");
494 return -1;
495 }
496
497 ret = snprintf(veth2buf, IFNAMSIZ, "%sp", veth1buf);
498 if (ret < 0 || ret >= IFNAMSIZ) {
499 usernic_error("%s\n", "Could not create nic name");
500 return -1;
501 }
502 /* create the nics */
503 ret = instantiate_veth(veth1buf, veth2buf);
504 if (ret < 0) {
505 usernic_error("%s", "Error creating veth tunnel\n");
506 return -1;
507 }
508
509 if (strcmp(br, "none")) {
510 /* copy the bridge's mtu to both ends */
511 mtu = get_mtu(br);
512 if (mtu > 0) {
513 ret = lxc_netdev_set_mtu(veth1buf, mtu);
514 if (ret < 0) {
515 usernic_error("Failed to set mtu to %d on %s\n",
516 mtu, veth1buf);
517 goto out_del;
518 }
519
520 ret = lxc_netdev_set_mtu(veth2buf, mtu);
521 if (ret < 0) {
522 usernic_error("Failed to set mtu to %d on %s\n",
523 mtu, veth2buf);
524 goto out_del;
525 }
526 }
527
528 /* attach veth1 to bridge */
529 ret = lxc_bridge_attach(br, veth1buf);
530 if (ret < 0) {
531 usernic_error("Error attaching %s to %s\n", veth1buf, br);
532 goto out_del;
533 }
534 }
535
536 /* pass veth2 to target netns */
537 ret = lxc_netdev_move_by_name(veth2buf, pid, NULL);
538 if (ret < 0) {
539 usernic_error("Error moving %s to network namespace of %d\n",
540 veth2buf, pid);
541 goto out_del;
542 }
543
544 *cnic = strdup(veth2buf);
545 if (!*cnic) {
546 usernic_error("Failed to copy string \"%s\"\n", veth2buf);
547 return -1;
548 }
549
550 return 0;
551
552 out_del:
553 lxc_netdev_delete_by_name(veth1buf);
554 return -1;
555 }
556
557 struct entry_line {
558 char *start;
559 int len;
560 bool keep;
561 };
562
563 static bool cull_entries(int fd, char *name, char *net_type, char *net_link,
564 char *net_dev, bool *found_nicname)
565 {
566 int i, ret;
567 char *buf, *buf_end, *buf_start;
568 struct stat sb;
569 int n = 0;
570 bool found, keep;
571 struct entry_line *entry_lines = NULL;
572
573 ret = fstat(fd, &sb);
574 if (ret < 0) {
575 usernic_error("Failed to fstat: %s\n", strerror(errno));
576 return false;
577 }
578
579 if (!sb.st_size)
580 return false;
581
582 buf = lxc_strmmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
583 if (buf == MAP_FAILED) {
584 usernic_error("Failed to establish shared memory mapping: %s\n",
585 strerror(errno));
586 return false;
587 }
588
589 buf_start = buf;
590 buf_end = buf + sb.st_size;
591 while ((buf_start = find_line(buf_start, buf_end, name, net_type,
592 net_link, net_dev, &(bool){true}, &found,
593 &keep))) {
594 struct entry_line *newe;
595
596 newe = realloc(entry_lines, sizeof(*entry_lines) * (n + 1));
597 if (!newe) {
598 free(entry_lines);
599 lxc_strmunmap(buf, sb.st_size);
600 return false;
601 }
602
603 if (found)
604 *found_nicname = true;
605
606 entry_lines = newe;
607 entry_lines[n].start = buf_start;
608 entry_lines[n].len = get_eol(buf_start, buf_end) - entry_lines[n].start;
609 entry_lines[n].keep = keep;
610 n++;
611
612 buf_start += entry_lines[n - 1].len + 1;
613 if (buf_start >= buf_end)
614 break;
615 }
616
617 buf_start = buf;
618 for (i = 0; i < n; i++) {
619 if (!entry_lines[i].keep)
620 continue;
621
622 memcpy(buf_start, entry_lines[i].start, entry_lines[i].len);
623 buf_start += entry_lines[i].len;
624 *buf_start = '\n';
625 buf_start++;
626 }
627 free(entry_lines);
628
629 ret = ftruncate(fd, buf_start - buf);
630 lxc_strmunmap(buf, sb.st_size);
631 if (ret < 0)
632 usernic_error("Failed to set new file size: %s\n",
633 strerror(errno));
634
635 return true;
636 }
637
638 static int count_entries(char *buf, off_t len, char *name, char *net_type, char *net_link)
639 {
640 int count = 0;
641 bool owner = false;;
642 char *buf_end;
643
644 buf_end = &buf[len];
645 while ((buf = find_line(buf, buf_end, name, net_type, net_link, NULL,
646 &owner, &(bool){true}, &(bool){true}))) {
647 if (owner)
648 count++;
649 buf = get_eol(buf, buf_end) + 1;
650 if (buf >= buf_end)
651 break;
652 }
653
654 return count;
655 }
656
657 /* The dbfile has lines of the format: user type bridge nicname. */
658 static char *get_nic_if_avail(int fd, struct alloted_s *names, int pid,
659 char *intype, char *br, int allowed, char **cnic)
660 {
661 int ret;
662 size_t slen;
663 char *newline, *owner;
664 char nicname[IFNAMSIZ];
665 struct stat sb;
666 struct alloted_s *n;
667 int count = 0;
668 char *buf = NULL;
669
670 for (n = names; n != NULL; n = n->next)
671 cull_entries(fd, n->name, intype, br, NULL, NULL);
672
673 if (allowed == 0)
674 return NULL;
675
676 owner = names->name;
677
678 ret = fstat(fd, &sb);
679 if (ret < 0) {
680 usernic_error("Failed to fstat: %s\n", strerror(errno));
681 return NULL;
682 }
683
684 if (sb.st_size > 0) {
685 buf = lxc_strmmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
686 MAP_SHARED, fd, 0);
687 if (buf == MAP_FAILED) {
688 usernic_error("Failed to establish shared memory "
689 "mapping: %s\n", strerror(errno));
690 return NULL;
691 }
692
693 owner = NULL;
694 for (n = names; n != NULL; n = n->next) {
695 count = count_entries(buf, sb.st_size, n->name, intype, br);
696 if (count >= n->allowed)
697 continue;
698
699 owner = n->name;
700 break;
701 }
702
703 lxc_strmunmap(buf, sb.st_size);
704 }
705
706 if (owner == NULL)
707 return NULL;
708
709 ret = snprintf(nicname, sizeof(nicname), "vethXXXXXX");
710 if (ret < 0 || (size_t)ret >= sizeof(nicname))
711 return NULL;
712
713 if (!lxc_mkifname(nicname))
714 return NULL;
715
716 ret = create_nic(nicname, br, pid, cnic);
717 if (ret < 0) {
718 usernic_error("%s", "Failed to create new nic\n");
719 return NULL;
720 }
721
722 /* strlen(owner)
723 * +
724 * " "
725 * +
726 * strlen(intype)
727 * +
728 * " "
729 * +
730 * strlen(br)
731 * +
732 * " "
733 * +
734 * strlen(nicname)
735 * +
736 * \n
737 * +
738 * \0
739 */
740 slen = strlen(owner) + strlen(intype) + strlen(br) + strlen(nicname) + 4;
741 newline = malloc(slen + 1);
742 if (!newline) {
743 free(newline);
744 usernic_error("Failed allocate memory: %s\n", strerror(errno));
745 return NULL;
746 }
747
748 ret = snprintf(newline, slen + 1, "%s %s %s %s\n", owner, intype, br, nicname);
749 if (ret < 0 || (size_t)ret >= (slen + 1)) {
750 if (lxc_netdev_delete_by_name(nicname) != 0)
751 usernic_error("Error unlinking %s\n", nicname);
752 free(newline);
753 return NULL;
754 }
755
756 /* Note that the file needs to be truncated to the size **without** the
757 * \0 byte! Files are not \0-terminated!
758 */
759 ret = ftruncate(fd, sb.st_size + slen);
760 if (ret < 0)
761 usernic_error("Failed to truncate file: %s\n", strerror(errno));
762
763 buf = lxc_strmmap(NULL, sb.st_size + slen, PROT_READ | PROT_WRITE,
764 MAP_SHARED, fd, 0);
765 if (buf == MAP_FAILED) {
766 usernic_error("Failed to establish shared memory mapping: %s\n",
767 strerror(errno));
768 if (lxc_netdev_delete_by_name(nicname) != 0)
769 usernic_error("Error unlinking %s\n", nicname);
770 free(newline);
771 return NULL;
772 }
773
774 /* Note that the memory needs to be moved in the buffer **without** the
775 * \0 byte! Files are not \0-terminated!
776 */
777 memmove(buf + sb.st_size, newline, slen);
778 free(newline);
779 lxc_strmunmap(buf, sb.st_size + slen);
780
781 return strdup(nicname);
782 }
783
784 static bool create_db_dir(char *fnam)
785 {
786 int ret;
787 char *p;
788
789 p = alloca(strlen(fnam) + 1);
790 strcpy(p, fnam);
791 fnam = p;
792 p = p + 1;
793
794 again:
795 while (*p && *p != '/')
796 p++;
797 if (!*p)
798 return true;
799
800 *p = '\0';
801
802 ret = mkdir(fnam, 0755);
803 if (ret < 0 && errno != EEXIST) {
804 usernic_error("Failed to create %s: %s\n", fnam,
805 strerror(errno));
806 *p = '/';
807 return false;
808 }
809 *(p++) = '/';
810
811 goto again;
812 }
813
814 static char *lxc_secure_rename_in_ns(int pid, char *oldname, char *newname,
815 int *container_veth_ifidx)
816 {
817 int ret;
818 pid_t pid_self;
819 uid_t ruid, suid, euid;
820 char ifname[IFNAMSIZ];
821 char *string_ret = NULL, *name = NULL;
822 int fd = -1, ifindex = -1, ofd = -1;
823
824 pid_self = lxc_raw_getpid();
825 ofd = lxc_preserve_ns(pid_self, "net");
826 if (ofd < 0) {
827 usernic_error("Failed opening network namespace path for %d", pid_self);
828 return NULL;
829 }
830
831 fd = lxc_preserve_ns(pid, "net");
832 if (fd < 0) {
833 usernic_error("Failed opening network namespace path for %d", pid);
834 goto do_partial_cleanup;
835 }
836
837 ret = getresuid(&ruid, &euid, &suid);
838 if (ret < 0) {
839 usernic_error("Failed to retrieve real, effective, and saved "
840 "user IDs: %s\n",
841 strerror(errno));
842 goto do_partial_cleanup;
843 }
844
845 ret = setns(fd, CLONE_NEWNET);
846 close(fd);
847 fd = -1;
848 if (ret < 0) {
849 usernic_error("Failed to setns() to the network namespace of "
850 "the container with PID %d: %s\n",
851 pid, strerror(errno));
852 goto do_partial_cleanup;
853 }
854
855 ret = setresuid(ruid, ruid, 0);
856 if (ret < 0) {
857 usernic_error("Failed to drop privilege by setting effective "
858 "user id and real user id to %d, and saved user "
859 "ID to 0: %s\n",
860 ruid, strerror(errno));
861 /* It's ok to jump to do_full_cleanup here since setresuid()
862 * will succeed when trying to set real, effective, and saved to
863 * values they currently have.
864 */
865 goto do_full_cleanup;
866 }
867
868 /* Check if old interface exists. */
869 ifindex = if_nametoindex(oldname);
870 if (!ifindex) {
871 usernic_error("Failed to get netdev index: %s\n", strerror(errno));
872 goto do_full_cleanup;
873 }
874
875 /* When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
876 * netlink will replace the format specifier with an appropriate index.
877 * So we pass "eth%d".
878 */
879 if (newname)
880 name = newname;
881 else
882 name = "eth%d";
883
884 ret = lxc_netdev_rename_by_name(oldname, name);
885 name = NULL;
886 if (ret < 0) {
887 usernic_error("Error %d renaming netdev %s to %s in container\n",
888 ret, oldname, newname ? newname : "eth%d");
889 goto do_full_cleanup;
890 }
891
892 /* Retrieve new name for interface. */
893 if (!if_indextoname(ifindex, ifname)) {
894 usernic_error("Failed to get new netdev name: %s\n", strerror(errno));
895 goto do_full_cleanup;
896 }
897
898 /* Allocation failure for strdup() is checked below. */
899 name = strdup(ifname);
900 string_ret = name;
901 *container_veth_ifidx = ifindex;
902
903 do_full_cleanup:
904 ret = setresuid(ruid, euid, suid);
905 if (ret < 0) {
906 usernic_error("Failed to restore privilege by setting "
907 "effective user id to %d, real user id to %d, "
908 "and saved user ID to %d: %s\n", ruid, euid, suid,
909 strerror(errno));
910
911 string_ret = NULL;
912 }
913
914 ret = setns(ofd, CLONE_NEWNET);
915 if (ret < 0) {
916 usernic_error("Failed to setns() to original network namespace "
917 "of PID %d: %s\n", ofd, strerror(errno));
918
919 string_ret = NULL;
920 }
921
922 do_partial_cleanup:
923 if (fd >= 0)
924 close(fd);
925
926 if (!string_ret && name)
927 free(name);
928
929 close(ofd);
930
931 return string_ret;
932 }
933
934 /* If the caller (real uid, not effective uid) may read the /proc/[pid]/ns/net,
935 * then it is either the caller's netns or one which it created.
936 */
937 static bool may_access_netns(int pid)
938 {
939 int ret;
940 char s[200];
941 uid_t ruid, suid, euid;
942 bool may_access = false;
943
944 ret = getresuid(&ruid, &euid, &suid);
945 if (ret < 0) {
946 usernic_error("Failed to retrieve real, effective, and saved "
947 "user IDs: %s\n",
948 strerror(errno));
949 return false;
950 }
951
952 ret = setresuid(ruid, ruid, euid);
953 if (ret < 0) {
954 usernic_error("Failed to drop privilege by setting effective "
955 "user id and real user id to %d, and saved user "
956 "ID to %d: %s\n",
957 ruid, euid, strerror(errno));
958 return false;
959 }
960
961 ret = snprintf(s, 200, "/proc/%d/ns/net", pid);
962 if (ret < 0 || ret >= 200)
963 return false;
964
965 ret = access(s, R_OK);
966 may_access = true;
967 if (ret < 0) {
968 may_access = false;
969 usernic_error("Uid %d may not access %s: %s\n", (int)ruid, s, strerror(errno));
970 }
971
972 ret = setresuid(ruid, euid, suid);
973 if (ret < 0) {
974 usernic_error("Failed to restore user id to %d, real user id "
975 "to %d, and saved user ID to %d: %s\n",
976 ruid, euid, suid, strerror(errno));
977 may_access = false;
978 }
979
980 return may_access;
981 }
982
983 struct user_nic_args {
984 char *cmd;
985 char *lxc_path;
986 char *lxc_name;
987 char *pid;
988 char *type;
989 char *link;
990 char *veth_name;
991 };
992
993 #define LXC_USERNIC_CREATE 0
994 #define LXC_USERNIC_DELETE 1
995
996 static bool is_privileged_over_netns(int netns_fd)
997 {
998 int ret;
999 pid_t pid_self;
1000 uid_t euid, ruid, suid;
1001 bool bret = false;
1002 int ofd = -1;
1003
1004 pid_self = lxc_raw_getpid();
1005 ofd = lxc_preserve_ns(pid_self, "net");
1006 if (ofd < 0) {
1007 usernic_error("Failed opening network namespace path for %d", pid_self);
1008 return false;
1009 }
1010
1011 ret = getresuid(&ruid, &euid, &suid);
1012 if (ret < 0) {
1013 usernic_error("Failed to retrieve real, effective, and saved "
1014 "user IDs: %s\n",
1015 strerror(errno));
1016 goto do_partial_cleanup;
1017 }
1018
1019 ret = setns(netns_fd, CLONE_NEWNET);
1020 if (ret < 0) {
1021 usernic_error("Failed to setns() to network namespace %s\n",
1022 strerror(errno));
1023 goto do_partial_cleanup;
1024 }
1025
1026 ret = setresuid(ruid, ruid, 0);
1027 if (ret < 0) {
1028 usernic_error("Failed to drop privilege by setting effective "
1029 "user id and real user id to %d, and saved user "
1030 "ID to 0: %s\n",
1031 ruid, strerror(errno));
1032 /* It's ok to jump to do_full_cleanup here since setresuid()
1033 * will succeed when trying to set real, effective, and saved to
1034 * values they currently have.
1035 */
1036 goto do_full_cleanup;
1037 }
1038
1039 /* Test whether we are privileged over the network namespace. To do this
1040 * we try to delete the loopback interface which is not possible. If we
1041 * are privileged over the network namespace we will get ENOTSUP. If we
1042 * are not privileged over the network namespace we will get EPERM.
1043 */
1044 ret = lxc_netdev_delete_by_name("lo");
1045 if (ret == -ENOTSUP)
1046 bret = true;
1047
1048 do_full_cleanup:
1049 ret = setresuid(ruid, euid, suid);
1050 if (ret < 0) {
1051 usernic_error("Failed to restore privilege by setting "
1052 "effective user id to %d, real user id to %d, "
1053 "and saved user ID to %d: %s\n", ruid, euid, suid,
1054 strerror(errno));
1055
1056 bret = false;
1057 }
1058
1059 ret = setns(ofd, CLONE_NEWNET);
1060 if (ret < 0) {
1061 usernic_error("Failed to setns() to original network namespace "
1062 "of PID %d: %s\n", ofd, strerror(errno));
1063
1064 bret = false;
1065 }
1066
1067 do_partial_cleanup:
1068
1069 close(ofd);
1070 return bret;
1071 }
1072
1073 int main(int argc, char *argv[])
1074 {
1075 int fd, n, pid, request, ret;
1076 char *me, *newname;
1077 struct user_nic_args args;
1078 int container_veth_ifidx = -1, host_veth_ifidx = -1, netns_fd = -1;
1079 char *cnic = NULL, *nicname = NULL;
1080 struct alloted_s *alloted = NULL;
1081
1082 if (argc < 7 || argc > 8) {
1083 usage(argv[0], true);
1084 exit(EXIT_FAILURE);
1085 }
1086
1087 memset(&args, 0, sizeof(struct user_nic_args));
1088 args.cmd = argv[1];
1089 args.lxc_path = argv[2];
1090 args.lxc_name = argv[3];
1091 args.pid = argv[4];
1092 args.type = argv[5];
1093 args.link = argv[6];
1094 if (argc >= 8)
1095 args.veth_name = argv[7];
1096
1097 if (!strcmp(args.cmd, "create")) {
1098 request = LXC_USERNIC_CREATE;
1099 } else if (!strcmp(args.cmd, "delete")) {
1100 request = LXC_USERNIC_DELETE;
1101 } else {
1102 usage(argv[0], true);
1103 exit(EXIT_FAILURE);
1104 }
1105
1106 /* Set a sane env, because we are setuid-root. */
1107 ret = clearenv();
1108 if (ret) {
1109 usernic_error("%s", "Failed to clear environment\n");
1110 exit(EXIT_FAILURE);
1111 }
1112
1113 ret = setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1);
1114 if (ret < 0) {
1115 usernic_error("%s", "Failed to set PATH, exiting\n");
1116 exit(EXIT_FAILURE);
1117 }
1118
1119 me = get_username();
1120 if (!me) {
1121 usernic_error("%s", "Failed to get username\n");
1122 exit(EXIT_FAILURE);
1123 }
1124
1125 if (request == LXC_USERNIC_CREATE) {
1126 ret = lxc_safe_int(args.pid, &pid);
1127 if (ret < 0) {
1128 usernic_error("Could not read pid: %s\n", args.pid);
1129 exit(EXIT_FAILURE);
1130 }
1131 } else if (request == LXC_USERNIC_DELETE) {
1132 netns_fd = open(args.pid, O_RDONLY);
1133 if (netns_fd < 0) {
1134 usernic_error("Could not open \"%s\": %s\n", args.pid,
1135 strerror(errno));
1136 exit(EXIT_FAILURE);
1137 }
1138 }
1139
1140 if (!create_db_dir(LXC_USERNIC_DB)) {
1141 usernic_error("%s", "Failed to create directory for db file\n");
1142 if (netns_fd >= 0)
1143 close(netns_fd);
1144 exit(EXIT_FAILURE);
1145 }
1146
1147 fd = open_and_lock(LXC_USERNIC_DB);
1148 if (fd < 0) {
1149 usernic_error("Failed to lock %s\n", LXC_USERNIC_DB);
1150 if (netns_fd >= 0)
1151 close(netns_fd);
1152 exit(EXIT_FAILURE);
1153 }
1154
1155 if (request == LXC_USERNIC_CREATE) {
1156 if (!may_access_netns(pid)) {
1157 usernic_error("User %s may not modify netns for pid %d\n", me, pid);
1158 exit(EXIT_FAILURE);
1159 }
1160 } else if (request == LXC_USERNIC_DELETE) {
1161 bool has_priv;
1162 has_priv = is_privileged_over_netns(netns_fd);
1163 close(netns_fd);
1164 if (!has_priv) {
1165 usernic_error("%s", "Process is not privileged over "
1166 "network namespace\n");
1167 exit(EXIT_FAILURE);
1168 }
1169 }
1170
1171 n = get_alloted(me, args.type, args.link, &alloted);
1172
1173 if (request == LXC_USERNIC_DELETE) {
1174 int ret;
1175 struct alloted_s *it;
1176 bool found_nicname = false;
1177
1178 if (!is_ovs_bridge(args.link)) {
1179 usernic_error("%s", "Deletion of non ovs type network "
1180 "devices not implemented\n");
1181 close(fd);
1182 free_alloted(&alloted);
1183 exit(EXIT_FAILURE);
1184 }
1185
1186 /* Check whether the network device we are supposed to delete
1187 * exists in the db. If it doesn't we will not delete it as we
1188 * need to assume the network device is not under our control.
1189 * As a side effect we also clear any invalid entries from the
1190 * database.
1191 */
1192 for (it = alloted; it; it = it->next)
1193 cull_entries(fd, it->name, args.type, args.link,
1194 args.veth_name, &found_nicname);
1195 close(fd);
1196 free_alloted(&alloted);
1197
1198 if (!found_nicname) {
1199 usernic_error("Caller is not allowed to delete network "
1200 "device \"%s\"\n", args.veth_name);
1201 exit(EXIT_FAILURE);
1202 }
1203
1204 ret = lxc_ovs_delete_port(args.link, args.veth_name);
1205 if (ret < 0) {
1206 usernic_error("Failed to remove port \"%s\" from "
1207 "openvswitch bridge \"%s\"",
1208 args.veth_name, args.link);
1209 exit(EXIT_FAILURE);
1210 }
1211
1212 exit(EXIT_SUCCESS);
1213 }
1214 if (n > 0)
1215 nicname = get_nic_if_avail(fd, alloted, pid, args.type,
1216 args.link, n, &cnic);
1217
1218 close(fd);
1219 free_alloted(&alloted);
1220 if (!nicname) {
1221 usernic_error("%s", "Quota reached\n");
1222 exit(EXIT_FAILURE);
1223 }
1224
1225 /* Now rename the link. */
1226 newname = lxc_secure_rename_in_ns(pid, cnic, args.veth_name,
1227 &container_veth_ifidx);
1228 if (!newname) {
1229 usernic_error("%s", "Failed to rename the link\n");
1230 ret = lxc_netdev_delete_by_name(cnic);
1231 if (ret < 0)
1232 usernic_error("Failed to delete \"%s\"\n", cnic);
1233 free(nicname);
1234 exit(EXIT_FAILURE);
1235 }
1236
1237 host_veth_ifidx = if_nametoindex(nicname);
1238 if (!host_veth_ifidx) {
1239 free(newname);
1240 free(nicname);
1241 usernic_error("Failed to get netdev index: %s\n", strerror(errno));
1242 exit(EXIT_FAILURE);
1243 }
1244
1245 /* Write names of veth pairs and their ifindeces to stout:
1246 * (e.g. eth0:731:veth9MT2L4:730)
1247 */
1248 fprintf(stdout, "%s:%d:%s:%d\n", newname, container_veth_ifidx, nicname,
1249 host_veth_ifidx);
1250 free(newname);
1251 free(nicname);
1252 exit(EXIT_SUCCESS);
1253 }