Skip to content
Permalink
Browse files

tree-wide: introduce new SOCKADDR_UN_LEN() macro, and use it everywhere

The macro determines the right length of a AF_UNIX "struct sockaddr_un" to pass to
connect() or bind(). It automatically figures out if the socket refers to an
abstract namespace socket, or a socket in the file system, and properly handles
the full length of the path field.

This macro is not only safer, but also simpler to use, than the usual
offsetof() + strlen() logic.
  • Loading branch information
poettering committed May 5, 2016
1 parent d8fdc62 commit fc2fffe7706ef269005bf4eef56570346c9ca3da
@@ -165,7 +165,7 @@ static int log_open_syslog(void) {
goto fail;
}

if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
safe_close(syslog_fd);

/* Some legacy syslog systems still use stream
@@ -177,7 +177,7 @@ static int log_open_syslog(void) {
goto fail;
}

if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = -errno;
goto fail;
}
@@ -215,7 +215,7 @@ static int log_open_journal(void) {
goto fail;
}

if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
if (connect(journal_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = -errno;
goto fail;
}
@@ -137,3 +137,14 @@ ssize_t next_datagram_size_fd(int fd);

#define CMSG_FOREACH(cmsg, mh) \
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))

/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
#define SOCKADDR_UN_LEN(sa) \
({ \
const struct sockaddr_un *_sa = &(sa); \
assert(_sa->sun_family == AF_UNIX); \
offsetof(struct sockaddr_un, sun_path) + \
(_sa->sun_path[0] == 0 ? \
1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \
strnlen(_sa->sun_path, sizeof(_sa->sun_path))); \
})
@@ -52,7 +52,7 @@ int main(int argc, char *argv[]) {

l = strlen(argv[1]);

n = sendto(fd, argv[1], l, 0, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
n = sendto(fd, argv[1], l, 0, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (n < 0) {
log_debug_errno(errno, "Failed to send cgroups agent message: %m");
return EXIT_FAILURE;
@@ -975,7 +975,7 @@ static int bus_init_private(Manager *m) {
return 0;

strcpy(sa.un.sun_path, "/run/systemd/private");
salen = offsetof(union sockaddr_union, un.sun_path) + strlen("/run/systemd/private");
salen = SOCKADDR_UN_LEN(sa.un);
} else {
size_t left = sizeof(sa.un.sun_path);
char *p = sa.un.sun_path;
@@ -271,7 +271,7 @@ static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
}
}

r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
r = -errno;

@@ -705,7 +705,7 @@ static int manager_setup_notify(Manager *m) {
(void) unlink(m->notify_socket);

strncpy(sa.un.sun_path, m->notify_socket, sizeof(sa.un.sun_path)-1);
r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);

@@ -782,7 +782,7 @@ static int manager_setup_cgroups_agent(Manager *m) {

/* Only allow root to connect to this socket */
RUN_WITH_UMASK(0077)
r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);

@@ -2245,11 +2245,10 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
}

void manager_send_unit_plymouth(Manager *m, Unit *u) {
union sockaddr_union sa = PLYMOUTH_SOCKET;

int n = 0;
static const union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_free_ char *message = NULL;
_cleanup_close_ int fd = -1;
int n = 0;

/* Don't generate plymouth events if the service was already
* started and we're just deserializing */
@@ -2275,7 +2274,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
return;
}

if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {

if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
log_error_errno(errno, "connect() failed: %m");
@@ -847,7 +847,7 @@ static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd)
if (fd < 0)
return log_error_errno(errno, "Failed to create coredump socket: %m");

if (connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)) < 0)
if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return log_error_errno(errno, "Failed to connect to coredump service: %m");

for (i = 0; i < n_iovec; i++) {
@@ -262,7 +262,7 @@ static int fsck_progress_socket(void) {
if (fd < 0)
return log_warning_errno(errno, "socket(): %m");

if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = log_full_errno(errno == ECONNREFUSED || errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
errno, "Failed to connect to progress socket %s, ignoring: %m", sa.un.sun_path);
safe_close(fd);
@@ -677,7 +677,7 @@ static int manager_new(Manager **ret) {
(void) mkdir_parents_label(sa.un.sun_path, 0755);
(void) unlink(sa.un.sun_path);

if (bind(m->notify_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)) < 0)
if (bind(m->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;

if (setsockopt(m->notify_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
@@ -208,13 +208,13 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
struct iovec *w;
uint64_t *l;
int i, j = 0;
struct sockaddr_un sa = {
.sun_family = AF_UNIX,
.sun_path = "/run/systemd/journal/socket",
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/socket",
};
struct msghdr mh = {
.msg_name = &sa,
.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
.msg_name = (struct sockaddr*) &sa.sa,
.msg_namelen = SOCKADDR_UN_LEN(sa.un),
};
ssize_t k;
bool have_syslog_identifier = false;
@@ -392,7 +392,7 @@ _public_ int sd_journal_perror(const char *message) {
}

_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
union sockaddr_union sa = {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};
@@ -408,7 +408,7 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve
if (fd < 0)
return -errno;

r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return -errno;

@@ -448,24 +448,24 @@ void server_process_native_file(
}

int server_open_native_socket(Server*s) {

static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/socket",
};
static const int one = 1;
int r;

assert(s);

if (s->native_fd < 0) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/socket",
};

s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->native_fd < 0)
return log_error_errno(errno, "socket() failed: %m");

unlink(sa.un.sun_path);
(void) unlink(sa.un.sun_path);

r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
r = bind(s->native_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);

@@ -1696,7 +1696,7 @@ static int server_connect_notify(Server *s) {
if (sa.un.sun_path[0] == '@')
sa.un.sun_path[0] = 0;

r = connect(s->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(e));
r = connect(s->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "Failed to connect to notify socket: %m");

@@ -700,23 +700,22 @@ int server_restore_streams(Server *s, FDSet *fds) {
}

int server_open_stdout_socket(Server *s) {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};
int r;

assert(s);

if (s->stdout_fd < 0) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};

s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->stdout_fd < 0)
return log_error_errno(errno, "socket() failed: %m");

unlink(sa.un.sun_path);
(void) unlink(sa.un.sun_path);

r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
r = bind(s->stdout_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);

@@ -52,8 +52,7 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
.msg_iov = (struct iovec *) iovec,
.msg_iovlen = n_iovec,
.msg_name = (struct sockaddr*) &sa.sa,
.msg_namelen = offsetof(union sockaddr_union, un.sun_path)
+ strlen("/run/systemd/journal/syslog"),
.msg_namelen = SOCKADDR_UN_LEN(sa.un),
};
struct cmsghdr *cmsg;
union {
@@ -383,24 +382,24 @@ void server_process_syslog_message(
}

int server_open_syslog_socket(Server *s) {

static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/dev-log",
};
static const int one = 1;
int r;

assert(s);

if (s->syslog_fd < 0) {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/dev-log",
};

s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->syslog_fd < 0)
return log_error_errno(errno, "socket() failed: %m");

unlink(sa.un.sun_path);
(void) unlink(sa.un.sun_path);

r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
r = bind(s->syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);

@@ -437,6 +436,7 @@ int server_open_syslog_socket(Server *s) {

void server_maybe_warn_forward_syslog_missed(Server *s) {
usec_t n;

assert(s);

if (s->n_forward_syslog_missed <= 0)
@@ -836,7 +836,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)

b->sockaddr.un.sun_family = AF_UNIX;
strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen("/var/run/dbus/system_bus_socket");
b->sockaddr_size = SOCKADDR_UN_LEN(b->sockaddr.un);

return 0;
}
@@ -458,9 +458,7 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
if (sockaddr.un.sun_path[0] == '@')
sockaddr.un.sun_path[0] = 0;

msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
msghdr.msg_namelen = sizeof(struct sockaddr_un);
msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);

have_pid = pid != 0 && pid != getpid();

@@ -150,7 +150,7 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_
if (fd < 0)
return -errno;

if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;

r = getpeercred(fd, &ucred);
@@ -26,14 +26,12 @@
#include "fd-util.h"
#include "log.h"
#include "macro.h"
#include "socket-util.h"
#include "string-util.h"
#include "util.h"

static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) {
union {
struct sockaddr sa;
struct sockaddr_un un;
} sa = {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};

@@ -43,7 +41,7 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s

strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));

if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0)
if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return log_error_errno(errno, "Failed to send: %m");

return 0;
@@ -431,7 +431,7 @@ static int create_socket(char **name) {
snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64());

RUN_WITH_UMASK(0177) {
if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
if (bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;
}

@@ -400,28 +400,19 @@ static int resolve_remote(Connection *c) {

union sockaddr_union sa = {};
const char *node, *service;
socklen_t salen;
int r;

if (path_is_absolute(arg_remote_host)) {
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, arg_remote_host, sizeof(sa.un.sun_path)-1);
sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;

salen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path);

return connection_start(c, &sa.sa, salen);
strncpy(sa.un.sun_path, arg_remote_host, sizeof(sa.un.sun_path));
return connection_start(c, &sa.sa, SOCKADDR_UN_LEN(sa.un));
}

if (arg_remote_host[0] == '@') {
sa.un.sun_family = AF_UNIX;
sa.un.sun_path[0] = 0;
strncpy(sa.un.sun_path+1, arg_remote_host+1, sizeof(sa.un.sun_path)-2);
sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;

salen = offsetof(union sockaddr_union, un.sun_path) + 1 + strlen(sa.un.sun_path + 1);

return connection_start(c, &sa.sa, salen);
strncpy(sa.un.sun_path+1, arg_remote_host+1, sizeof(sa.un.sun_path)-1);
return connection_start(c, &sa.sa, SOCKADDR_UN_LEN(sa.un));
}

service = strrchr(arg_remote_host, ':');

0 comments on commit fc2fffe

Please sign in to comment.
You can’t perform that action at this time.