Skip to content

Commit 0f1f4e4

Browse files
committed
selftests/xattr: test xattrs on various socket families
Test user.* xattr operations on sockets from different address families: AF_INET, AF_INET6, AF_NETLINK, and AF_PACKET. All socket types use sockfs for their inodes, so user.* xattrs should work regardless of address family. Each fixture creates a socket (no bind needed) and verifies the full fsetxattr/fgetxattr/flistxattr/fremovexattr cycle. AF_INET6 skips if not supported; AF_PACKET skips if CAP_NET_RAW is unavailable. Also tests abstract namespace AF_UNIX sockets, which live in sockfs (not on a filesystem) and should support user.* xattrs. Link: https://patch.msgid.link/20260216-work-xattr-socket-v1-14-c2efa4f74cb7@kernel.org Acked-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent 0e75aea commit 0f1f4e4

3 files changed

Lines changed: 179 additions & 1 deletion

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
xattr_socket_test
22
xattr_sockfs_test
3+
xattr_socket_types_test
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SPDX-License-Identifier: GPL-2.0
22

33
CFLAGS += $(KHDR_INCLUDES)
4-
TEST_GEN_PROGS := xattr_socket_test xattr_sockfs_test
4+
TEST_GEN_PROGS := xattr_socket_test xattr_sockfs_test xattr_socket_types_test
55

66
include ../../lib.mk
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
// Copyright (c) 2026 Christian Brauner <brauner@kernel.org>
3+
/*
4+
* Test user.* xattrs on various socket families.
5+
*
6+
* All socket types use sockfs for their inodes, so user.* xattrs should
7+
* work on any socket regardless of address family. This tests AF_INET,
8+
* AF_INET6, AF_NETLINK, AF_PACKET, and abstract namespace AF_UNIX sockets.
9+
*/
10+
11+
#define _GNU_SOURCE
12+
#include <errno.h>
13+
#include <stddef.h>
14+
#include <stdio.h>
15+
#include <stdlib.h>
16+
#include <string.h>
17+
#include <sys/socket.h>
18+
#include <sys/types.h>
19+
#include <sys/un.h>
20+
#include <sys/xattr.h>
21+
#include <linux/netlink.h>
22+
#include <unistd.h>
23+
24+
#include "../../kselftest_harness.h"
25+
26+
#define TEST_XATTR_NAME "user.testattr"
27+
#define TEST_XATTR_VALUE "testvalue"
28+
29+
FIXTURE(xattr_socket_types)
30+
{
31+
int sockfd;
32+
};
33+
34+
FIXTURE_VARIANT(xattr_socket_types)
35+
{
36+
int family;
37+
int type;
38+
int protocol;
39+
};
40+
41+
FIXTURE_VARIANT_ADD(xattr_socket_types, inet) {
42+
.family = AF_INET,
43+
.type = SOCK_STREAM,
44+
.protocol = 0,
45+
};
46+
47+
FIXTURE_VARIANT_ADD(xattr_socket_types, inet6) {
48+
.family = AF_INET6,
49+
.type = SOCK_STREAM,
50+
.protocol = 0,
51+
};
52+
53+
FIXTURE_VARIANT_ADD(xattr_socket_types, netlink) {
54+
.family = AF_NETLINK,
55+
.type = SOCK_RAW,
56+
.protocol = NETLINK_USERSOCK,
57+
};
58+
59+
FIXTURE_VARIANT_ADD(xattr_socket_types, packet) {
60+
.family = AF_PACKET,
61+
.type = SOCK_DGRAM,
62+
.protocol = 0,
63+
};
64+
65+
FIXTURE_SETUP(xattr_socket_types)
66+
{
67+
self->sockfd = socket(variant->family, variant->type,
68+
variant->protocol);
69+
if (self->sockfd < 0 &&
70+
(errno == EAFNOSUPPORT || errno == EPERM || errno == EACCES))
71+
SKIP(return, "socket(%d, %d, %d) not available: %s",
72+
variant->family, variant->type, variant->protocol,
73+
strerror(errno));
74+
ASSERT_GE(self->sockfd, 0) {
75+
TH_LOG("Failed to create socket(%d, %d, %d): %s",
76+
variant->family, variant->type, variant->protocol,
77+
strerror(errno));
78+
}
79+
}
80+
81+
FIXTURE_TEARDOWN(xattr_socket_types)
82+
{
83+
if (self->sockfd >= 0)
84+
close(self->sockfd);
85+
}
86+
87+
TEST_F(xattr_socket_types, set_get_list_remove)
88+
{
89+
char buf[256], list[4096], *ptr;
90+
ssize_t ret;
91+
bool found;
92+
93+
ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,
94+
TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0);
95+
ASSERT_EQ(ret, 0) {
96+
TH_LOG("fsetxattr failed: %s", strerror(errno));
97+
}
98+
99+
memset(buf, 0, sizeof(buf));
100+
ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf));
101+
ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE));
102+
ASSERT_STREQ(buf, TEST_XATTR_VALUE);
103+
104+
memset(list, 0, sizeof(list));
105+
ret = flistxattr(self->sockfd, list, sizeof(list));
106+
ASSERT_GT(ret, 0);
107+
found = false;
108+
for (ptr = list; ptr < list + ret; ptr += strlen(ptr) + 1) {
109+
if (strcmp(ptr, TEST_XATTR_NAME) == 0)
110+
found = true;
111+
}
112+
ASSERT_TRUE(found);
113+
114+
ret = fremovexattr(self->sockfd, TEST_XATTR_NAME);
115+
ASSERT_EQ(ret, 0);
116+
117+
ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf));
118+
ASSERT_EQ(ret, -1);
119+
ASSERT_EQ(errno, ENODATA);
120+
}
121+
122+
/*
123+
* Test abstract namespace AF_UNIX socket.
124+
* Abstract sockets don't have a filesystem path; their inodes live in
125+
* sockfs so user.* xattrs should work via fsetxattr/fgetxattr.
126+
*/
127+
FIXTURE(xattr_abstract)
128+
{
129+
int sockfd;
130+
};
131+
132+
FIXTURE_SETUP(xattr_abstract)
133+
{
134+
struct sockaddr_un addr;
135+
char name[64];
136+
int ret, len;
137+
138+
self->sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
139+
ASSERT_GE(self->sockfd, 0);
140+
141+
len = snprintf(name, sizeof(name), "xattr_test_abstract_%d", getpid());
142+
143+
memset(&addr, 0, sizeof(addr));
144+
addr.sun_family = AF_UNIX;
145+
addr.sun_path[0] = '\0';
146+
memcpy(&addr.sun_path[1], name, len);
147+
148+
ret = bind(self->sockfd, (struct sockaddr *)&addr,
149+
offsetof(struct sockaddr_un, sun_path) + 1 + len);
150+
ASSERT_EQ(ret, 0);
151+
}
152+
153+
FIXTURE_TEARDOWN(xattr_abstract)
154+
{
155+
if (self->sockfd >= 0)
156+
close(self->sockfd);
157+
}
158+
159+
TEST_F(xattr_abstract, set_get)
160+
{
161+
char buf[256];
162+
ssize_t ret;
163+
164+
ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,
165+
TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0);
166+
ASSERT_EQ(ret, 0) {
167+
TH_LOG("fsetxattr on abstract socket failed: %s",
168+
strerror(errno));
169+
}
170+
171+
memset(buf, 0, sizeof(buf));
172+
ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf));
173+
ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE));
174+
ASSERT_STREQ(buf, TEST_XATTR_VALUE);
175+
}
176+
177+
TEST_HARNESS_MAIN

0 commit comments

Comments
 (0)