Path: blob/master/tools/testing/selftests/filesystems/xattr/xattr_sockfs_test.c
170989 views
// SPDX-License-Identifier: GPL-2.01// Copyright (c) 2026 Christian Brauner <[email protected]>2/*3* Test extended attributes on sockfs sockets.4*5* Sockets created via socket() have their inodes in sockfs, which supports6* user.* xattrs with per-inode limits: up to 128 xattrs and 128KB total7* value size. These tests verify xattr operations via fsetxattr/fgetxattr/8* flistxattr/fremovexattr on the socket fd, as well as limit enforcement.9*/1011#define _GNU_SOURCE12#include <errno.h>13#include <stdio.h>14#include <stdlib.h>15#include <string.h>16#include <sys/socket.h>17#include <sys/types.h>18#include <sys/xattr.h>19#include <unistd.h>2021#include "../../kselftest_harness.h"2223#define TEST_XATTR_NAME "user.testattr"24#define TEST_XATTR_VALUE "testvalue"25#define TEST_XATTR_VALUE2 "newvalue"2627/* Per-inode limits for user.* xattrs on sockfs (from include/linux/xattr.h) */28#define SIMPLE_XATTR_MAX_NR 12829#define SIMPLE_XATTR_MAX_SIZE (128 << 10) /* 128 KB */3031#ifndef XATTR_SIZE_MAX32#define XATTR_SIZE_MAX 6553633#endif3435/*36* Fixture for sockfs socket xattr tests.37* Creates an AF_UNIX socket (lives in sockfs, not bound to any path).38*/39FIXTURE(xattr_sockfs)40{41int sockfd;42};4344FIXTURE_SETUP(xattr_sockfs)45{46self->sockfd = socket(AF_UNIX, SOCK_STREAM, 0);47ASSERT_GE(self->sockfd, 0) {48TH_LOG("Failed to create socket: %s", strerror(errno));49}50}5152FIXTURE_TEARDOWN(xattr_sockfs)53{54if (self->sockfd >= 0)55close(self->sockfd);56}5758TEST_F(xattr_sockfs, set_get_user_xattr)59{60char buf[256];61ssize_t ret;6263ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,64TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0);65ASSERT_EQ(ret, 0) {66TH_LOG("fsetxattr failed: %s", strerror(errno));67}6869memset(buf, 0, sizeof(buf));70ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf));71ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE)) {72TH_LOG("fgetxattr returned %zd: %s", ret, strerror(errno));73}74ASSERT_STREQ(buf, TEST_XATTR_VALUE);75}7677/*78* Test listing xattrs on a sockfs socket.79* Should include user.* xattrs and system.sockprotoname.80*/81TEST_F(xattr_sockfs, list_user_xattr)82{83char list[4096];84ssize_t ret;85char *ptr;86bool found_user = false;87bool found_proto = false;8889ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,90TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0);91ASSERT_EQ(ret, 0) {92TH_LOG("fsetxattr failed: %s", strerror(errno));93}9495memset(list, 0, sizeof(list));96ret = flistxattr(self->sockfd, list, sizeof(list));97ASSERT_GT(ret, 0) {98TH_LOG("flistxattr failed: %s", strerror(errno));99}100101for (ptr = list; ptr < list + ret; ptr += strlen(ptr) + 1) {102if (strcmp(ptr, TEST_XATTR_NAME) == 0)103found_user = true;104if (strcmp(ptr, "system.sockprotoname") == 0)105found_proto = true;106}107ASSERT_TRUE(found_user) {108TH_LOG("user xattr not found in list");109}110ASSERT_TRUE(found_proto) {111TH_LOG("system.sockprotoname not found in list");112}113}114115TEST_F(xattr_sockfs, remove_user_xattr)116{117char buf[256];118ssize_t ret;119120ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,121TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0);122ASSERT_EQ(ret, 0);123124ret = fremovexattr(self->sockfd, TEST_XATTR_NAME);125ASSERT_EQ(ret, 0) {126TH_LOG("fremovexattr failed: %s", strerror(errno));127}128129ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf));130ASSERT_EQ(ret, -1);131ASSERT_EQ(errno, ENODATA);132}133134TEST_F(xattr_sockfs, update_user_xattr)135{136char buf[256];137ssize_t ret;138139ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,140TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0);141ASSERT_EQ(ret, 0);142143ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,144TEST_XATTR_VALUE2, strlen(TEST_XATTR_VALUE2), 0);145ASSERT_EQ(ret, 0);146147memset(buf, 0, sizeof(buf));148ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf));149ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE2));150ASSERT_STREQ(buf, TEST_XATTR_VALUE2);151}152153TEST_F(xattr_sockfs, xattr_create_flag)154{155int ret;156157ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,158TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0);159ASSERT_EQ(ret, 0);160161ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,162TEST_XATTR_VALUE2, strlen(TEST_XATTR_VALUE2),163XATTR_CREATE);164ASSERT_EQ(ret, -1);165ASSERT_EQ(errno, EEXIST);166}167168TEST_F(xattr_sockfs, xattr_replace_flag)169{170int ret;171172ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,173TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE),174XATTR_REPLACE);175ASSERT_EQ(ret, -1);176ASSERT_EQ(errno, ENODATA);177}178179TEST_F(xattr_sockfs, get_nonexistent)180{181char buf[256];182ssize_t ret;183184ret = fgetxattr(self->sockfd, "user.nonexistent", buf, sizeof(buf));185ASSERT_EQ(ret, -1);186ASSERT_EQ(errno, ENODATA);187}188189TEST_F(xattr_sockfs, empty_value)190{191ssize_t ret;192193ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, "", 0, 0);194ASSERT_EQ(ret, 0);195196ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, NULL, 0);197ASSERT_EQ(ret, 0);198}199200TEST_F(xattr_sockfs, get_size)201{202ssize_t ret;203204ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,205TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0);206ASSERT_EQ(ret, 0);207208ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, NULL, 0);209ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE));210}211212TEST_F(xattr_sockfs, buffer_too_small)213{214char buf[2];215ssize_t ret;216217ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,218TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0);219ASSERT_EQ(ret, 0);220221ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf));222ASSERT_EQ(ret, -1);223ASSERT_EQ(errno, ERANGE);224}225226/*227* Test maximum number of user.* xattrs per socket.228* The kernel enforces SIMPLE_XATTR_MAX_NR (128), so the 129th should229* fail with ENOSPC.230*/231TEST_F(xattr_sockfs, max_nr_xattrs)232{233char name[32];234int i, ret;235236for (i = 0; i < SIMPLE_XATTR_MAX_NR; i++) {237snprintf(name, sizeof(name), "user.test%03d", i);238ret = fsetxattr(self->sockfd, name, "v", 1, 0);239ASSERT_EQ(ret, 0) {240TH_LOG("fsetxattr %s failed at i=%d: %s",241name, i, strerror(errno));242}243}244245ret = fsetxattr(self->sockfd, "user.overflow", "v", 1, 0);246ASSERT_EQ(ret, -1);247ASSERT_EQ(errno, ENOSPC) {248TH_LOG("Expected ENOSPC for xattr %d, got %s",249SIMPLE_XATTR_MAX_NR + 1, strerror(errno));250}251}252253/*254* Test maximum total value size for user.* xattrs.255* The kernel enforces SIMPLE_XATTR_MAX_SIZE (128KB). Individual xattr256* values are limited to XATTR_SIZE_MAX (64KB) by the VFS, so we need257* at least two xattrs to hit the total limit.258*/259TEST_F(xattr_sockfs, max_xattr_size)260{261char *value;262int ret;263264value = malloc(XATTR_SIZE_MAX);265ASSERT_NE(value, NULL);266memset(value, 'A', XATTR_SIZE_MAX);267268/* First 64KB xattr - total = 64KB */269ret = fsetxattr(self->sockfd, "user.big1", value, XATTR_SIZE_MAX, 0);270ASSERT_EQ(ret, 0) {271TH_LOG("first large xattr failed: %s", strerror(errno));272}273274/* Second 64KB xattr - total = 128KB (exactly at limit) */275ret = fsetxattr(self->sockfd, "user.big2", value, XATTR_SIZE_MAX, 0);276free(value);277ASSERT_EQ(ret, 0) {278TH_LOG("second large xattr failed: %s", strerror(errno));279}280281/* Third xattr with 1 byte - total > 128KB, should fail */282ret = fsetxattr(self->sockfd, "user.big3", "v", 1, 0);283ASSERT_EQ(ret, -1);284ASSERT_EQ(errno, ENOSPC) {285TH_LOG("Expected ENOSPC when exceeding size limit, got %s",286strerror(errno));287}288}289290/*291* Test that removing an xattr frees limit space, allowing re-addition.292*/293TEST_F(xattr_sockfs, limit_remove_readd)294{295char name[32];296int i, ret;297298/* Fill up to the maximum count */299for (i = 0; i < SIMPLE_XATTR_MAX_NR; i++) {300snprintf(name, sizeof(name), "user.test%03d", i);301ret = fsetxattr(self->sockfd, name, "v", 1, 0);302ASSERT_EQ(ret, 0);303}304305/* Verify we're at the limit */306ret = fsetxattr(self->sockfd, "user.overflow", "v", 1, 0);307ASSERT_EQ(ret, -1);308ASSERT_EQ(errno, ENOSPC);309310/* Remove one xattr */311ret = fremovexattr(self->sockfd, "user.test000");312ASSERT_EQ(ret, 0);313314/* Now we should be able to add one more */315ret = fsetxattr(self->sockfd, "user.newattr", "v", 1, 0);316ASSERT_EQ(ret, 0) {317TH_LOG("re-add after remove failed: %s", strerror(errno));318}319}320321/*322* Test that two different sockets have independent xattr limits.323*/324TEST_F(xattr_sockfs, limits_per_inode)325{326char buf[256];327int sock2;328ssize_t ret;329330sock2 = socket(AF_UNIX, SOCK_STREAM, 0);331ASSERT_GE(sock2, 0);332333/* Set xattr on first socket */334ret = fsetxattr(self->sockfd, TEST_XATTR_NAME,335TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0);336ASSERT_EQ(ret, 0);337338/* First socket's xattr should not be visible on second socket */339ret = fgetxattr(sock2, TEST_XATTR_NAME, NULL, 0);340ASSERT_EQ(ret, -1);341ASSERT_EQ(errno, ENODATA);342343/* Second socket should independently accept xattrs */344ret = fsetxattr(sock2, TEST_XATTR_NAME,345TEST_XATTR_VALUE2, strlen(TEST_XATTR_VALUE2), 0);346ASSERT_EQ(ret, 0);347348/* Verify each socket has its own value */349memset(buf, 0, sizeof(buf));350ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf));351ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE));352ASSERT_STREQ(buf, TEST_XATTR_VALUE);353354memset(buf, 0, sizeof(buf));355ret = fgetxattr(sock2, TEST_XATTR_NAME, buf, sizeof(buf));356ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE2));357ASSERT_STREQ(buf, TEST_XATTR_VALUE2);358359close(sock2);360}361362TEST_HARNESS_MAIN363364365