Quoting S.Çağlar Onur ([email protected]): > Based on Stéphane's suggestion, those two API methods now; > > * fork a new process, > * switch to appropriate namespace(s), > * do what we want, > * return the data over a pipe to the parent which returns the result to the > original caller. > > For the whole thread please see; > > > https://lists.linuxcontainers.org/pipermail/lxc-devel/2014-January/007362.html > > This patch also makes lxc-ls and lxc-info call those functions. > > I'm adding Stéphane as an author here since both the idea as well as > the initial setns code come from him. > > Author: S.Çağlar Onur <[email protected]> > Author: Stéphane Graber <[email protected]> > Signed-off-by: S.Çağlar Onur <[email protected]>
Thanks, looks good except for two issues below. With those fixed, Acked-by: Serge E. Hallyn <[email protected]> > --- > src/lxc/lxc-ls | 2 +- > src/lxc/lxc_info.c | 20 ++-- > src/lxc/lxccontainer.c | 276 > +++++++++++++++++++++++++++++++------------------ > 3 files changed, 182 insertions(+), 116 deletions(-) > > diff --git a/src/lxc/lxc-ls b/src/lxc/lxc-ls > index 68c0b41..fa53fac 100755 > --- a/src/lxc/lxc-ls > +++ b/src/lxc/lxc-ls > @@ -265,7 +265,7 @@ for container_name in > lxc.list_containers(config_path=nest_lxcpath): > > # FIXME: We should get get_ips working as non-root > if container.running: > - if not SUPPORT_SETNS_NET or os.geteuid() != 0: > + if not SUPPORT_SETNS_NET: > entry[protocol] = 'UNKNOWN' > continue > > diff --git a/src/lxc/lxc_info.c b/src/lxc/lxc_info.c > index 0990036..b515087 100644 > --- a/src/lxc/lxc_info.c > +++ b/src/lxc/lxc_info.c > @@ -310,19 +310,15 @@ static int print_info(const char *name, const char > *lxcpath) > } > > if (ips) { > - if (geteuid() == 0) { > - char **addresses = c->get_ips(c, NULL, NULL, 0); > - if (addresses) { > - char *address; > - i = 0; > - while (addresses[i]) { > - address = addresses[i]; > - print_info_msg_str("IP:", address); > - i++; > - } > + char **addresses = c->get_ips(c, NULL, NULL, 0); > + if (addresses) { > + char *address; > + i = 0; > + while (addresses[i]) { > + address = addresses[i]; > + print_info_msg_str("IP:", address); > + i++; > } > - } else { > - print_info_msg_str("IP:", "UNKNOWN"); > } > } > > diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c > index 368cb46..1336a3d 100644 > --- a/src/lxc/lxccontainer.c > +++ b/src/lxc/lxccontainer.c > @@ -1372,48 +1372,51 @@ static bool lxcapi_clear_config_item(struct > lxc_container *c, const char *key) > return ret == 0; > } > > -static inline void exit_from_ns(struct lxc_container *c, int *old_netns, int > *new_netns) { > - /* Switch back to original netns */ > - if (*old_netns >= 0 && setns(*old_netns, CLONE_NEWNET)) > - SYSERROR("failed to setns"); > - if (*new_netns >= 0) > - close(*new_netns); > - if (*old_netns >= 0) > - close(*old_netns); > -} > - > -static inline bool enter_to_ns(struct lxc_container *c, int *old_netns, int > *new_netns) { > - int ret = 0; > +static inline bool enter_to_ns(struct lxc_container *c) { > + int netns, userns, ret = 0, init_pid = 0;; > char new_netns_path[MAXPATHLEN]; > + char new_userns_path[MAXPATHLEN]; > > if (!c->is_running(c)) > goto out; > > - /* Save reference to old netns */ > - *old_netns = open("/proc/self/ns/net", O_RDONLY); > - if (*old_netns < 0) { > - SYSERROR("failed to open /proc/self/ns/net"); > - goto out; > + init_pid = c->init_pid(c); > + > + /* Switch to new userns */ > + if (geteuid() && access("/proc/self/ns/user", F_OK) == 0) { > + ret = snprintf(new_userns_path, MAXPATHLEN, "/proc/%d/ns/user", > init_pid); > + if (ret < 0 || ret >= MAXPATHLEN) > + goto out; > + > + userns = open(new_userns_path, O_RDONLY); > + if (userns < 0) { > + SYSERROR("failed to open %s", new_userns_path); > + goto out; > + } > + > + if (setns(userns, CLONE_NEWUSER)) { > + SYSERROR("failed to setns for CLONE_NEWUSER"); > + goto out; > + } > } > > /* Switch to new netns */ > - ret = snprintf(new_netns_path, MAXPATHLEN, "/proc/%d/ns/net", > c->init_pid(c)); > + ret = snprintf(new_netns_path, MAXPATHLEN, "/proc/%d/ns/net", init_pid); > if (ret < 0 || ret >= MAXPATHLEN) > goto out; > > - *new_netns = open(new_netns_path, O_RDONLY); > - if (*new_netns < 0) { > + netns = open(new_netns_path, O_RDONLY); > + if (netns < 0) { > SYSERROR("failed to open %s", new_netns_path); > goto out; > } > > - if (setns(*new_netns, CLONE_NEWNET)) { > - SYSERROR("failed to setns"); > + if (setns(netns, CLONE_NEWNET)) { > + SYSERROR("failed to setns for CLONE_NEWNET"); > goto out; > } > return true; > out: > - exit_from_ns(c, old_netns, new_netns); > return false; > } > > @@ -1490,135 +1493,202 @@ static bool remove_from_array(char ***names, char > *cname, int size) > > static char** lxcapi_get_interfaces(struct lxc_container *c) > { > - int i, count = 0; > - struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL; > + pid_t pid; > + int i, count = 0, pipefd[2]; > char **interfaces = NULL; > - int old_netns = -1, new_netns = -1; > + char interface[IFNAMSIZ]; > > - if (am_unpriv()) { > - ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__); > - goto out; > + if(pipe(pipefd) < 0) { > + SYSERROR("pipe failed"); > + return NULL; > } > > - if (!enter_to_ns(c, &old_netns, &new_netns)) > - goto out; > + pid = fork(); > + if (pid < 0) { > + SYSERROR("failed to fork task for container creation > template\n"); pipefds should be closed here > + return NULL; > + } > > - /* Grab the list of interfaces */ > - if (getifaddrs(&interfaceArray)) { > - SYSERROR("failed to get interfaces list"); > - goto out; > + if (pid == 0) { // child > + int ret = 1, nbytes; > + struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL; > + > + /* close the read-end of the pipe */ > + close(pipefd[0]); > + > + if (!enter_to_ns(c)) { > + SYSERROR("failed to enter namespace"); > + goto out; > + } > + > + /* Grab the list of interfaces */ > + if (getifaddrs(&interfaceArray)) { > + SYSERROR("failed to get interfaces list"); > + goto out; > + } > + > + /* Iterate through the interfaces */ > + for (tempIfAddr = interfaceArray; tempIfAddr != NULL; > tempIfAddr = tempIfAddr->ifa_next) { > + nbytes = write(pipefd[1], tempIfAddr->ifa_name, > IFNAMSIZ); > + if (nbytes < 0) { > + ERROR("write failed"); > + goto out; > + } > + count++; > + } > + ret = 0; > + > + out: > + if (interfaceArray) > + freeifaddrs(interfaceArray); > + > + /* close the write-end of the pipe, thus sending EOF to the > reader */ > + close(pipefd[1]); > + exit(ret); > } > > - /* Iterate through the interfaces */ > - for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = > tempIfAddr->ifa_next) { > - if (array_contains(&interfaces, tempIfAddr->ifa_name, count)) > - continue; > + /* close the write-end of the pipe */ > + close(pipefd[1]); > > - if(!add_to_array(&interfaces, tempIfAddr->ifa_name, count)) > - goto err; > + while (read(pipefd[0], &interface, IFNAMSIZ) > 0) { > + if (array_contains(&interfaces, interface, count)) > + continue; > + > + if(!add_to_array(&interfaces, interface, count)) > + ERROR("PARENT: add_to_array failed"); > count++; > } > > -out: > - if (interfaceArray) > - freeifaddrs(interfaceArray); > + if (wait_for_pid(pid) != 0) { > + for(i=0;i<count;i++) > + free(interfaces[i]); > + free(interfaces); > + interfaces = NULL; > + } > > - exit_from_ns(c, &old_netns, &new_netns); > + /* close the read-end of the pipe */ > + close(pipefd[0]); > > /* Append NULL to the array */ > if(interfaces) > interfaces = (char **)lxc_append_null_to_array((void > **)interfaces, count); > > return interfaces; > - > -err: > - for(i=0;i<count;i++) > - free(interfaces[i]); > - free(interfaces); > - interfaces = NULL; > - goto out; > } > > static char** lxcapi_get_ips(struct lxc_container *c, const char* interface, > const char* family, int scope) > { > - int i, count = 0; > - struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL; > - char addressOutputBuffer[INET6_ADDRSTRLEN]; > - void *tempAddrPtr = NULL; > + pid_t pid; > + int i, count = 0, pipefd[2]; > char **addresses = NULL; > - char *address = NULL; > - int old_netns = -1, new_netns = -1; > + char address[INET6_ADDRSTRLEN]; > > - if (am_unpriv()) { > - ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__); > - goto out; > + if(pipe(pipefd) < 0) { > + SYSERROR("pipe failed"); > + return NULL; > } > > - if (!enter_to_ns(c, &old_netns, &new_netns)) > - goto out; > - > - /* Grab the list of interfaces */ > - if (getifaddrs(&interfaceArray)) { > - SYSERROR("failed to get interfaces list"); > - goto out; > + pid = fork(); > + if (pid < 0) { > + SYSERROR("failed to fork task for container creation > template\n"); and here > + return NULL; > } > > - /* Iterate through the interfaces */ > - for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = > tempIfAddr->ifa_next) { > - if (tempIfAddr->ifa_addr == NULL) > - continue; > + if (pid == 0) { // child > + int ret = 1, nbytes; > + struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL; > + char addressOutputBuffer[INET6_ADDRSTRLEN]; > + void *tempAddrPtr = NULL; > + char *address = NULL; > > - if(tempIfAddr->ifa_addr->sa_family == AF_INET) { > - if (family && strcmp(family, "inet")) > - continue; > - tempAddrPtr = &((struct sockaddr_in > *)tempIfAddr->ifa_addr)->sin_addr; > + /* close the read-end of the pipe */ > + close(pipefd[0]); > + > + if (!enter_to_ns(c)) { > + SYSERROR("failed to enter namespace"); > + goto out; > + } > + > + /* Grab the list of interfaces */ > + if (getifaddrs(&interfaceArray)) { > + SYSERROR("failed to get interfaces list"); > + goto out; > } > - else { > - if (family && strcmp(family, "inet6")) > + > + /* Iterate through the interfaces */ > + for (tempIfAddr = interfaceArray; tempIfAddr != NULL; > tempIfAddr = tempIfAddr->ifa_next) { > + if (tempIfAddr->ifa_addr == NULL) > continue; > > - if (((struct sockaddr_in6 > *)tempIfAddr->ifa_addr)->sin6_scope_id != scope) > + if(tempIfAddr->ifa_addr->sa_family == AF_INET) { > + if (family && strcmp(family, "inet")) > + continue; > + tempAddrPtr = &((struct sockaddr_in > *)tempIfAddr->ifa_addr)->sin_addr; > + } > + else { > + if (family && strcmp(family, "inet6")) > + continue; > + > + if (((struct sockaddr_in6 > *)tempIfAddr->ifa_addr)->sin6_scope_id != scope) > + continue; > + > + tempAddrPtr = &((struct sockaddr_in6 > *)tempIfAddr->ifa_addr)->sin6_addr; > + } > + > + if (interface && strcmp(interface, > tempIfAddr->ifa_name)) > continue; > + else if (!interface && strcmp("lo", > tempIfAddr->ifa_name) == 0) > + continue; > + > + address = (char > *)inet_ntop(tempIfAddr->ifa_addr->sa_family, > + tempAddrPtr, > + addressOutputBuffer, > + sizeof(addressOutputBuffer)); > + if (!address) > + continue; > > - tempAddrPtr = &((struct sockaddr_in6 > *)tempIfAddr->ifa_addr)->sin6_addr; > + nbytes = write(pipefd[1], address, INET6_ADDRSTRLEN); > + if (nbytes < 0) { > + ERROR("write failed"); > + goto out; > + } > + count++; > } > + ret = 0; > > - if (interface && strcmp(interface, tempIfAddr->ifa_name)) > - continue; > - else if (!interface && strcmp("lo", tempIfAddr->ifa_name) == 0) > - continue; > + out: > + if(interfaceArray) > + freeifaddrs(interfaceArray); > > - address = (char *)inet_ntop(tempIfAddr->ifa_addr->sa_family, > - tempAddrPtr, > - addressOutputBuffer, > - sizeof(addressOutputBuffer)); > - if (!address) > - continue; > + /* close the write-end of the pipe, thus sending EOF to the > reader */ > + close(pipefd[1]); > + exit(ret); > + } > + > + /* close the write-end of the pipe */ > + close(pipefd[1]); > > + while (read(pipefd[0], &address, INET6_ADDRSTRLEN) > 0) { > if(!add_to_array(&addresses, address, count)) > - goto err; > + ERROR("PARENT: add_to_array failed"); > count++; > } > > -out: > - if(interfaceArray) > - freeifaddrs(interfaceArray); > + if (wait_for_pid(pid) != 0) { > + for(i=0;i<count;i++) > + free(addresses[i]); > + free(addresses); > + addresses = NULL; > + } > > - exit_from_ns(c, &old_netns, &new_netns); > + /* close the read-end of the pipe */ > + close(pipefd[0]); > > /* Append NULL to the array */ > if(addresses) > addresses = (char **)lxc_append_null_to_array((void > **)addresses, count); > > return addresses; > - > -err: > - for(i=0;i<count;i++) > - free(addresses[i]); > - free(addresses); > - addresses = NULL; > - > - goto out; > } > > static int lxcapi_get_config_item(struct lxc_container *c, const char *key, > char *retv, int inlen) > -- > 1.8.3.2 > > _______________________________________________ > lxc-devel mailing list > [email protected] > http://lists.linuxcontainers.org/listinfo/lxc-devel _______________________________________________ lxc-devel mailing list [email protected] http://lists.linuxcontainers.org/listinfo/lxc-devel
