[lxc-devel] [PATCH] make lxcapi_get_interfaces and lxcapi_get_ips unprivileged container aware
Stéphane Graber
stgraber at ubuntu.com
Wed Jan 22 02:44:16 UTC 2014
On Tue, Jan 21, 2014 at 09:36:06PM -0500, S.Çağlar Onur wrote:
> On Tue, Jan 21, 2014 at 6:41 PM, Serge Hallyn <serge.hallyn at ubuntu.com> wrote:
> > Quoting S.Çağlar Onur (caglar at 10ur.org):
> >> 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 <caglar at 10ur.org>
> >> Author: Stéphane Graber <stgraber at ubuntu.com>
> >> Signed-off-by: S.Çağlar Onur <caglar at 10ur.org>
> >
> > Thanks, looks good except for two issues below. With those fixed,
> >
> > Acked-by: Serge E. Hallyn <serge.hallyn at ubuntu.com>
>
> I believe Stéphane fixed them while pushing :)
I did indeed and also updated the ERROR messages to be a bit more
relevant (they were mentioning template creation).
>
> >> ---
> >> 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
> >> lxc-devel at lists.linuxcontainers.org
> >> http://lists.linuxcontainers.org/listinfo/lxc-devel
> > _______________________________________________
> > lxc-devel mailing list
> > lxc-devel at lists.linuxcontainers.org
> > http://lists.linuxcontainers.org/listinfo/lxc-devel
>
>
>
> --
> S.Çağlar Onur <caglar at 10ur.org>
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel
--
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20140121/7b3b8ebc/attachment-0001.pgp>
More information about the lxc-devel
mailing list