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