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>
......@@ -122,7 +160,7 @@ 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>
......@@ -132,6 +170,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</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