netns: Improve error checking

Change-Id: I9b9c8fd6eeaaa7d190b8e2a34ca82088904c7708
This commit is contained in:
Pau Espin 2020-02-25 12:17:29 +01:00
parent b629240a35
commit ad6eaa2881
3 changed files with 128 additions and 61 deletions

View File

@ -49,99 +49,133 @@ static int default_nsfd;
int switch_ns(int nsfd, sigset_t *oldmask)
{
sigset_t intmask;
int rc;
sigfillset(&intmask);
sigprocmask(SIG_BLOCK, &intmask, oldmask);
if (sigfillset(&intmask) < 0)
return -errno;
if ((rc = sigprocmask(SIG_BLOCK, &intmask, oldmask)) != 0)
return -rc;
return setns(nsfd, CLONE_NEWNET);
if (setns(nsfd, CLONE_NEWNET) < 0)
return -errno;
return 0;
}
void restore_ns(sigset_t *oldmask)
int restore_ns(sigset_t *oldmask)
{
setns(default_nsfd, CLONE_NEWNET);
int rc;
if (setns(default_nsfd, CLONE_NEWNET) < 0)
return -errno;
sigprocmask(SIG_SETMASK, oldmask, NULL);
if ((rc = sigprocmask(SIG_SETMASK, oldmask, NULL)) != 0)
return -rc;
return 0;
}
int open_ns(int nsfd, const char *pathname, int flags)
{
sigset_t intmask, oldmask;
int fd;
int errsv;
int rc;
sigfillset(&intmask);
sigprocmask(SIG_BLOCK, &intmask, &oldmask);
if (sigfillset(&intmask) < 0)
return -errno;
if ((rc = sigprocmask(SIG_BLOCK, &intmask, &oldmask)) != 0)
return -rc;
setns(nsfd, CLONE_NEWNET);
fd = open(pathname, flags);
errsv = errno;
setns(default_nsfd, CLONE_NEWNET);
if (setns(nsfd, CLONE_NEWNET) < 0)
return -errno;
if ((fd = open(pathname, flags)) < 0)
return -errno;
if (setns(default_nsfd, CLONE_NEWNET) < 0) {
close(fd);
return -errno;
}
if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0) {
close(fd);
return -rc;
}
sigprocmask(SIG_SETMASK, &oldmask, NULL);
errno = errsv;
return fd;
return 0;
}
int socket_ns(int nsfd, int domain, int type, int protocol)
{
sigset_t intmask, oldmask;
int sk;
int errsv;
int rc;
sigfillset(&intmask);
sigprocmask(SIG_BLOCK, &intmask, &oldmask);
if (sigfillset(&intmask) < 0)
return -errno;
if ((rc = sigprocmask(SIG_BLOCK, &intmask, &oldmask)) != 0)
return -rc;
setns(nsfd, CLONE_NEWNET);
sk = socket(domain, type, protocol);
errsv = errno;
setns(default_nsfd, CLONE_NEWNET);
if (setns(nsfd, CLONE_NEWNET) < 0)
return -errno;
if ((sk = socket(domain, type, protocol)) < 0)
return -errno;
if (setns(default_nsfd, CLONE_NEWNET) < 0) {
close(sk);
return -errno;
}
sigprocmask(SIG_SETMASK, &oldmask, NULL);
errno = errsv;
if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0) {
close(sk);
return -rc;
}
return sk;
}
void init_netns()
int init_netns()
{
if ((default_nsfd = open("/proc/self/ns/net", O_RDONLY)) < 0) {
perror("init_netns");
exit(EXIT_FAILURE);
}
if ((default_nsfd = open("/proc/self/ns/net", O_RDONLY)) < 0)
return -errno;
return 0;
}
int get_nsfd(const char *name)
{
int r;
int rc;
int fd;
sigset_t intmask, oldmask;
char path[MAXPATHLEN] = NETNS_PATH;
r = mkdir(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
if (r < 0 && errno != EEXIST)
return r;
rc = mkdir(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
if (rc < 0 && errno != EEXIST)
return rc;
snprintf(path, sizeof(path), "%s/%s", NETNS_PATH, name);
r = open(path, O_RDONLY|O_CREAT|O_EXCL, 0);
if (r < 0) {
if (errno == EEXIST)
return open(path, O_RDONLY);
return r;
fd = open(path, O_RDONLY|O_CREAT|O_EXCL, 0);
if (fd < 0) {
if (errno == EEXIST) {
if ((fd = open(path, O_RDONLY)) < 0)
return -errno;
return fd;
}
return -errno;
}
close(r);
if (close(fd) < 0)
return -errno;
sigfillset(&intmask);
sigprocmask(SIG_BLOCK, &intmask, &oldmask);
if (sigfillset(&intmask) < 0)
return -errno;
if ((rc = sigprocmask(SIG_BLOCK, &intmask, &oldmask)) != 0)
return -rc;
unshare(CLONE_NEWNET);
mount("/proc/self/ns/net", path, "none", MS_BIND, NULL);
if (unshare(CLONE_NEWNET) < 0)
return -errno;
if (mount("/proc/self/ns/net", path, "none", MS_BIND, NULL) < 0)
return -errno;
setns(default_nsfd, CLONE_NEWNET);
if (setns(default_nsfd, CLONE_NEWNET) < 0)
return -errno;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0)
return -rc;
return open(path, O_RDONLY);
if ((fd = open(path, O_RDONLY)) < 0)
return -errno;
return fd;
}
#endif

View File

@ -21,10 +21,10 @@
#if defined(__linux__)
void init_netns(void);
int init_netns(void);
int switch_ns(int nsfd, sigset_t *oldmask);
void restore_ns(sigset_t *oldmask);
int restore_ns(sigset_t *oldmask);
int open_ns(int nsfd, const char *pathname, int flags);
int socket_ns(int nsfd, int domain, int type, int protocol);

View File

@ -1323,19 +1323,29 @@ static int create_ping(void *gsn, struct pdp_t *pdp,
static int delete_context(struct pdp_t *pdp)
{
int rc;
if (tun && options.ipdown) {
#if defined(__linux__)
sigset_t oldmask;
if ((options.netns)) {
switch_ns(netns, &oldmask);
if ((rc = switch_ns(netns, &oldmask)) < 0) {
SYS_ERR(DSGSN, LOGL_ERROR, 0,
"Failed to switch to netns %s: %s\n",
options.netns, strerror(-rc));
}
}
#endif
tun_runscript(tun, options.ipdown);
#if defined(__linux__)
if ((options.netns)) {
restore_ns(&oldmask);
if ((rc = restore_ns(&oldmask)) < 0) {
SYS_ERR(DSGSN, LOGL_ERROR, 0,
"Failed to switch to original netns: %s\n",
strerror(-rc));
}
}
#endif
}
@ -1399,6 +1409,7 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
{
int rc;
struct in46_addr addr;
#if defined(__linux__)
sigset_t oldmask;
@ -1458,7 +1469,11 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
#if defined(__linux__)
if ((options.createif) && (options.netns)) {
switch_ns(netns, &oldmask);
if ((rc = switch_ns(netns, &oldmask)) < 0) {
SYS_ERR(DSGSN, LOGL_ERROR, 0,
"Failed to switch to netns %s: %s\n",
options.netns, strerror(-rc));
}
}
#endif
@ -1504,7 +1519,10 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
#if defined(__linux__)
if ((options.createif) && (options.netns)) {
restore_ns(&oldmask);
if ((rc = restore_ns(&oldmask)) < 0) {
SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to original netns: %s\n",
strerror(-rc));
}
}
#endif
@ -1572,7 +1590,7 @@ int main(int argc, char **argv)
fd_set fds; /* For select() */
struct timeval idleTime; /* How long to select() */
struct pdp_t *pdp;
int n;
int n, rc;
int starttime = time(NULL); /* Time program was started */
int stoptime = 0; /* Time to exit */
int pingtimeout = 0; /* Time to print ping statistics */
@ -1594,7 +1612,10 @@ int main(int argc, char **argv)
osmo_init_logging2(tall_sgsnemu_ctx, &log_info);
#if defined(__linux__)
init_netns();
if ((rc = init_netns()) < 0) {
SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to initialize netns: %s", strerror(-rc));
exit(1);
}
#endif
/* Process options given in configuration file and command line */
@ -1622,8 +1643,16 @@ int main(int argc, char **argv)
#if defined(__linux__)
if ((options.createif) && (options.netns)) {
netns = get_nsfd(options.netns);
switch_ns(netns, &oldmask);
if ((netns = get_nsfd(options.netns)) < 0) {
SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to obtain fd for netns %s: %s\n",
options.netns, strerror(-netns));
exit(1);
}
if ((rc = switch_ns(netns, &oldmask)) < 0) {
SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to netns %s: %s\n",
options.netns, strerror(-rc));
exit(1);
}
}
#endif
@ -1654,7 +1683,11 @@ int main(int argc, char **argv)
#if defined(__linux__)
if ((options.createif) && (options.netns)) {
restore_ns(&oldmask);
if ((rc = restore_ns(&oldmask)) < 0) {
SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to original netns: %s\n",
strerror(-rc));
exit(1);
}
}
#endif