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

Reply via email to