mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
core: SMACK label to Unix socket path and FD (#39772)
Currently, when a socket unit specifies SmackLabel=,
the label is not applied to the underlying Unix socket file or its file
descriptor.
This change ensures that the SMACK label is applied both to the
Unix socket path on the filesystem and to all associated socket FDs
when the socket is created.
Testing:
- Tested on Fedora 43 with kernel 6.17.7 with SMACK enabled.
- Created a systemd socket unit:
[Unit]
Description=UNIX socket
[Socket]
ListenStream=/run/test.sock
SmackLabel=label
[Install]
WantedBy=sockets.target
- Created a corresponding service:
[Unit]
Description=UNIX socket service
Requires=test.socket
[Service]
ExecStart=/usr/bin/socat -v - -
StandardInput=socket
[Install]
WantedBy=multi-user.target
- Verified SMACK labels using getfattr:
- Without SmackLabel:
```
# file: run/test.sock
security.SMACK64="_"
# file: proc/<pid>/fd/*
security.SMACK64="*"
```
- With SmackLabel=label:
```
# file: run/test.sock
security.SMACK64="label"
# file: proc/<pid>/fd/*
security.SMACK64="label"
```
This commit is contained in:
@@ -669,26 +669,6 @@ static const char* const netlink_family_table[] = {
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
|
||||
|
||||
static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
|
||||
[SOCKET_ADDRESS_DEFAULT] = "default",
|
||||
[SOCKET_ADDRESS_BOTH] = "both",
|
||||
[SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
|
||||
|
||||
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *n) {
|
||||
int r;
|
||||
|
||||
r = parse_boolean(n);
|
||||
if (r > 0)
|
||||
return SOCKET_ADDRESS_IPV6_ONLY;
|
||||
if (r == 0)
|
||||
return SOCKET_ADDRESS_BOTH;
|
||||
|
||||
return socket_address_bind_ipv6_only_from_string(n);
|
||||
}
|
||||
|
||||
bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
@@ -53,14 +53,6 @@ typedef struct SocketAddress {
|
||||
int protocol;
|
||||
} SocketAddress;
|
||||
|
||||
typedef enum SocketAddressBindIPv6Only {
|
||||
SOCKET_ADDRESS_DEFAULT,
|
||||
SOCKET_ADDRESS_BOTH,
|
||||
SOCKET_ADDRESS_IPV6_ONLY,
|
||||
_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX,
|
||||
_SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -EINVAL,
|
||||
} SocketAddressBindIPv6Only;
|
||||
|
||||
#define socket_address_family(a) ((a)->sockaddr.sa.sa_family)
|
||||
|
||||
const char* socket_address_type_to_string(int t) _const_;
|
||||
@@ -74,19 +66,6 @@ static inline int socket_address_unlink(const SocketAddress *a) {
|
||||
|
||||
bool socket_address_can_accept(const SocketAddress *a) _pure_;
|
||||
|
||||
int socket_address_listen(
|
||||
const SocketAddress *a,
|
||||
int flags,
|
||||
int backlog,
|
||||
SocketAddressBindIPv6Only only,
|
||||
const char *bind_to_device,
|
||||
bool reuse_port,
|
||||
bool free_bind,
|
||||
bool transparent,
|
||||
mode_t directory_mode,
|
||||
mode_t socket_mode,
|
||||
const char *label);
|
||||
|
||||
int socket_address_verify(const SocketAddress *a, bool strict) _pure_;
|
||||
int socket_address_print(const SocketAddress *a, char **p);
|
||||
bool socket_address_matches_fd(const SocketAddress *a, int fd);
|
||||
@@ -108,10 +87,6 @@ int getsockname_pretty(int fd, char **ret);
|
||||
|
||||
int socknameinfo_pretty(const struct sockaddr *sa, socklen_t salen, char **_ret);
|
||||
|
||||
const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_;
|
||||
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_;
|
||||
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *s);
|
||||
|
||||
int netlink_family_to_string_alloc(int b, char **s);
|
||||
int netlink_family_from_string(const char *s) _pure_;
|
||||
|
||||
|
||||
@@ -1504,7 +1504,7 @@ static int socket_determine_selinux_label(Socket *s, char **ret) {
|
||||
static int socket_address_listen_do(
|
||||
Socket *s,
|
||||
const SocketAddress *address,
|
||||
const char *label) {
|
||||
const char *selinux_label) {
|
||||
|
||||
assert(s);
|
||||
assert(address);
|
||||
@@ -1520,7 +1520,8 @@ static int socket_address_listen_do(
|
||||
s->transparent,
|
||||
s->directory_mode,
|
||||
s->socket_mode,
|
||||
label);
|
||||
selinux_label,
|
||||
s->smack);
|
||||
}
|
||||
|
||||
#define log_address_error_errno(u, address, error, fmt) \
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "execute.h"
|
||||
#include "list.h"
|
||||
#include "pidref.h"
|
||||
#include "socket-label.h"
|
||||
#include "socket-util.h"
|
||||
#include "unit.h"
|
||||
|
||||
|
||||
@@ -8,10 +8,34 @@
|
||||
#include "fs-util.h"
|
||||
#include "log.h"
|
||||
#include "mkdir-label.h"
|
||||
#include "parse-util.h"
|
||||
#include "selinux-util.h"
|
||||
#include "smack-util.h"
|
||||
#include "socket-label.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-table.h"
|
||||
#include "umask-util.h"
|
||||
|
||||
static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
|
||||
[SOCKET_ADDRESS_DEFAULT] = "default",
|
||||
[SOCKET_ADDRESS_BOTH] = "both",
|
||||
[SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
|
||||
|
||||
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *n) {
|
||||
int r;
|
||||
|
||||
r = parse_boolean(n);
|
||||
if (r > 0)
|
||||
return SOCKET_ADDRESS_IPV6_ONLY;
|
||||
if (r == 0)
|
||||
return SOCKET_ADDRESS_BOTH;
|
||||
|
||||
return socket_address_bind_ipv6_only_from_string(n);
|
||||
}
|
||||
|
||||
int socket_address_listen(
|
||||
const SocketAddress *a,
|
||||
int flags,
|
||||
@@ -23,7 +47,8 @@ int socket_address_listen(
|
||||
bool transparent,
|
||||
mode_t directory_mode,
|
||||
mode_t socket_mode,
|
||||
const char *label) {
|
||||
const char *selinux_label,
|
||||
const char *smack_label) {
|
||||
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
const char *p;
|
||||
@@ -38,20 +63,26 @@ int socket_address_listen(
|
||||
if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
if (label) {
|
||||
r = mac_selinux_create_socket_prepare(label);
|
||||
if (selinux_label) {
|
||||
r = mac_selinux_create_socket_prepare(selinux_label);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
fd = RET_NERRNO(socket(socket_address_family(a), a->type | flags, a->protocol));
|
||||
|
||||
if (label)
|
||||
if (selinux_label)
|
||||
mac_selinux_create_socket_clear();
|
||||
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (smack_label) {
|
||||
r = mac_smack_apply_fd(fd, SMACK_ATTR_ACCESS, smack_label);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to apply SMACK label for socket FD, ignoring: %m");
|
||||
}
|
||||
|
||||
if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
|
||||
r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_V6ONLY, only == SOCKET_ADDRESS_IPV6_ONLY);
|
||||
if (r < 0)
|
||||
@@ -107,6 +138,11 @@ int socket_address_listen(
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
if (smack_label) {
|
||||
r = mac_smack_apply(p, SMACK_ATTR_ACCESS, smack_label);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to apply SMACK label for socket path, ignoring: %m");
|
||||
}
|
||||
} else {
|
||||
if (bind(fd, &a->sockaddr.sa, a->size) < 0)
|
||||
return -errno;
|
||||
|
||||
30
src/shared/socket-label.h
Normal file
30
src/shared/socket-label.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "shared-forward.h"
|
||||
|
||||
typedef enum SocketAddressBindIPv6Only {
|
||||
SOCKET_ADDRESS_DEFAULT,
|
||||
SOCKET_ADDRESS_BOTH,
|
||||
SOCKET_ADDRESS_IPV6_ONLY,
|
||||
_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX,
|
||||
_SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -EINVAL,
|
||||
} SocketAddressBindIPv6Only;
|
||||
|
||||
const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_;
|
||||
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_;
|
||||
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *s);
|
||||
|
||||
int socket_address_listen(
|
||||
const SocketAddress *a,
|
||||
int flags,
|
||||
int backlog,
|
||||
SocketAddressBindIPv6Only only,
|
||||
const char *bind_to_device,
|
||||
bool reuse_port,
|
||||
bool free_bind,
|
||||
bool transparent,
|
||||
mode_t directory_mode,
|
||||
mode_t socket_mode,
|
||||
const char *selinux_label,
|
||||
const char *smack_label);
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "netlink-sock-diag.h"
|
||||
#include "netlink-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "socket-label.h"
|
||||
#include "socket-netlink.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-util.h"
|
||||
@@ -183,8 +184,18 @@ int make_socket_fd(int log_level, const char* address, int type, int flags) {
|
||||
|
||||
a.type = type;
|
||||
|
||||
fd = socket_address_listen(&a, type | flags, SOMAXCONN_DELUXE, SOCKET_ADDRESS_DEFAULT,
|
||||
NULL, false, false, false, 0755, 0644, NULL);
|
||||
fd = socket_address_listen(
|
||||
&a,
|
||||
type | flags,
|
||||
SOMAXCONN_DELUXE, SOCKET_ADDRESS_DEFAULT,
|
||||
/* bind_to_device= */ NULL,
|
||||
/* reuse_port= */ false,
|
||||
/* free_bind= */ false,
|
||||
/* transparent= */ false,
|
||||
0755,
|
||||
0644,
|
||||
/* selinux_label= */ NULL,
|
||||
/* smack_label= */ NULL);
|
||||
if (fd < 0 || log_get_max_level() >= log_level) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "service.h"
|
||||
#include "show-status.h"
|
||||
#include "socket.h"
|
||||
#include "socket-label.h"
|
||||
#include "socket-util.h"
|
||||
#include "swap.h"
|
||||
#include "test-tables.h"
|
||||
|
||||
Reference in New Issue
Block a user