aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2020-04-11 12:08:17 +0200
committerlaforge <laforge@osmocom.org>2020-04-14 17:15:52 +0000
commit8398bccb0b011f2440f63917f8789b216229427f (patch)
treefaa0b2649db191140398cd88d99231f2e9d1a83f
parent555287273392a71b555894c81920e3b6e28b8795 (diff)
lib/netns: Fix up error paths
The error handling in the code was doing exactly what one would not expect. If we switch to a netns and then encounter an error, we obviously have to switch back to the original netns before returning. Likewise, if we temporarily change the signal mask, we need to switch back to the original one before returning. Change-Id: I9ff5ae7bffc5bd7629dae0af1b72cfea548f9039
-rw-r--r--lib/netns.c74
1 files changed, 54 insertions, 20 deletions
diff --git a/lib/netns.c b/lib/netns.c
index 6e0e179..b16a42b 100644
--- a/lib/netns.c
+++ b/lib/netns.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014-2017, Travelping GmbH <info@travelping.com>
+ * Copyright (C) 2020, Harald Welte <laforge@gnumonks.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -65,8 +66,11 @@ int switch_ns(int nsfd, sigset_t *oldmask)
if ((rc = sigprocmask(SIG_BLOCK, &intmask, oldmask)) != 0)
return -rc;
- if (setns(nsfd, CLONE_NEWNET) < 0)
+ if (setns(nsfd, CLONE_NEWNET) < 0) {
+ /* restore old mask if we couldn't switch the netns */
+ sigprocmask(SIG_SETMASK, oldmask, NULL);
return -errno;
+ }
return 0;
}
@@ -90,7 +94,8 @@ int restore_ns(sigset_t *oldmask)
int open_ns(int nsfd, const char *pathname, int flags)
{
sigset_t intmask, oldmask;
- int fd;
+ int ret;
+ int fd = -1;
int rc;
OSMO_ASSERT(default_nsfd >= 0);
@@ -102,23 +107,34 @@ int open_ns(int nsfd, const char *pathname, int flags)
return -rc;
/* associate the calling thread with namespace file descriptor */
- if (setns(nsfd, CLONE_NEWNET) < 0)
- return -errno;
+ if (setns(nsfd, CLONE_NEWNET) < 0) {
+ ret = -errno;
+ goto restore_sigmask;
+ }
/* open the requested file/path */
- if ((fd = open(pathname, flags)) < 0)
- return -errno;
+ if ((fd = open(pathname, flags)) < 0) {
+ ret = -errno;
+ goto restore_defaultns;
+ }
+ ret = fd;
+
+restore_defaultns:
/* return back to default namespace */
if (setns(default_nsfd, CLONE_NEWNET) < 0) {
- close(fd);
+ if (fd >= 0)
+ close(fd);
return -errno;
}
+
+restore_sigmask:
/* restore process mask */
if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0) {
- close(fd);
+ if (fd >= 0)
+ close(fd);
return -rc;
}
- return fd;
+ return ret;
}
/*! create a socket in another namespace.
@@ -132,7 +148,8 @@ int open_ns(int nsfd, const char *pathname, int flags)
int socket_ns(int nsfd, int domain, int type, int protocol)
{
sigset_t intmask, oldmask;
- int sk;
+ int ret;
+ int sk = -1;
int rc;
OSMO_ASSERT(default_nsfd >= 0);
@@ -144,25 +161,34 @@ int socket_ns(int nsfd, int domain, int type, int protocol)
return -rc;
/* associate the calling thread with namespace file descriptor */
- if (setns(nsfd, CLONE_NEWNET) < 0)
- return -errno;
+ if (setns(nsfd, CLONE_NEWNET) < 0) {
+ ret = -errno;
+ goto restore_sigmask;
+ }
/* create socket of requested domain/type/proto */
- if ((sk = socket(domain, type, protocol)) < 0)
- return -errno;
+ if ((sk = socket(domain, type, protocol)) < 0) {
+ ret = -errno;
+ goto restore_defaultns;
+ }
+ ret = sk;
+restore_defaultns:
/* return back to default namespace */
if (setns(default_nsfd, CLONE_NEWNET) < 0) {
- close(sk);
+ if (sk >= 0)
+ close(sk);
return -errno;
}
+restore_sigmask:
/* restore process mask */
if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0) {
- close(sk);
+ if (sk >= 0)
+ close(sk);
return -rc;
}
- return sk;
+ return ret;
}
/*! initialize this network namespace helper module.
@@ -182,6 +208,7 @@ int init_netns()
* \returns File descriptor of network namespace; negative errno in case of error */
int get_nsfd(const char *name)
{
+ int ret = 0;
int rc;
int fd;
sigset_t intmask, oldmask;
@@ -215,19 +242,26 @@ int get_nsfd(const char *name)
return -rc;
/* create a new network namespace */
- if (unshare(CLONE_NEWNET) < 0)
- return -errno;
+ if (unshare(CLONE_NEWNET) < 0) {
+ ret = -errno;
+ goto restore_sigmask;
+ }
if (mount("/proc/self/ns/net", path, "none", MS_BIND, NULL) < 0)
- return -errno;
+ ret = -errno;
/* switch back to default namespace */
if (setns(default_nsfd, CLONE_NEWNET) < 0)
return -errno;
+restore_sigmask:
/* restore process mask */
if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0)
return -rc;
+ /* might have been set above in case mount fails */
+ if (ret < 0)
+ return ret;
+
/* finally, open the created namespace file descriptor from default ns */
if ((fd = open(path, O_RDONLY)) < 0)
return -errno;