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
<refname>lxc-user-nic</refname>
<refpurpose>
Create and attach a nic to another network namespace.
Manage nics in another network namespace
</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<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>type</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>
</refsynopsisdiv>
......@@ -61,7 +75,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<para>
<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>
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
<filename>@LXC_USERNIC_DB@</filename>. It ensures that the calling
user is privileged over the network namespace to which the interface
will be attached.
<command>lxc-user-nic</command> also allows to delete network devices.
Currently only ovs ports can be deleted.
</para>
</refsect1>
......@@ -80,6 +97,27 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<title>Options</title>
<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>
<term>
......@@ -99,7 +137,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</term>
<listitem>
<para>
The network interface type to attach. Currently only veth is
The network interface type to attach. Currently only veth is
supported. With this type, two interfaces representing each
tunnel endpoint are created. One endpoint will be attached
to the specified bridge, while the other will be passed into
......@@ -122,16 +160,29 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<varlistentry>
<term>
<option><replaceable>nicname</replaceable></option>
<option><replaceable>container nicname</replaceable></option>
</term>
<listitem>
<para>
The desired interface name in the container. This will be
The desired interface name in the container. This will be
<filename>eth0</filename> if unspecified.
</para>
</listitem>
</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>
</refsect1>
......@@ -159,6 +210,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<refsect1>
<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>
</refsect1>
......
......@@ -47,6 +47,7 @@
#include <sys/types.h>
#include <unistd.h>
#include "compiler.h"
#include "config.h"
#include "log.h"
#include "memory_utils.h"
......@@ -69,13 +70,17 @@
#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} "
"{bridge} {nicname}\n", me);
fprintf(stderr, "Usage: %s delete {lxcpath} {name} "
"{/proc/<pid>/ns/net} {type} {bridge} {nicname}\n", me);
fprintf(stderr, "{nicname} is the name to use inside the container\n");
fprintf(stderr, "Description:\n");
fprintf(stderr, " Manage nics in another network namespace\n\n");
fprintf(stderr, "Usage:\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)
_exit(EXIT_FAILURE);
......@@ -83,9 +88,10 @@ static void usage(char *me, bool fail)
_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;
fd = open(path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR);
......@@ -102,11 +108,10 @@ static int open_and_lock(char *path)
ret = fcntl(fd, F_SETLKW, &lk);
if (ret < 0) {
CMD_SYSERROR("Failed to lock \"%s\"\n", path);
close(fd);
return -1;
}
return fd;
return move_fd(fd);
}
static char *get_username(void)
......@@ -881,16 +886,15 @@ static char *lxc_secure_rename_in_ns(int pid, char *oldname, char *newname,
close(fd);
fd = -1;
if (ret < 0) {
CMD_SYSERROR("Failed to setns() to the network namespace of "
"the container with PID %d\n", pid);
CMD_SYSERROR("Failed to setns() to the network namespace of the container with PID %d\n",
pid);
goto do_partial_cleanup;
}
ret = setresuid(ruid, ruid, 0);
if (ret < 0) {
CMD_SYSERROR("Failed to drop privilege by setting effective "
"user id and real user id to %d, and saved user "
"ID to 0\n", ruid);
CMD_SYSERROR("Failed to drop privilege by setting effective user id and real user id to %d, and saved user ID to 0\n",
ruid);
/* It's ok to jump to do_full_cleanup here since setresuid()
* will succeed when trying to set real, effective, and saved to
* values they currently have.
......@@ -936,18 +940,15 @@ static char *lxc_secure_rename_in_ns(int pid, char *oldname, char *newname,
do_full_cleanup:
ret = setresuid(ruid, euid, suid);
if (ret < 0) {
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", ruid, euid, suid);
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",
ruid, euid, suid);
string_ret = NULL;
}
ret = setns(ofd, CLONE_NEWNET);
if (ret < 0) {
CMD_SYSERROR("Failed to setns() to original network namespace "
"of PID %d\n", ofd);
CMD_SYSERROR("Failed to setns() to original network namespace of PID %d\n", ofd);
string_ret = NULL;
}
......@@ -981,9 +982,8 @@ static bool may_access_netns(int pid)
ret = setresuid(ruid, ruid, euid);
if (ret < 0) {
CMD_SYSERROR("Failed to drop privilege by setting effective "
"user id and real user id to %d, and saved user "
"ID to %d\n", ruid, euid);
CMD_SYSERROR("Failed to drop privilege by setting effective user id and real user id to %d, and saved user ID to %d\n",
ruid, euid);
return false;
}
......@@ -1000,8 +1000,8 @@ static bool may_access_netns(int pid)
ret = setresuid(ruid, euid, suid);
if (ret < 0) {
CMD_SYSERROR("Failed to restore user id to %d, real user id "
"to %d, and saved user ID to %d\n", ruid, euid, suid);
CMD_SYSERROR("Failed to restore user id to %d, real user id to %d, and saved user ID to %d\n",
ruid, euid, suid);
may_access = false;
}
......@@ -1018,8 +1018,10 @@ struct user_nic_args {
char *veth_name;
};
#define LXC_USERNIC_CREATE 0
#define LXC_USERNIC_DELETE 1
enum lxc_user_nic_command {
LXC_USERNIC_CREATE = 0,
LXC_USERNIC_DELETE = 1,
};
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);
if (ret < 0) {
CMD_SYSERROR("Failed to drop privilege by setting effective "
"user id and real user id to %d, and saved user "
"ID to 0\n", ruid);
CMD_SYSERROR("Failed to drop privilege by setting effective user id and real user id to %d, and saved user ID to 0\n",
ruid);
/* It's ok to jump to do_full_cleanup here since setresuid()
* will succeed when trying to set real, effective, and saved to
* values they currently have.
......@@ -1072,16 +1073,15 @@ static bool is_privileged_over_netns(int netns_fd)
do_full_cleanup:
ret = setresuid(ruid, euid, suid);
if (ret < 0) {
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", ruid, euid, suid);
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",
ruid, euid, suid);
bret = false;
}
ret = setns(ofd, CLONE_NEWNET);
if (ret < 0) {
CMD_SYSERROR("Failed to setns() to original network namespace "
"of PID %d\n", ofd);
CMD_SYSERROR("Failed to setns() to original network namespace of PID %d\n",
ofd);
bret = false;
}
......@@ -1090,6 +1090,18 @@ do_partial_cleanup:
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[])
{
__do_free char *me = NULL, *newname = NULL, *nicname = NULL;
......@@ -1099,10 +1111,8 @@ int main(int argc, char *argv[])
char *cnic = NULL;
struct alloted_s *alloted = NULL;
if (argc < 7 || argc > 8) {
usage(argv[0], true);
_exit(EXIT_FAILURE);
}
if (argc < 7 || argc > 8)
usage(true);
memset(&args, 0, sizeof(struct user_nic_args));
......@@ -1112,17 +1122,12 @@ int main(int argc, char *argv[])
args.pid = argv[4];
args.type = argv[5];
args.link = argv[6];
if (argc >= 8)
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);
}
request = validate_args(&args, argc);
if (request < 0)
usage(true);
/* Set a sane env, because we are setuid-root. */
ret = clearenv();
......@@ -1218,8 +1223,7 @@ int main(int argc, char *argv[])
has_priv = is_privileged_over_netns(netns_fd);
close(netns_fd);
if (!has_priv) {
usernic_error("%s", "Process is not privileged over "
"network namespace\n");
usernic_error("%s", "Process is not privileged over network namespace\n");
_exit(EXIT_FAILURE);
}
}
......@@ -1231,8 +1235,7 @@ int main(int argc, char *argv[])
bool found_nicname = false;
if (!is_ovs_bridge(args.link)) {
usernic_error("%s", "Deletion of non ovs type network "
"devices not implemented\n");
usernic_error("%s", "Deletion of non ovs type network devices not implemented\n");
close(fd);
free_alloted(&alloted);
_exit(EXIT_FAILURE);
......@@ -1251,16 +1254,13 @@ int main(int argc, char *argv[])
free_alloted(&alloted);
if (!found_nicname) {
usernic_error("Caller is not allowed to delete network "
"device \"%s\"\n", args.veth_name);
usernic_error("Caller is not allowed to delete network device \"%s\"\n", args.veth_name);
_exit(EXIT_FAILURE);
}
ret = lxc_ovs_delete_port(args.link, args.veth_name);
if (ret < 0) {
usernic_error("Failed to remove port \"%s\" from "
"openvswitch bridge \"%s\"",
args.veth_name, args.link);
usernic_error("Failed to remove port \"%s\" from openvswitch bridge \"%s\"", args.veth_name, args.link);
_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