Accessing multipathd's socket from a different network namespace (e.g. from a container) is impossible with an abstract socket. Add the option to compile multipathd using a regular Unix socket instead, by compiling with the flag "use_regular_socket=1". By default, the socket path is /run/multipathd. [1] https://github.com/opensvc/multipath-tools/issues/111 Signed-off-by: Martin Wilck <mwilck@xxxxxxxx> --- .gitignore | 1 + Makefile.inc | 9 ++++++-- README.md | 4 ++++ libmpathcmd/mpath_cmd.c | 5 +++-- libmpathutil/uxsock.c | 21 ++++++++++++++++--- multipathd/Makefile | 6 +++--- ...multipathd.socket => multipathd.socket.in} | 2 +- 7 files changed, 37 insertions(+), 11 deletions(-) rename multipathd/{multipathd.socket => multipathd.socket.in} (87%) diff --git a/.gitignore b/.gitignore index 4548cfb..6a1f6fc 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ multipathd/multipathd multipathd/multipathd.8 multipathd/multipathc multipathd/multipathd.service +multipathd/multipathd.socket mpathpersist/mpathpersist mpathpersist/mpathpersist.8 abi.tar.gz diff --git a/Makefile.inc b/Makefile.inc index 949e7b5..104aeaf 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -79,8 +79,11 @@ libudev_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir libudev),/usr kernel_incdir := /usr/include sysdir_bin := $(sys_execprefix)bin +use_regular_socket := +regular_socket_path := /run/multipathd.socket abstract_socket_path := /org/kernel/linux/storage/multipathd -mpath_socket := $(abstract_socket_path) +mpath_socket := $(if $(use_regular_socket),$(regular_socket_path),$(abstract_socket_path)) +mpath_socket_systemd := $(if $(use_regular_socket),$(regular_socket_path),@$(abstract_socket_path)) ifeq ($(V),) Q := @ @@ -118,7 +121,8 @@ CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) $(D_URCU_VERSION) \ -DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(TGTDIR)$(configdir)\" \ -DDEFAULT_CONFIGFILE=\"$(TGTDIR)$(configfile)\" -DSTATE_DIR=\"$(TGTDIR)$(statedir)\" \ -DEXTRAVERSION=\"$(EXTRAVERSION)\" \ - -DDEFAULT_SOCKET=\"$(mpath_socket)\" -MMD -MP + -DDEFAULT_SOCKET=\"$(mpath_socket)\" -DUSE_REGULAR_SOCKET=$(if $(use_regular_socket),1,0) \ + -MMD -MP CFLAGS := -std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \ -fexceptions BIN_CFLAGS := -fPIE -DPIE @@ -171,4 +175,5 @@ NV_VERSION_SCRIPT = $(DEVLIB:%.so=%-nv.version) -e 's:@SYSDIR_BIN@:'$(sysdir_bin)': g' \ -e 's:@RUNTIME_DIR@:'$(runtimedir)':g' \ -e 's/@MODPROBE_UNIT@/'$(MODPROBE_UNIT)'/g' \ + -e 's,@MPATH_SOCKET@,'$(mpath_socket_systemd)',g' \ $< >$@ diff --git a/README.md b/README.md index 530caed..f6cf675 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,10 @@ The following variables can be passed to the `make` command line: stores run-time settings that need persist between reboots, such as known WWIDs, user-friendly names, and persistent reservation keys. The default is `$(etc_prefix)/etc/multipath`. + * `use_regular_socket`: if unset (default), use an abstract socket, which is + invisible in the file system. Otherwise, if set to 1, use the regular unix socket + `/run/multipathd.socket`. Setting this to 1 is necessary in order to + communicate with **multipathd** from containers. * `READLINE=libedit` or `READLINE=libreadline`: enable command line history and TAB completion in the interactive mode *(which is entered with `multipathd -k` or `multipathc`)*. The respective development package will be required for building. diff --git a/libmpathcmd/mpath_cmd.c b/libmpathcmd/mpath_cmd.c index a38e8b6..fdc7951 100644 --- a/libmpathcmd/mpath_cmd.c +++ b/libmpathcmd/mpath_cmd.c @@ -100,12 +100,13 @@ int mpath_connect__(int nonblocking) size_t len; struct sockaddr_un addr; int flags = 0; + const int offset = USE_REGULAR_SOCKET ? 0 : 1; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_LOCAL; addr.sun_path[0] = '\0'; - strncpy(&addr.sun_path[1], DEFAULT_SOCKET, sizeof(addr.sun_path) - 1); - len = strlen(DEFAULT_SOCKET) + 1 + sizeof(sa_family_t); + strncpy(&addr.sun_path[offset], DEFAULT_SOCKET, sizeof(addr.sun_path) - offset); + len = strlen(DEFAULT_SOCKET) + offset + sizeof(sa_family_t); if (len > sizeof(struct sockaddr_un)) len = sizeof(struct sockaddr_un); diff --git a/libmpathutil/uxsock.c b/libmpathutil/uxsock.c index 2135476..976a047 100644 --- a/libmpathutil/uxsock.c +++ b/libmpathutil/uxsock.c @@ -12,6 +12,7 @@ #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> +#include <sys/stat.h> #include <sys/un.h> #include <poll.h> #include <signal.h> @@ -45,6 +46,7 @@ int ux_socket_listen(const char *name) int num; #endif struct sockaddr_un addr; + const int offset = USE_REGULAR_SOCKET ? 0 : 1; #ifdef USE_SYSTEMD num = sd_listen_fds(0); @@ -56,6 +58,11 @@ int ux_socket_listen(const char *name) condlog(3, "using fd %d from sd_listen_fds", fd); return fd; } +#endif +#if USE_REGULAR_SOCKET + /* This is after the PID check, so unlinking should be fine */ + if (unlink(name) == -1 && errno != ENOENT) + condlog(1, "Failed to unlink %s", name); #endif fd = socket(AF_LOCAL, SOCK_STREAM, 0); if (fd == -1) { @@ -66,10 +73,10 @@ int ux_socket_listen(const char *name) memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_LOCAL; addr.sun_path[0] = '\0'; - len = strlen(name) + 1; + len = strlen(name) + offset; if (len >= sizeof(addr.sun_path)) - len = sizeof(addr.sun_path) - 1; - memcpy(&addr.sun_path[1], name, len); + len = sizeof(addr.sun_path); + memcpy(&addr.sun_path[offset], name, len); len += sizeof(sa_family_t); if (bind(fd, (struct sockaddr *)&addr, len) == -1) { @@ -78,6 +85,14 @@ int ux_socket_listen(const char *name) return -1; } +#if USE_REGULAR_SOCKET + /* + * Socket needs to have rw permissions for everone. + * SO_PEERCRED makes sure that only root can modify things. + */ + if (chmod(name, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) + condlog(3, "failed to set permissions on %s: %s", name, strerror(errno)); +#endif if (listen(fd, 10) == -1) { condlog(3, "Couldn't listen to ux_socket, error %d", errno); close(fd); diff --git a/multipathd/Makefile b/multipathd/Makefile index 997b40c..3673b1e 100644 --- a/multipathd/Makefile +++ b/multipathd/Makefile @@ -41,7 +41,7 @@ ifeq ($(FPIN_SUPPORT),1) OBJS += fpin_handlers.o endif -all : $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service +all : $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service $(EXEC).socket $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so @echo building $@ because of $? @@ -75,10 +75,10 @@ uninstall: $(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(EXEC).8 $(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(CLI).8 $(Q)$(RM) $(DESTDIR)$(unitdir)/$(EXEC).service - $(Q)$(RM) $(DESTDIR)$(unitdir)/$(EXEC).socket + $(Q)$(RM) $(DESTDIR)$(unitdir)/$(EXEC).socket $(EXEC).service clean: dep_clean - $(Q)$(RM) core *.o $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service + $(Q)$(RM) core *.o $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service $(EXEC).socket include $(wildcard $(OBJS:.o=.d) $(CLI_OBJS:.o=.d)) diff --git a/multipathd/multipathd.socket b/multipathd/multipathd.socket.in similarity index 87% rename from multipathd/multipathd.socket rename to multipathd/multipathd.socket.in index 6a62f5f..c0e86c3 100644 --- a/multipathd/multipathd.socket +++ b/multipathd/multipathd.socket.in @@ -7,7 +7,7 @@ ConditionVirtualization=!container Before=sockets.target [Socket] -ListenStream=@/org/kernel/linux/storage/multipathd +ListenStream=@MPATH_SOCKET@ [Install] # Socket activation for multipathd is disabled by default. -- 2.48.1