Unverified Commit a38fa3d1 by Stéphane Graber Committed by GitHub

Merge pull request #2924 from brauner/2019-04-05/lxc_user_nice_update

lxc-user-nic: update
parents 4f34c6f9 ff63fd78
...@@ -42,17 +42,31 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -42,17 +42,31 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<refname>lxc-user-nic</refname> <refname>lxc-user-nic</refname>
<refpurpose> <refpurpose>
Create and attach a nic to another network namespace. Manage nics in another network namespace
</refpurpose> </refpurpose>
</refnamediv> </refnamediv>
<refsynopsisdiv> <refsynopsisdiv>
<cmdsynopsis> <cmdsynopsis>
<command>lxc-user-nic</command> <command>lxc-user-nic</command>
<command>create</command>
<arg choice="req"><replaceable>lxcpath</replaceable></arg>
<arg choice="req"><replaceable>name</replaceable></arg>
<arg choice="req"><replaceable>pid</replaceable></arg> <arg choice="req"><replaceable>pid</replaceable></arg>
<arg choice="req"><replaceable>type</replaceable></arg> <arg choice="req"><replaceable>type</replaceable></arg>
<arg choice="req"><replaceable>bridge</replaceable></arg> <arg choice="req"><replaceable>bridge</replaceable></arg>
<arg choice="opt"><replaceable>nicname</replaceable></arg> <arg choice="req"><replaceable>container nicname</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>lxc-user-nic</command>
<command>delete</command>
<arg choice="req"><replaceable>lxcpath</replaceable></arg>
<arg choice="req"><replaceable>name</replaceable></arg>
<arg choice="req"><replaceable>path to network namespace</replaceable></arg>
<arg choice="req"><replaceable>type</replaceable></arg>
<arg choice="req"><replaceable>bridge</replaceable></arg>
<arg choice="req"><replaceable>container nicname</replaceable></arg>
</cmdsynopsis> </cmdsynopsis>
</refsynopsisdiv> </refsynopsisdiv>
...@@ -61,7 +75,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -61,7 +75,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<para> <para>
<command>lxc-user-nic</command> is a setuid-root program with which <command>lxc-user-nic</command> is a setuid-root program with which
unprivileged users may create network interfaces for use by a lxc container. unprivileged users may manage network interfaces for use by a
lxc container.
</para> </para>
<para> <para>
It will consult the configuration file <filename>@LXC_USERNIC_CONF@</filename> It will consult the configuration file <filename>@LXC_USERNIC_CONF@</filename>
...@@ -71,6 +86,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -71,6 +86,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<filename>@LXC_USERNIC_DB@</filename>. It ensures that the calling <filename>@LXC_USERNIC_DB@</filename>. It ensures that the calling
user is privileged over the network namespace to which the interface user is privileged over the network namespace to which the interface
will be attached. will be attached.
<command>lxc-user-nic</command> also allows to delete network devices.
Currently only ovs ports can be deleted.
</para> </para>
</refsect1> </refsect1>
...@@ -80,6 +97,27 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -80,6 +97,27 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<title>Options</title> <title>Options</title>
<variablelist> <variablelist>
<varlistentry>
<term>
<option><replaceable>lxcpath</replaceable></option>
</term>
<listitem>
<para>
The path of the container. This is currently not used.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option><replaceable>name</replaceable></option>
</term>
<listitem>
<para>
The name of the container. This is currently not used.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term> <term>
...@@ -122,7 +160,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -122,7 +160,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<varlistentry> <varlistentry>
<term> <term>
<option><replaceable>nicname</replaceable></option> <option><replaceable>container nicname</replaceable></option>
</term> </term>
<listitem> <listitem>
<para> <para>
...@@ -132,6 +170,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -132,6 +170,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<option><replaceable>path to network namespace</replaceable></option>
</term>
<listitem>
<para>
A path to open to get a file descriptor for the target
network namespace.
This is only relevant when an veth device is deleted.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
...@@ -159,6 +210,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -159,6 +210,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<refsect1> <refsect1>
<title>Author</title> <title>Author</title>
<para>Christian Brauner <email>christian@brauner.io</email></para>
<para>Serge Hallyn <email>serge@hallyn.com</email></para>
<para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para> <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
</refsect1> </refsect1>
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "compiler.h"
#include "config.h" #include "config.h"
#include "log.h" #include "log.h"
#include "memory_utils.h" #include "memory_utils.h"
...@@ -69,13 +70,17 @@ ...@@ -69,13 +70,17 @@
#define usernic_error(format, ...) usernic_debug_stream(stderr, format, __VA_ARGS__) #define usernic_error(format, ...) usernic_debug_stream(stderr, format, __VA_ARGS__)
static void usage(char *me, bool fail) __noreturn static void usage(bool fail)
{ {
fprintf(stderr, "Usage: %s create {lxcpath} {name} {pid} {type} " fprintf(stderr, "Description:\n");
"{bridge} {nicname}\n", me); fprintf(stderr, " Manage nics in another network namespace\n\n");
fprintf(stderr, "Usage: %s delete {lxcpath} {name} "
"{/proc/<pid>/ns/net} {type} {bridge} {nicname}\n", me); fprintf(stderr, "Usage:\n");
fprintf(stderr, "{nicname} is the name to use inside the container\n"); fprintf(stderr, " lxc-user-nic [command]\n\n");
fprintf(stderr, "Available Commands:\n");
fprintf(stderr, " create {lxcpath} {name} {pid} {type} {bridge} {container nicname}\n");
fprintf(stderr, " delete {lxcpath} {name} {/proc/<pid>/ns/net} {type} {bridge} {container nicname}\n");
if (fail) if (fail)
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
...@@ -83,9 +88,10 @@ static void usage(char *me, bool fail) ...@@ -83,9 +88,10 @@ static void usage(char *me, bool fail)
_exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
} }
static int open_and_lock(char *path) static int open_and_lock(const char *path)
{ {
int fd, ret; __do_close_prot_errno int fd = -EBADF;
int ret;
struct flock lk; struct flock lk;
fd = open(path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR); fd = open(path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR);
...@@ -102,11 +108,10 @@ static int open_and_lock(char *path) ...@@ -102,11 +108,10 @@ static int open_and_lock(char *path)
ret = fcntl(fd, F_SETLKW, &lk); ret = fcntl(fd, F_SETLKW, &lk);
if (ret < 0) { if (ret < 0) {
CMD_SYSERROR("Failed to lock \"%s\"\n", path); CMD_SYSERROR("Failed to lock \"%s\"\n", path);
close(fd);
return -1; return -1;
} }
return fd; return move_fd(fd);
} }
static char *get_username(void) static char *get_username(void)
...@@ -881,16 +886,15 @@ static char *lxc_secure_rename_in_ns(int pid, char *oldname, char *newname, ...@@ -881,16 +886,15 @@ static char *lxc_secure_rename_in_ns(int pid, char *oldname, char *newname,
close(fd); close(fd);
fd = -1; fd = -1;
if (ret < 0) { if (ret < 0) {
CMD_SYSERROR("Failed to setns() to the network namespace of " CMD_SYSERROR("Failed to setns() to the network namespace of the container with PID %d\n",
"the container with PID %d\n", pid); pid);
goto do_partial_cleanup; goto do_partial_cleanup;
} }
ret = setresuid(ruid, ruid, 0); ret = setresuid(ruid, ruid, 0);
if (ret < 0) { if (ret < 0) {
CMD_SYSERROR("Failed to drop privilege by setting effective " CMD_SYSERROR("Failed to drop privilege by setting effective user id and real user id to %d, and saved user ID to 0\n",
"user id and real user id to %d, and saved user " ruid);
"ID to 0\n", ruid);
/* It's ok to jump to do_full_cleanup here since setresuid() /* It's ok to jump to do_full_cleanup here since setresuid()
* will succeed when trying to set real, effective, and saved to * will succeed when trying to set real, effective, and saved to
* values they currently have. * values they currently have.
...@@ -936,18 +940,15 @@ static char *lxc_secure_rename_in_ns(int pid, char *oldname, char *newname, ...@@ -936,18 +940,15 @@ static char *lxc_secure_rename_in_ns(int pid, char *oldname, char *newname,
do_full_cleanup: do_full_cleanup:
ret = setresuid(ruid, euid, suid); ret = setresuid(ruid, euid, suid);
if (ret < 0) { if (ret < 0) {
CMD_SYSERROR("Failed to restore privilege by setting " CMD_SYSERROR("Failed to restore privilege by setting effective user id to %d, real user id to %d, and saved user ID to %d\n",
"effective user id to %d, real user id to %d, " ruid, euid, suid);
"and saved user ID to %d\n", ruid, euid, suid);
string_ret = NULL; string_ret = NULL;
} }
ret = setns(ofd, CLONE_NEWNET); ret = setns(ofd, CLONE_NEWNET);
if (ret < 0) { if (ret < 0) {
CMD_SYSERROR("Failed to setns() to original network namespace " CMD_SYSERROR("Failed to setns() to original network namespace of PID %d\n", ofd);
"of PID %d\n", ofd);
string_ret = NULL; string_ret = NULL;
} }
...@@ -981,9 +982,8 @@ static bool may_access_netns(int pid) ...@@ -981,9 +982,8 @@ static bool may_access_netns(int pid)
ret = setresuid(ruid, ruid, euid); ret = setresuid(ruid, ruid, euid);
if (ret < 0) { if (ret < 0) {
CMD_SYSERROR("Failed to drop privilege by setting effective " CMD_SYSERROR("Failed to drop privilege by setting effective user id and real user id to %d, and saved user ID to %d\n",
"user id and real user id to %d, and saved user " ruid, euid);
"ID to %d\n", ruid, euid);
return false; return false;
} }
...@@ -1000,8 +1000,8 @@ static bool may_access_netns(int pid) ...@@ -1000,8 +1000,8 @@ static bool may_access_netns(int pid)
ret = setresuid(ruid, euid, suid); ret = setresuid(ruid, euid, suid);
if (ret < 0) { if (ret < 0) {
CMD_SYSERROR("Failed to restore user id to %d, real user id " CMD_SYSERROR("Failed to restore user id to %d, real user id to %d, and saved user ID to %d\n",
"to %d, and saved user ID to %d\n", ruid, euid, suid); ruid, euid, suid);
may_access = false; may_access = false;
} }
...@@ -1018,8 +1018,10 @@ struct user_nic_args { ...@@ -1018,8 +1018,10 @@ struct user_nic_args {
char *veth_name; char *veth_name;
}; };
#define LXC_USERNIC_CREATE 0 enum lxc_user_nic_command {
#define LXC_USERNIC_DELETE 1 LXC_USERNIC_CREATE = 0,
LXC_USERNIC_DELETE = 1,
};
static bool is_privileged_over_netns(int netns_fd) static bool is_privileged_over_netns(int netns_fd)
{ {
...@@ -1050,9 +1052,8 @@ static bool is_privileged_over_netns(int netns_fd) ...@@ -1050,9 +1052,8 @@ static bool is_privileged_over_netns(int netns_fd)
ret = setresuid(ruid, ruid, 0); ret = setresuid(ruid, ruid, 0);
if (ret < 0) { if (ret < 0) {
CMD_SYSERROR("Failed to drop privilege by setting effective " CMD_SYSERROR("Failed to drop privilege by setting effective user id and real user id to %d, and saved user ID to 0\n",
"user id and real user id to %d, and saved user " ruid);
"ID to 0\n", ruid);
/* It's ok to jump to do_full_cleanup here since setresuid() /* It's ok to jump to do_full_cleanup here since setresuid()
* will succeed when trying to set real, effective, and saved to * will succeed when trying to set real, effective, and saved to
* values they currently have. * values they currently have.
...@@ -1072,16 +1073,15 @@ static bool is_privileged_over_netns(int netns_fd) ...@@ -1072,16 +1073,15 @@ static bool is_privileged_over_netns(int netns_fd)
do_full_cleanup: do_full_cleanup:
ret = setresuid(ruid, euid, suid); ret = setresuid(ruid, euid, suid);
if (ret < 0) { if (ret < 0) {
CMD_SYSERROR("Failed to restore privilege by setting " CMD_SYSERROR("Failed to restore privilege by setting effective user id to %d, real user id to %d, and saved user ID to %d\n",
"effective user id to %d, real user id to %d, " ruid, euid, suid);
"and saved user ID to %d\n", ruid, euid, suid);
bret = false; bret = false;
} }
ret = setns(ofd, CLONE_NEWNET); ret = setns(ofd, CLONE_NEWNET);
if (ret < 0) { if (ret < 0) {
CMD_SYSERROR("Failed to setns() to original network namespace " CMD_SYSERROR("Failed to setns() to original network namespace of PID %d\n",
"of PID %d\n", ofd); ofd);
bret = false; bret = false;
} }
...@@ -1090,6 +1090,18 @@ do_partial_cleanup: ...@@ -1090,6 +1090,18 @@ do_partial_cleanup:
return bret; return bret;
} }
static inline int validate_args(const struct user_nic_args *args, int argc)
{
int request = -EINVAL;
if (!strcmp(args->cmd, "create"))
request = LXC_USERNIC_CREATE;
else if (!strcmp(args->cmd, "delete"))
request = LXC_USERNIC_DELETE;
return request;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
__do_free char *me = NULL, *newname = NULL, *nicname = NULL; __do_free char *me = NULL, *newname = NULL, *nicname = NULL;
...@@ -1099,10 +1111,8 @@ int main(int argc, char *argv[]) ...@@ -1099,10 +1111,8 @@ int main(int argc, char *argv[])
char *cnic = NULL; char *cnic = NULL;
struct alloted_s *alloted = NULL; struct alloted_s *alloted = NULL;
if (argc < 7 || argc > 8) { if (argc < 7 || argc > 8)
usage(argv[0], true); usage(true);
_exit(EXIT_FAILURE);
}
memset(&args, 0, sizeof(struct user_nic_args)); memset(&args, 0, sizeof(struct user_nic_args));
...@@ -1112,17 +1122,12 @@ int main(int argc, char *argv[]) ...@@ -1112,17 +1122,12 @@ int main(int argc, char *argv[])
args.pid = argv[4]; args.pid = argv[4];
args.type = argv[5]; args.type = argv[5];
args.link = argv[6]; args.link = argv[6];
if (argc >= 8) if (argc == 8)
args.veth_name = argv[7]; args.veth_name = argv[7];
if (!strcmp(args.cmd, "create")) { request = validate_args(&args, argc);
request = LXC_USERNIC_CREATE; if (request < 0)
} else if (!strcmp(args.cmd, "delete")) { usage(true);
request = LXC_USERNIC_DELETE;
} else {
usage(argv[0], true);
_exit(EXIT_FAILURE);
}
/* Set a sane env, because we are setuid-root. */ /* Set a sane env, because we are setuid-root. */
ret = clearenv(); ret = clearenv();
...@@ -1218,8 +1223,7 @@ int main(int argc, char *argv[]) ...@@ -1218,8 +1223,7 @@ int main(int argc, char *argv[])
has_priv = is_privileged_over_netns(netns_fd); has_priv = is_privileged_over_netns(netns_fd);
close(netns_fd); close(netns_fd);
if (!has_priv) { if (!has_priv) {
usernic_error("%s", "Process is not privileged over " usernic_error("%s", "Process is not privileged over network namespace\n");
"network namespace\n");
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
} }
...@@ -1231,8 +1235,7 @@ int main(int argc, char *argv[]) ...@@ -1231,8 +1235,7 @@ int main(int argc, char *argv[])
bool found_nicname = false; bool found_nicname = false;
if (!is_ovs_bridge(args.link)) { if (!is_ovs_bridge(args.link)) {
usernic_error("%s", "Deletion of non ovs type network " usernic_error("%s", "Deletion of non ovs type network devices not implemented\n");
"devices not implemented\n");
close(fd); close(fd);
free_alloted(&alloted); free_alloted(&alloted);
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
...@@ -1251,16 +1254,13 @@ int main(int argc, char *argv[]) ...@@ -1251,16 +1254,13 @@ int main(int argc, char *argv[])
free_alloted(&alloted); free_alloted(&alloted);
if (!found_nicname) { if (!found_nicname) {
usernic_error("Caller is not allowed to delete network " usernic_error("Caller is not allowed to delete network device \"%s\"\n", args.veth_name);
"device \"%s\"\n", args.veth_name);
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
ret = lxc_ovs_delete_port(args.link, args.veth_name); ret = lxc_ovs_delete_port(args.link, args.veth_name);
if (ret < 0) { if (ret < 0) {
usernic_error("Failed to remove port \"%s\" from " usernic_error("Failed to remove port \"%s\" from openvswitch bridge \"%s\"", args.veth_name, args.link);
"openvswitch bridge \"%s\"",
args.veth_name, args.link);
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment