Skip to content

Commit

Permalink
lxc-user-nic: check db before trying to delete
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
  • Loading branch information
Christian Brauner committed Aug 28, 2017
1 parent af25697 commit 8b8e00a
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 26 deletions.
18 changes: 8 additions & 10 deletions src/lxc/conf.c
Expand Up @@ -3234,7 +3234,7 @@ bool lxc_delete_network(struct lxc_handler *handler)
if (am_unpriv()) {
if (is_ovs_bridge(netdev->link)) {
ret = lxc_unpriv_delete_nic(handler->lxcpath,
handler->name, "ovs",
handler->name,
netdev, getpid());
if (ret < 0)
WARN("Failed to remove port \"%s\" "
Expand Down Expand Up @@ -5143,12 +5143,11 @@ struct lxc_list *sort_cgroup_settings(struct lxc_list* cgroup_settings)
return result;
}

int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname, char *type,
int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname,
struct lxc_netdev *netdev, pid_t pid)
{
pid_t child;
int bytes, pipefd[2];
char netdev_link[IFNAMSIZ + 1];
char buffer[MAX_BUFFER_SIZE] = {0};

if (netdev->type != LXC_NET_VETH) {
Expand Down Expand Up @@ -5187,20 +5186,19 @@ int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname, char *type,
exit(EXIT_FAILURE);
}

if (netdev->link)
strncpy(netdev_link, netdev->link, IFNAMSIZ);
else
strncpy(netdev_link, "none", IFNAMSIZ);
if (!netdev->link)
SYSERROR("Network link for network device \"%s\" is "
"missing", netdev->priv.veth_attr.pair);

ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
if (ret < 0 || ret >= LXC_NUMSTRLEN64)
exit(EXIT_FAILURE);
pidstr[LXC_NUMSTRLEN64 - 1] = '\0';

INFO("Execing lxc-user-nic delete %s %s %s ovs %s %s", lxcpath,
lxcname, pidstr, netdev_link, netdev->priv.veth_attr.pair);
INFO("Execing lxc-user-nic delete %s %s %s veth %s %s", lxcpath,
lxcname, pidstr, netdev->link, netdev->priv.veth_attr.pair);
execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "delete", lxcpath,
lxcname, pidstr, "ovs", netdev_link,
lxcname, pidstr, "veth", netdev->link,
netdev->priv.veth_attr.pair, (char *)NULL);
SYSERROR("Failed to exec lxc-user-nic.");
exit(EXIT_FAILURE);
Expand Down
2 changes: 1 addition & 1 deletion src/lxc/conf.h
Expand Up @@ -500,7 +500,7 @@ extern FILE *make_anonymous_mount_file(struct lxc_list *mount);
extern struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings);
extern unsigned long add_required_remount_flags(const char *s, const char *d,
unsigned long flags);
extern int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname, char *type,
extern int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname,
struct lxc_netdev *netdev, pid_t pid);

#endif /* __LXC_CONF_H */
73 changes: 58 additions & 15 deletions src/lxc/lxc_user_nic.c
Expand Up @@ -572,19 +572,22 @@ struct entry_line {
bool keep;
};

static bool cull_entries(int fd, char *me, char *t, char *br)
static bool cull_entries(int fd, char *me, char *t, char *br, char *nicname,
bool *found_nicname)
{
int i, n = 0;
int i, ret;
off_t len;
char *buf, *p, *e, *nic;
char *buf, *e, *nic, *p;
struct stat sb;
int n = 0;
struct entry_line *entry_lines = NULL;

nic = alloca(100);
if (!nic)
return false;

if (fstat(fd, &sb) < 0) {
ret = fstat(fd, &sb);
if (ret < 0) {
usernic_error("Failed to fstat: %s\n", strerror(errno));
return false;
}
Expand All @@ -593,7 +596,7 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
if (len == 0)
return true;

buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
buf = lxc_strmmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (buf == MAP_FAILED) {
usernic_error("Failed to establish shared memory mapping: %s\n",
strerror(errno));
Expand Down Expand Up @@ -622,6 +625,10 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
if (nic && !nic_exists(nic))
entry_lines[n - 1].keep = false;

if (nicname)
if (!strcmp(nic, nicname))
*found_nicname = true;

p += entry_lines[n - 1].len + 1;
if (p >= e)
break;
Expand All @@ -639,8 +646,9 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
}
free(entry_lines);

munmap(buf, sb.st_size);
if (ftruncate(fd, p - buf))
lxc_strmunmap(buf, sb.st_size);
ret = ftruncate(fd, p - buf);
if (ret < 0)
usernic_error("Failed to set new file size: %s\n",
strerror(errno));

Expand Down Expand Up @@ -676,7 +684,7 @@ static char *get_nic_if_avail(int fd, struct alloted_s *names, int pid,
char *buf = NULL;

for (n = names; n != NULL; n = n->next)
cull_entries(fd, n->name, intype, br);
cull_entries(fd, n->name, intype, br, NULL, NULL);

if (allowed == 0)
return NULL;
Expand Down Expand Up @@ -965,9 +973,12 @@ struct user_nic_args {
char *veth_name;
};

#define LXC_USERNIC_CREATE 0
#define LXC_USERNIC_DELETE 1

int main(int argc, char *argv[])
{
int fd, ifindex, n, pid, ret;
int fd, ifindex, n, pid, request, ret;
char *me, *newname;
char *cnic = NULL, *nicname = NULL;
struct alloted_s *alloted = NULL;
Expand All @@ -988,6 +999,15 @@ int main(int argc, char *argv[])
if (argc >= 8)
args.veth_name = argv[7];

if (!strcmp(args.cmd, "create")) {
request = LXC_USERNIC_CREATE;
} else if (!strcmp(args.cmd, "delete")) {
request = LXC_USERNIC_DELETE;
} else {
usage(argv[0], true);
exit(EXIT_FAILURE);
}

/* Set a sane env, because we are setuid-root. */
ret = clearenv();
if (ret) {
Expand Down Expand Up @@ -1029,12 +1049,36 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}

if (!strcmp(args.cmd, "delete")) {
close(fd);
n = get_alloted(me, args.type, args.link, &alloted);

if (strcmp(args.type, "ovs")) {
if (request == LXC_USERNIC_DELETE) {
int ret;
struct alloted_s *it;
bool found_nicname = false;

if (!is_ovs_bridge(args.link)) {
usernic_error("%s", "Deletion of non ovs type network "
"devics not implemented\n");
"devices not implemented\n");
close(fd);
free_alloted(&alloted);
exit(EXIT_FAILURE);
}

/* Check whether the network device we are supposed to delete
* exists in the db. If it doesn't we will not delete it as we
* need to assume the network device is not under our control.
* As a side effect we also clear any invalid entries from the
* database.
*/
for (it = alloted; it; it = it->next)
cull_entries(fd, it->name, args.type, args.link,
args.veth_name, &found_nicname);
close(fd);
free_alloted(&alloted);

if (!found_nicname) {
usernic_error("%s", "Caller is not allowed to delete "
"network device\n");
exit(EXIT_FAILURE);
}

Expand All @@ -1045,10 +1089,9 @@ int main(int argc, char *argv[])
args.veth_name, args.link);
exit(EXIT_FAILURE);
}

exit(EXIT_SUCCESS);
}

n = get_alloted(me, args.type, args.link, &alloted);
if (n > 0)
nicname = get_nic_if_avail(fd, alloted, pid, args.type,
args.link, n, &cnic);
Expand Down

0 comments on commit 8b8e00a

Please sign in to comment.