Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'vfs-7.1-rc1.xattr' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs xattr updates from Christian Brauner:
"This reworks the simple_xattr infrastructure and adds support for
user.* extended attributes on sockets.

The simple_xattr subsystem currently uses an rbtree protected by a
reader-writer spinlock. This series replaces the rbtree with an
rhashtable giving O(1) average-case lookup with RCU-based lockless
reads. This sped up concurrent access patterns on tmpfs quite a bit
and it's an overall easy enough conversion to do and gets rid or
rwlock_t.

The conversion is done incrementally: a new rhashtable path is added
alongside the existing rbtree, consumers are migrated one at a time
(shmem, kernfs, pidfs), and then the rbtree code is removed. All three
consumers switch from embedded structs to pointer-based lazy
allocation so the rhashtable overhead is only paid for inodes that
actually use xattrs.

With this infrastructure in place the series adds support for user.*
xattrs on sockets. Path-based AF_UNIX sockets inherit xattr support
from the underlying filesystem (e.g. tmpfs) but sockets in sockfs -
that is everything created via socket() including abstract namespace
AF_UNIX sockets - had no xattr support at all.

The xattr_permission() checks are reworked to allow user.* xattrs on
S_IFSOCK inodes. Sockfs sockets get per-inode limits of 128 xattrs and
128KB total value size matching the limits already in use for kernfs.

The practical motivation comes from several directions. systemd and
GNOME are expanding their use of Varlink as an IPC mechanism.

For D-Bus there are tools like dbus-monitor that can observe IPC
traffic across the system but this only works because D-Bus has a
central broker.

For Varlink there is no broker and there is currently no way to
identify which sockets speak Varlink. With user.* xattrs on sockets a
service can label its socket with the IPC protocol it speaks (e.g.,
user.varlink=1) and an eBPF program can then selectively capture
traffic on those sockets. Enumerating bound sockets via netlink
combined with these xattr labels gives a way to discover all Varlink
IPC entrypoints for debugging and introspection.

Similarly, systemd-journald wants to use xattrs on the /dev/log socket
for protocol negotiation to indicate whether RFC 5424 structured
syslog is supported or whether only the legacy RFC 3164 format should
be used.

In containers these labels are particularly useful as high-privilege
or more complicated solutions for socket identification aren't
available.

The series comes with comprehensive selftests covering path-based
AF_UNIX sockets, sockfs socket operations, per-inode limit
enforcement, and xattr operations across multiple address families
(AF_INET, AF_INET6, AF_NETLINK, AF_PACKET)"

* tag 'vfs-7.1-rc1.xattr' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
selftests/xattr: test xattrs on various socket families
selftests/xattr: sockfs socket xattr tests
selftests/xattr: path-based AF_UNIX socket xattr tests
xattr: support extended attributes on sockets
xattr,net: support limited amount of extended attributes on sockfs sockets
xattr: move user limits for xattrs to generic infra
xattr: switch xattr_permission() to switch statement
xattr: add xattr_permission_error()
xattr: remove rbtree-based simple_xattr infrastructure
pidfs: adapt to rhashtable-based simple_xattrs
kernfs: adapt to rhashtable-based simple_xattrs with lazy allocation
shmem: adapt to rhashtable-based simple_xattrs with lazy allocation
xattr: add rhashtable-based simple_xattr infrastructure
xattr: add rcu_head and rhash_head to struct simple_xattr

+1547 -296
+11 -4
fs/kernfs/dir.c
··· 564 564 /* If the whole node goes away, then name can't be used outside */ 565 565 kfree_const(rcu_access_pointer(kn->name)); 566 566 567 - if (kn->iattr) { 568 - simple_xattrs_free(&kn->iattr->xattrs, NULL); 567 + if (kn->iattr) 569 568 kmem_cache_free(kernfs_iattrs_cache, kn->iattr); 570 - } 571 569 572 570 kmem_cache_free(kernfs_node_cache, kn); 573 571 } ··· 598 600 599 601 if (kernfs_type(kn) == KERNFS_LINK) 600 602 kernfs_put(kn->symlink.target_kn); 603 + 604 + if (kn->iattr && kn->iattr->xattrs) { 605 + simple_xattrs_free(kn->iattr->xattrs, NULL); 606 + kfree(kn->iattr->xattrs); 607 + kn->iattr->xattrs = NULL; 608 + } 601 609 602 610 spin_lock(&root->kernfs_idr_lock); 603 611 idr_remove(&root->ino_idr, (u32)kernfs_ino(kn)); ··· 703 699 704 700 err_out4: 705 701 if (kn->iattr) { 706 - simple_xattrs_free(&kn->iattr->xattrs, NULL); 702 + if (kn->iattr->xattrs) { 703 + simple_xattrs_free(kn->iattr->xattrs, NULL); 704 + kfree(kn->iattr->xattrs); 705 + } 707 706 kmem_cache_free(kernfs_iattrs_cache, kn->iattr); 708 707 } 709 708 err_out3:
+23 -76
fs/kernfs/inode.c
··· 45 45 ret->ia_mtime = ret->ia_atime; 46 46 ret->ia_ctime = ret->ia_atime; 47 47 48 - simple_xattrs_init(&ret->xattrs); 49 - atomic_set(&ret->nr_user_xattrs, 0); 50 - atomic_set(&ret->user_xattr_size, 0); 48 + simple_xattr_limits_init(&ret->xattr_limits); 51 49 52 50 /* If someone raced us, recognize it. */ 53 51 if (!try_cmpxchg(&kn->iattr, &attr, ret)) ··· 144 146 if (!attrs) 145 147 return -ENOMEM; 146 148 147 - return simple_xattr_list(d_inode(dentry), &attrs->xattrs, buf, size); 149 + return simple_xattr_list(d_inode(dentry), READ_ONCE(attrs->xattrs), 150 + buf, size); 148 151 } 149 152 150 153 static inline void set_default_inode_attr(struct inode *inode, umode_t mode) ··· 297 298 void *value, size_t size) 298 299 { 299 300 struct kernfs_iattrs *attrs = kernfs_iattrs_noalloc(kn); 301 + struct simple_xattrs *xattrs; 302 + 300 303 if (!attrs) 301 304 return -ENODATA; 302 305 303 - return simple_xattr_get(&attrs->xattrs, name, value, size); 306 + xattrs = READ_ONCE(attrs->xattrs); 307 + if (!xattrs) 308 + return -ENODATA; 309 + 310 + return simple_xattr_get(xattrs, name, value, size); 304 311 } 305 312 306 313 int kernfs_xattr_set(struct kernfs_node *kn, const char *name, 307 314 const void *value, size_t size, int flags) 308 315 { 309 316 struct simple_xattr *old_xattr; 317 + struct simple_xattrs *xattrs; 310 318 struct kernfs_iattrs *attrs; 311 319 312 320 attrs = kernfs_iattrs(kn); 313 321 if (!attrs) 314 322 return -ENOMEM; 315 323 316 - old_xattr = simple_xattr_set(&attrs->xattrs, name, value, size, flags); 324 + xattrs = simple_xattrs_lazy_alloc(&attrs->xattrs, value, flags); 325 + if (IS_ERR_OR_NULL(xattrs)) 326 + return PTR_ERR(xattrs); 327 + 328 + old_xattr = simple_xattr_set(xattrs, name, value, size, flags); 317 329 if (IS_ERR(old_xattr)) 318 330 return PTR_ERR(old_xattr); 319 331 320 - simple_xattr_free(old_xattr); 332 + simple_xattr_free_rcu(old_xattr); 321 333 return 0; 322 334 } 323 335 ··· 354 344 return kernfs_xattr_set(kn, name, value, size, flags); 355 345 } 356 346 357 - static int kernfs_vfs_user_xattr_add(struct kernfs_node *kn, 358 - const char *full_name, 359 - struct simple_xattrs *xattrs, 360 - const void *value, size_t size, int flags) 361 - { 362 - struct kernfs_iattrs *attr = kernfs_iattrs_noalloc(kn); 363 - atomic_t *sz = &attr->user_xattr_size; 364 - atomic_t *nr = &attr->nr_user_xattrs; 365 - struct simple_xattr *old_xattr; 366 - int ret; 367 - 368 - if (atomic_inc_return(nr) > KERNFS_MAX_USER_XATTRS) { 369 - ret = -ENOSPC; 370 - goto dec_count_out; 371 - } 372 - 373 - if (atomic_add_return(size, sz) > KERNFS_USER_XATTR_SIZE_LIMIT) { 374 - ret = -ENOSPC; 375 - goto dec_size_out; 376 - } 377 - 378 - old_xattr = simple_xattr_set(xattrs, full_name, value, size, flags); 379 - if (!old_xattr) 380 - return 0; 381 - 382 - if (IS_ERR(old_xattr)) { 383 - ret = PTR_ERR(old_xattr); 384 - goto dec_size_out; 385 - } 386 - 387 - ret = 0; 388 - size = old_xattr->size; 389 - simple_xattr_free(old_xattr); 390 - dec_size_out: 391 - atomic_sub(size, sz); 392 - dec_count_out: 393 - atomic_dec(nr); 394 - return ret; 395 - } 396 - 397 - static int kernfs_vfs_user_xattr_rm(struct kernfs_node *kn, 398 - const char *full_name, 399 - struct simple_xattrs *xattrs, 400 - const void *value, size_t size, int flags) 401 - { 402 - struct kernfs_iattrs *attr = kernfs_iattrs_noalloc(kn); 403 - atomic_t *sz = &attr->user_xattr_size; 404 - atomic_t *nr = &attr->nr_user_xattrs; 405 - struct simple_xattr *old_xattr; 406 - 407 - old_xattr = simple_xattr_set(xattrs, full_name, value, size, flags); 408 - if (!old_xattr) 409 - return 0; 410 - 411 - if (IS_ERR(old_xattr)) 412 - return PTR_ERR(old_xattr); 413 - 414 - atomic_sub(old_xattr->size, sz); 415 - atomic_dec(nr); 416 - simple_xattr_free(old_xattr); 417 - return 0; 418 - } 419 - 420 347 static int kernfs_vfs_user_xattr_set(const struct xattr_handler *handler, 421 348 struct mnt_idmap *idmap, 422 349 struct dentry *unused, struct inode *inode, ··· 362 415 { 363 416 const char *full_name = xattr_full_name(handler, suffix); 364 417 struct kernfs_node *kn = inode->i_private; 418 + struct simple_xattrs *xattrs; 365 419 struct kernfs_iattrs *attrs; 366 420 367 421 if (!(kernfs_root(kn)->flags & KERNFS_ROOT_SUPPORT_USER_XATTR)) ··· 372 424 if (!attrs) 373 425 return -ENOMEM; 374 426 375 - if (value) 376 - return kernfs_vfs_user_xattr_add(kn, full_name, &attrs->xattrs, 377 - value, size, flags); 378 - else 379 - return kernfs_vfs_user_xattr_rm(kn, full_name, &attrs->xattrs, 380 - value, size, flags); 427 + xattrs = simple_xattrs_lazy_alloc(&attrs->xattrs, value, flags); 428 + if (IS_ERR_OR_NULL(xattrs)) 429 + return PTR_ERR(xattrs); 381 430 431 + return simple_xattr_set_limited(xattrs, &attrs->xattr_limits, 432 + full_name, value, size, flags); 382 433 } 383 434 384 435 static const struct xattr_handler kernfs_trusted_xattr_handler = {
+2 -3
fs/kernfs/kernfs-internal.h
··· 26 26 struct timespec64 ia_mtime; 27 27 struct timespec64 ia_ctime; 28 28 29 - struct simple_xattrs xattrs; 30 - atomic_t nr_user_xattrs; 31 - atomic_t user_xattr_size; 29 + struct simple_xattrs *xattrs; 30 + struct simple_xattr_limits xattr_limits; 32 31 }; 33 32 34 33 struct kernfs_root {
+40 -24
fs/pidfs.c
··· 22 22 #include <net/net_namespace.h> 23 23 #include <linux/coredump.h> 24 24 #include <linux/rhashtable.h> 25 + #include <linux/llist.h> 25 26 #include <linux/xattr.h> 26 27 #include <linux/cookie.h> 27 28 ··· 32 31 #define PIDFS_PID_DEAD ERR_PTR(-ESRCH) 33 32 34 33 static struct kmem_cache *pidfs_attr_cachep __ro_after_init; 35 - static struct kmem_cache *pidfs_xattr_cachep __ro_after_init; 36 34 37 35 static struct path pidfs_root_path = {}; 38 36 ··· 46 46 PIDFS_ATTR_BIT_COREDUMP = 1, 47 47 }; 48 48 49 - struct pidfs_attr { 49 + struct pidfs_anon_attr { 50 50 unsigned long attr_mask; 51 - struct simple_xattrs *xattrs; 52 51 struct /* exit info */ { 53 52 __u64 cgroupid; 54 53 __s32 exit_code; ··· 92 93 * inode number and the inode generation number to compare or 93 94 * use file handles. 94 95 */ 96 + struct pidfs_attr { 97 + struct simple_xattrs *xattrs; 98 + union { 99 + struct pidfs_anon_attr; 100 + struct llist_node pidfs_llist; 101 + }; 102 + }; 95 103 96 104 #if BITS_PER_LONG == 32 97 105 ··· 184 178 pidfs_ino_ht_params); 185 179 } 186 180 181 + static LLIST_HEAD(pidfs_free_list); 182 + 183 + static void pidfs_free_attr_work(struct work_struct *work) 184 + { 185 + struct pidfs_attr *attr, *next; 186 + struct llist_node *head; 187 + 188 + head = llist_del_all(&pidfs_free_list); 189 + llist_for_each_entry_safe(attr, next, head, pidfs_llist) { 190 + struct simple_xattrs *xattrs = attr->xattrs; 191 + 192 + if (xattrs) { 193 + simple_xattrs_free(xattrs, NULL); 194 + kfree(xattrs); 195 + } 196 + kfree(attr); 197 + } 198 + } 199 + 200 + static DECLARE_WORK(pidfs_free_work, pidfs_free_attr_work); 201 + 187 202 void pidfs_free_pid(struct pid *pid) 188 203 { 189 - struct pidfs_attr *attr __free(kfree) = no_free_ptr(pid->attr); 190 - struct simple_xattrs *xattrs __free(kfree) = NULL; 204 + struct pidfs_attr *attr = pid->attr; 191 205 192 206 /* 193 207 * Any dentry must've been wiped from the pid by now. ··· 226 200 if (IS_ERR(attr)) 227 201 return; 228 202 229 - xattrs = no_free_ptr(attr->xattrs); 230 - if (xattrs) 231 - simple_xattrs_free(xattrs, NULL); 203 + if (likely(!attr->xattrs)) 204 + kfree(attr); 205 + else if (llist_add(&attr->pidfs_llist, &pidfs_free_list)) 206 + schedule_work(&pidfs_free_work); 232 207 } 233 208 234 209 #ifdef CONFIG_PROC_FS ··· 1036 1009 1037 1010 xattrs = READ_ONCE(attr->xattrs); 1038 1011 if (!xattrs) 1039 - return 0; 1012 + return -ENODATA; 1040 1013 1041 1014 name = xattr_full_name(handler, suffix); 1042 1015 return simple_xattr_get(xattrs, name, value, size); ··· 1056 1029 /* Ensure we're the only one to set @attr->xattrs. */ 1057 1030 WARN_ON_ONCE(!inode_is_locked(inode)); 1058 1031 1059 - xattrs = READ_ONCE(attr->xattrs); 1060 - if (!xattrs) { 1061 - xattrs = kmem_cache_zalloc(pidfs_xattr_cachep, GFP_KERNEL); 1062 - if (!xattrs) 1063 - return -ENOMEM; 1064 - 1065 - simple_xattrs_init(xattrs); 1066 - smp_store_release(&pid->attr->xattrs, xattrs); 1067 - } 1032 + xattrs = simple_xattrs_lazy_alloc(&attr->xattrs, value, flags); 1033 + if (IS_ERR_OR_NULL(xattrs)) 1034 + return PTR_ERR(xattrs); 1068 1035 1069 1036 name = xattr_full_name(handler, suffix); 1070 1037 old_xattr = simple_xattr_set(xattrs, name, value, size, flags); 1071 1038 if (IS_ERR(old_xattr)) 1072 1039 return PTR_ERR(old_xattr); 1073 1040 1074 - simple_xattr_free(old_xattr); 1041 + simple_xattr_free_rcu(old_xattr); 1075 1042 return 0; 1076 1043 } 1077 1044 ··· 1142 1121 pidfs_attr_cachep = kmem_cache_create("pidfs_attr_cache", sizeof(struct pidfs_attr), 0, 1143 1122 (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | 1144 1123 SLAB_ACCOUNT | SLAB_PANIC), NULL); 1145 - 1146 - pidfs_xattr_cachep = kmem_cache_create("pidfs_xattr_cache", 1147 - sizeof(struct simple_xattrs), 0, 1148 - (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | 1149 - SLAB_ACCOUNT | SLAB_PANIC), NULL); 1150 1124 1151 1125 pidfs_mnt = kern_mount(&pidfs_type); 1152 1126 if (IS_ERR(pidfs_mnt))
+286 -139
fs/xattr.c
··· 22 22 #include <linux/audit.h> 23 23 #include <linux/vmalloc.h> 24 24 #include <linux/posix_acl_xattr.h> 25 + #include <linux/rhashtable.h> 25 26 26 27 #include <linux/uaccess.h> 27 28 ··· 106 105 return 0; 107 106 } 108 107 108 + static inline int xattr_permission_error(int mask) 109 + { 110 + if (mask & MAY_WRITE) 111 + return -EPERM; 112 + return -ENODATA; 113 + } 114 + 109 115 /* 110 116 * Check permissions for extended attribute access. This is a bit complicated 111 117 * because different namespaces have very different rules. ··· 142 134 */ 143 135 if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) { 144 136 if (!capable(CAP_SYS_ADMIN)) 145 - return (mask & MAY_WRITE) ? -EPERM : -ENODATA; 137 + return xattr_permission_error(mask); 146 138 return 0; 147 139 } 148 140 ··· 152 144 * privileged users can write attributes. 153 145 */ 154 146 if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) { 155 - if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) 156 - return (mask & MAY_WRITE) ? -EPERM : -ENODATA; 157 - if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && 158 - (mask & MAY_WRITE) && 159 - !inode_owner_or_capable(idmap, inode)) 147 + switch (inode->i_mode & S_IFMT) { 148 + case S_IFREG: 149 + break; 150 + case S_IFDIR: 151 + if (!(inode->i_mode & S_ISVTX)) 152 + break; 153 + if (!(mask & MAY_WRITE)) 154 + break; 155 + if (inode_owner_or_capable(idmap, inode)) 156 + break; 160 157 return -EPERM; 158 + case S_IFSOCK: 159 + break; 160 + default: 161 + return xattr_permission_error(mask); 162 + } 161 163 } 162 164 163 165 return inode_permission(idmap, inode, mask); ··· 1215 1197 kvfree(xattr); 1216 1198 } 1217 1199 1200 + static void simple_xattr_rcu_free(struct rcu_head *head) 1201 + { 1202 + struct simple_xattr *xattr = container_of(head, struct simple_xattr, rcu); 1203 + 1204 + simple_xattr_free(xattr); 1205 + } 1206 + 1207 + /** 1208 + * simple_xattr_free_rcu - free an xattr object with RCU delay 1209 + * @xattr: the xattr object 1210 + * 1211 + * Free the xattr object after an RCU grace period. This must be used when 1212 + * the xattr was removed from a data structure that concurrent RCU readers 1213 + * may still be traversing. Can handle @xattr being NULL. 1214 + */ 1215 + void simple_xattr_free_rcu(struct simple_xattr *xattr) 1216 + { 1217 + if (xattr) 1218 + call_rcu(&xattr->rcu, simple_xattr_rcu_free); 1219 + } 1220 + 1218 1221 /** 1219 1222 * simple_xattr_alloc - allocate new xattr object 1220 1223 * @value: value of the xattr object ··· 1244 1205 * Allocate a new xattr object and initialize respective members. The caller is 1245 1206 * responsible for handling the name of the xattr. 1246 1207 * 1247 - * Return: On success a new xattr object is returned. On failure NULL is 1248 - * returned. 1208 + * Return: New xattr object on success, NULL if @value is NULL, ERR_PTR on 1209 + * failure. 1249 1210 */ 1250 1211 struct simple_xattr *simple_xattr_alloc(const void *value, size_t size) 1251 1212 { 1252 1213 struct simple_xattr *new_xattr; 1253 1214 size_t len; 1254 1215 1216 + if (!value) 1217 + return NULL; 1218 + 1255 1219 /* wrap around? */ 1256 1220 len = sizeof(*new_xattr) + size; 1257 1221 if (len < sizeof(*new_xattr)) 1258 - return NULL; 1222 + return ERR_PTR(-ENOMEM); 1259 1223 1260 1224 new_xattr = kvmalloc(len, GFP_KERNEL_ACCOUNT); 1261 1225 if (!new_xattr) 1262 - return NULL; 1226 + return ERR_PTR(-ENOMEM); 1263 1227 1264 1228 new_xattr->size = size; 1265 1229 memcpy(new_xattr->value, value, size); 1266 1230 return new_xattr; 1267 1231 } 1268 1232 1269 - /** 1270 - * rbtree_simple_xattr_cmp - compare xattr name with current rbtree xattr entry 1271 - * @key: xattr name 1272 - * @node: current node 1273 - * 1274 - * Compare the xattr name with the xattr name attached to @node in the rbtree. 1275 - * 1276 - * Return: Negative value if continuing left, positive if continuing right, 0 1277 - * if the xattr attached to @node matches @key. 1278 - */ 1279 - static int rbtree_simple_xattr_cmp(const void *key, const struct rb_node *node) 1233 + static u32 simple_xattr_hashfn(const void *data, u32 len, u32 seed) 1280 1234 { 1281 - const char *xattr_name = key; 1282 - const struct simple_xattr *xattr; 1283 - 1284 - xattr = rb_entry(node, struct simple_xattr, rb_node); 1285 - return strcmp(xattr->name, xattr_name); 1235 + const char *name = data; 1236 + return jhash(name, strlen(name), seed); 1286 1237 } 1287 1238 1288 - /** 1289 - * rbtree_simple_xattr_node_cmp - compare two xattr rbtree nodes 1290 - * @new_node: new node 1291 - * @node: current node 1292 - * 1293 - * Compare the xattr attached to @new_node with the xattr attached to @node. 1294 - * 1295 - * Return: Negative value if continuing left, positive if continuing right, 0 1296 - * if the xattr attached to @new_node matches the xattr attached to @node. 1297 - */ 1298 - static int rbtree_simple_xattr_node_cmp(struct rb_node *new_node, 1299 - const struct rb_node *node) 1239 + static u32 simple_xattr_obj_hashfn(const void *obj, u32 len, u32 seed) 1300 1240 { 1301 - struct simple_xattr *xattr; 1302 - xattr = rb_entry(new_node, struct simple_xattr, rb_node); 1303 - return rbtree_simple_xattr_cmp(xattr->name, node); 1241 + const struct simple_xattr *xattr = obj; 1242 + return jhash(xattr->name, strlen(xattr->name), seed); 1304 1243 } 1244 + 1245 + static int simple_xattr_obj_cmpfn(struct rhashtable_compare_arg *arg, 1246 + const void *obj) 1247 + { 1248 + const struct simple_xattr *xattr = obj; 1249 + return strcmp(xattr->name, arg->key); 1250 + } 1251 + 1252 + static const struct rhashtable_params simple_xattr_params = { 1253 + .head_offset = offsetof(struct simple_xattr, hash_node), 1254 + .hashfn = simple_xattr_hashfn, 1255 + .obj_hashfn = simple_xattr_obj_hashfn, 1256 + .obj_cmpfn = simple_xattr_obj_cmpfn, 1257 + .automatic_shrinking = true, 1258 + }; 1305 1259 1306 1260 /** 1307 1261 * simple_xattr_get - get an xattr object ··· 1314 1282 int simple_xattr_get(struct simple_xattrs *xattrs, const char *name, 1315 1283 void *buffer, size_t size) 1316 1284 { 1317 - struct simple_xattr *xattr = NULL; 1318 - struct rb_node *rbp; 1285 + struct simple_xattr *xattr; 1319 1286 int ret = -ENODATA; 1320 1287 1321 - read_lock(&xattrs->lock); 1322 - rbp = rb_find(name, &xattrs->rb_root, rbtree_simple_xattr_cmp); 1323 - if (rbp) { 1324 - xattr = rb_entry(rbp, struct simple_xattr, rb_node); 1288 + guard(rcu)(); 1289 + xattr = rhashtable_lookup(&xattrs->ht, name, simple_xattr_params); 1290 + if (xattr) { 1325 1291 ret = xattr->size; 1326 1292 if (buffer) { 1327 1293 if (size < xattr->size) ··· 1328 1298 memcpy(buffer, xattr->value, xattr->size); 1329 1299 } 1330 1300 } 1331 - read_unlock(&xattrs->lock); 1332 1301 return ret; 1333 1302 } 1334 1303 ··· 1354 1325 * nothing if XATTR_CREATE is specified in @flags or @flags is zero. For 1355 1326 * XATTR_REPLACE we fail as mentioned above. 1356 1327 * 1328 + * Note: Callers must externally serialize writes. All current callers hold 1329 + * the inode lock for write operations. The lookup->replace/remove sequence 1330 + * is not atomic with respect to the rhashtable's per-bucket locking, but 1331 + * is safe because writes are serialized by the caller. 1332 + * 1357 1333 * Return: On success, the removed or replaced xattr is returned, to be freed 1358 1334 * by the caller; or NULL if none. On failure a negative error code is returned. 1359 1335 */ ··· 1366 1332 const char *name, const void *value, 1367 1333 size_t size, int flags) 1368 1334 { 1369 - struct simple_xattr *old_xattr = NULL, *new_xattr = NULL; 1370 - struct rb_node *parent = NULL, **rbp; 1371 - int err = 0, ret; 1335 + struct simple_xattr *old_xattr = NULL; 1336 + int err; 1372 1337 1373 - /* value == NULL means remove */ 1374 - if (value) { 1375 - new_xattr = simple_xattr_alloc(value, size); 1376 - if (!new_xattr) 1377 - return ERR_PTR(-ENOMEM); 1338 + CLASS(simple_xattr, new_xattr)(value, size); 1339 + if (IS_ERR(new_xattr)) 1340 + return new_xattr; 1378 1341 1342 + if (new_xattr) { 1379 1343 new_xattr->name = kstrdup(name, GFP_KERNEL_ACCOUNT); 1380 - if (!new_xattr->name) { 1381 - simple_xattr_free(new_xattr); 1344 + if (!new_xattr->name) 1382 1345 return ERR_PTR(-ENOMEM); 1383 - } 1384 1346 } 1385 1347 1386 - write_lock(&xattrs->lock); 1387 - rbp = &xattrs->rb_root.rb_node; 1388 - while (*rbp) { 1389 - parent = *rbp; 1390 - ret = rbtree_simple_xattr_cmp(name, *rbp); 1391 - if (ret < 0) 1392 - rbp = &(*rbp)->rb_left; 1393 - else if (ret > 0) 1394 - rbp = &(*rbp)->rb_right; 1395 - else 1396 - old_xattr = rb_entry(*rbp, struct simple_xattr, rb_node); 1397 - if (old_xattr) 1398 - break; 1399 - } 1348 + /* Lookup is safe without RCU here since writes are serialized. */ 1349 + old_xattr = rhashtable_lookup_fast(&xattrs->ht, name, 1350 + simple_xattr_params); 1400 1351 1401 1352 if (old_xattr) { 1402 1353 /* Fail if XATTR_CREATE is requested and the xattr exists. */ 1403 - if (flags & XATTR_CREATE) { 1404 - err = -EEXIST; 1405 - goto out_unlock; 1406 - } 1354 + if (flags & XATTR_CREATE) 1355 + return ERR_PTR(-EEXIST); 1407 1356 1408 - if (new_xattr) 1409 - rb_replace_node(&old_xattr->rb_node, 1410 - &new_xattr->rb_node, &xattrs->rb_root); 1411 - else 1412 - rb_erase(&old_xattr->rb_node, &xattrs->rb_root); 1357 + if (new_xattr) { 1358 + err = rhashtable_replace_fast(&xattrs->ht, 1359 + &old_xattr->hash_node, 1360 + &new_xattr->hash_node, 1361 + simple_xattr_params); 1362 + if (err) 1363 + return ERR_PTR(err); 1364 + } else { 1365 + err = rhashtable_remove_fast(&xattrs->ht, 1366 + &old_xattr->hash_node, 1367 + simple_xattr_params); 1368 + if (err) 1369 + return ERR_PTR(err); 1370 + } 1413 1371 } else { 1414 1372 /* Fail if XATTR_REPLACE is requested but no xattr is found. */ 1415 - if (flags & XATTR_REPLACE) { 1416 - err = -ENODATA; 1417 - goto out_unlock; 1418 - } 1373 + if (flags & XATTR_REPLACE) 1374 + return ERR_PTR(-ENODATA); 1419 1375 1420 1376 /* 1421 1377 * If XATTR_CREATE or no flags are specified together with a 1422 1378 * new value simply insert it. 1423 1379 */ 1424 1380 if (new_xattr) { 1425 - rb_link_node(&new_xattr->rb_node, parent, rbp); 1426 - rb_insert_color(&new_xattr->rb_node, &xattrs->rb_root); 1381 + err = rhashtable_insert_fast(&xattrs->ht, 1382 + &new_xattr->hash_node, 1383 + simple_xattr_params); 1384 + if (err) 1385 + return ERR_PTR(err); 1427 1386 } 1428 1387 1429 1388 /* ··· 1425 1398 */ 1426 1399 } 1427 1400 1428 - out_unlock: 1429 - write_unlock(&xattrs->lock); 1430 - if (!err) 1431 - return old_xattr; 1432 - simple_xattr_free(new_xattr); 1433 - return ERR_PTR(err); 1401 + retain_and_null_ptr(new_xattr); 1402 + return old_xattr; 1403 + } 1404 + 1405 + static inline void simple_xattr_limits_dec(struct simple_xattr_limits *limits, 1406 + size_t size) 1407 + { 1408 + atomic_sub(size, &limits->xattr_size); 1409 + atomic_dec(&limits->nr_xattrs); 1410 + } 1411 + 1412 + static inline int simple_xattr_limits_inc(struct simple_xattr_limits *limits, 1413 + size_t size) 1414 + { 1415 + if (atomic_inc_return(&limits->nr_xattrs) > SIMPLE_XATTR_MAX_NR) { 1416 + atomic_dec(&limits->nr_xattrs); 1417 + return -ENOSPC; 1418 + } 1419 + 1420 + if (atomic_add_return(size, &limits->xattr_size) <= SIMPLE_XATTR_MAX_SIZE) 1421 + return 0; 1422 + 1423 + simple_xattr_limits_dec(limits, size); 1424 + return -ENOSPC; 1425 + } 1426 + 1427 + /** 1428 + * simple_xattr_set_limited - set an xattr with per-inode user.* limits 1429 + * @xattrs: the header of the xattr object 1430 + * @limits: per-inode limit counters for user.* xattrs 1431 + * @name: the name of the xattr to set or remove 1432 + * @value: the value to store (NULL to remove) 1433 + * @size: the size of @value 1434 + * @flags: XATTR_CREATE, XATTR_REPLACE, or 0 1435 + * 1436 + * Like simple_xattr_set(), but enforces per-inode count and total value size 1437 + * limits for user.* xattrs. Uses speculative pre-increment of the atomic 1438 + * counters to avoid races without requiring external locks. 1439 + * 1440 + * Return: On success zero is returned. On failure a negative error code is 1441 + * returned. 1442 + */ 1443 + int simple_xattr_set_limited(struct simple_xattrs *xattrs, 1444 + struct simple_xattr_limits *limits, 1445 + const char *name, const void *value, 1446 + size_t size, int flags) 1447 + { 1448 + struct simple_xattr *old_xattr; 1449 + int ret; 1450 + 1451 + if (value) { 1452 + ret = simple_xattr_limits_inc(limits, size); 1453 + if (ret) 1454 + return ret; 1455 + } 1456 + 1457 + old_xattr = simple_xattr_set(xattrs, name, value, size, flags); 1458 + if (IS_ERR(old_xattr)) { 1459 + if (value) 1460 + simple_xattr_limits_dec(limits, size); 1461 + return PTR_ERR(old_xattr); 1462 + } 1463 + if (old_xattr) { 1464 + simple_xattr_limits_dec(limits, old_xattr->size); 1465 + simple_xattr_free_rcu(old_xattr); 1466 + } 1467 + return 0; 1434 1468 } 1435 1469 1436 1470 static bool xattr_is_trusted(const char *name) ··· 1531 1443 char *buffer, size_t size) 1532 1444 { 1533 1445 bool trusted = ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN); 1446 + struct rhashtable_iter iter; 1534 1447 struct simple_xattr *xattr; 1535 - struct rb_node *rbp; 1536 1448 ssize_t remaining_size = size; 1537 1449 int err = 0; 1538 1450 ··· 1552 1464 remaining_size -= err; 1553 1465 err = 0; 1554 1466 1555 - read_lock(&xattrs->lock); 1556 - for (rbp = rb_first(&xattrs->rb_root); rbp; rbp = rb_next(rbp)) { 1557 - xattr = rb_entry(rbp, struct simple_xattr, rb_node); 1467 + if (!xattrs) 1468 + return size - remaining_size; 1469 + 1470 + rhashtable_walk_enter(&xattrs->ht, &iter); 1471 + rhashtable_walk_start(&iter); 1472 + 1473 + while ((xattr = rhashtable_walk_next(&iter)) != NULL) { 1474 + if (IS_ERR(xattr)) { 1475 + if (PTR_ERR(xattr) == -EAGAIN) 1476 + continue; 1477 + err = PTR_ERR(xattr); 1478 + break; 1479 + } 1558 1480 1559 1481 /* skip "trusted." attributes for unprivileged callers */ 1560 1482 if (!trusted && xattr_is_trusted(xattr->name)) ··· 1578 1480 if (err) 1579 1481 break; 1580 1482 } 1581 - read_unlock(&xattrs->lock); 1483 + 1484 + rhashtable_walk_stop(&iter); 1485 + rhashtable_walk_exit(&iter); 1582 1486 1583 1487 return err ? err : size - remaining_size; 1584 - } 1585 - 1586 - /** 1587 - * rbtree_simple_xattr_less - compare two xattr rbtree nodes 1588 - * @new_node: new node 1589 - * @node: current node 1590 - * 1591 - * Compare the xattr attached to @new_node with the xattr attached to @node. 1592 - * Note that this function technically tolerates duplicate entries. 1593 - * 1594 - * Return: True if insertion point in the rbtree is found. 1595 - */ 1596 - static bool rbtree_simple_xattr_less(struct rb_node *new_node, 1597 - const struct rb_node *node) 1598 - { 1599 - return rbtree_simple_xattr_node_cmp(new_node, node) < 0; 1600 1488 } 1601 1489 1602 1490 /** ··· 1593 1509 * Add an xattr object to @xattrs. This assumes no replacement or removal 1594 1510 * of matching xattrs is wanted. Should only be called during inode 1595 1511 * initialization when a few distinct initial xattrs are supposed to be set. 1512 + * 1513 + * Return: On success zero is returned. On failure a negative error code is 1514 + * returned. 1596 1515 */ 1597 - void simple_xattr_add(struct simple_xattrs *xattrs, 1598 - struct simple_xattr *new_xattr) 1516 + int simple_xattr_add(struct simple_xattrs *xattrs, 1517 + struct simple_xattr *new_xattr) 1599 1518 { 1600 - write_lock(&xattrs->lock); 1601 - rb_add(&new_xattr->rb_node, &xattrs->rb_root, rbtree_simple_xattr_less); 1602 - write_unlock(&xattrs->lock); 1519 + return rhashtable_insert_fast(&xattrs->ht, &new_xattr->hash_node, 1520 + simple_xattr_params); 1603 1521 } 1604 1522 1605 1523 /** 1606 1524 * simple_xattrs_init - initialize new xattr header 1607 1525 * @xattrs: header to initialize 1608 1526 * 1609 - * Initialize relevant fields of a an xattr header. 1527 + * Initialize the rhashtable used to store xattr objects. 1528 + * 1529 + * Return: On success zero is returned. On failure a negative error code is 1530 + * returned. 1610 1531 */ 1611 - void simple_xattrs_init(struct simple_xattrs *xattrs) 1532 + int simple_xattrs_init(struct simple_xattrs *xattrs) 1612 1533 { 1613 - xattrs->rb_root = RB_ROOT; 1614 - rwlock_init(&xattrs->lock); 1534 + return rhashtable_init(&xattrs->ht, &simple_xattr_params); 1535 + } 1536 + 1537 + /** 1538 + * simple_xattrs_alloc - allocate and initialize a new xattr header 1539 + * 1540 + * Dynamically allocate a simple_xattrs header and initialize the 1541 + * underlying rhashtable. This is intended for consumers that want 1542 + * to lazily allocate xattr storage only when the first xattr is set, 1543 + * avoiding the per-inode rhashtable overhead when no xattrs are used. 1544 + * 1545 + * Return: On success a new simple_xattrs is returned. On failure an 1546 + * ERR_PTR is returned. 1547 + */ 1548 + struct simple_xattrs *simple_xattrs_alloc(void) 1549 + { 1550 + struct simple_xattrs *xattrs __free(kfree) = NULL; 1551 + int ret; 1552 + 1553 + xattrs = kzalloc(sizeof(*xattrs), GFP_KERNEL); 1554 + if (!xattrs) 1555 + return ERR_PTR(-ENOMEM); 1556 + 1557 + ret = simple_xattrs_init(xattrs); 1558 + if (ret) 1559 + return ERR_PTR(ret); 1560 + 1561 + return no_free_ptr(xattrs); 1562 + } 1563 + 1564 + /** 1565 + * simple_xattrs_lazy_alloc - get or allocate xattrs for a set operation 1566 + * @xattrsp: pointer to the xattrs pointer (may point to NULL) 1567 + * @value: value being set (NULL means remove) 1568 + * @flags: xattr set flags 1569 + * 1570 + * For lazily-allocated xattrs on the write path. If no xattrs exist yet 1571 + * and this is a remove operation, returns the appropriate result without 1572 + * allocating. Otherwise ensures xattrs is allocated and published with 1573 + * store-release semantics. 1574 + * 1575 + * Return: On success a valid pointer to the xattrs is returned. On 1576 + * failure or early-exit an ERR_PTR or NULL is returned. Callers should 1577 + * check with IS_ERR_OR_NULL() and propagate with PTR_ERR() which 1578 + * correctly returns 0 for the NULL no-op case. 1579 + */ 1580 + struct simple_xattrs *simple_xattrs_lazy_alloc(struct simple_xattrs **xattrsp, 1581 + const void *value, int flags) 1582 + { 1583 + struct simple_xattrs *xattrs; 1584 + 1585 + xattrs = READ_ONCE(*xattrsp); 1586 + if (xattrs) 1587 + return xattrs; 1588 + 1589 + if (!value) 1590 + return (flags & XATTR_REPLACE) ? ERR_PTR(-ENODATA) : NULL; 1591 + 1592 + xattrs = simple_xattrs_alloc(); 1593 + if (!IS_ERR(xattrs)) 1594 + smp_store_release(xattrsp, xattrs); 1595 + return xattrs; 1596 + } 1597 + 1598 + static void simple_xattr_ht_free(void *ptr, void *arg) 1599 + { 1600 + struct simple_xattr *xattr = ptr; 1601 + size_t *freed_space = arg; 1602 + 1603 + if (freed_space) 1604 + *freed_space += simple_xattr_space(xattr->name, xattr->size); 1605 + simple_xattr_free(xattr); 1615 1606 } 1616 1607 1617 1608 /** ··· 1699 1540 */ 1700 1541 void simple_xattrs_free(struct simple_xattrs *xattrs, size_t *freed_space) 1701 1542 { 1702 - struct rb_node *rbp; 1543 + might_sleep(); 1703 1544 1704 1545 if (freed_space) 1705 1546 *freed_space = 0; 1706 - rbp = rb_first(&xattrs->rb_root); 1707 - while (rbp) { 1708 - struct simple_xattr *xattr; 1709 - struct rb_node *rbp_next; 1710 - 1711 - rbp_next = rb_next(rbp); 1712 - xattr = rb_entry(rbp, struct simple_xattr, rb_node); 1713 - rb_erase(&xattr->rb_node, &xattrs->rb_root); 1714 - if (freed_space) 1715 - *freed_space += simple_xattr_space(xattr->name, 1716 - xattr->size); 1717 - simple_xattr_free(xattr); 1718 - rbp = rbp_next; 1719 - } 1547 + rhashtable_free_and_destroy(&xattrs->ht, simple_xattr_ht_free, 1548 + freed_space); 1720 1549 }
-2
include/linux/kernfs.h
··· 100 100 101 101 #define KERNFS_TYPE_MASK 0x000f 102 102 #define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK 103 - #define KERNFS_MAX_USER_XATTRS 128 104 - #define KERNFS_USER_XATTR_SIZE_LIMIT (128 << 10) 105 103 106 104 enum kernfs_node_flag { 107 105 KERNFS_ACTIVATED = 0x0010,
+1 -1
include/linux/shmem_fs.h
··· 48 48 }; 49 49 struct timespec64 i_crtime; /* file creation time */ 50 50 struct shared_policy policy; /* NUMA memory alloc policy */ 51 - struct simple_xattrs xattrs; /* list of xattrs */ 51 + struct simple_xattrs *xattrs; /* list of xattrs */ 52 52 pgoff_t fallocend; /* highest fallocate endindex */ 53 53 unsigned int fsflags; /* for FS_IOC_[SG]ETFLAGS */ 54 54 atomic_t stop_eviction; /* hold when working on inode */
+41 -6
include/linux/xattr.h
··· 16 16 #include <linux/types.h> 17 17 #include <linux/spinlock.h> 18 18 #include <linux/mm.h> 19 + #include <linux/rhashtable-types.h> 19 20 #include <linux/user_namespace.h> 20 21 #include <uapi/linux/xattr.h> 21 22 ··· 107 106 } 108 107 109 108 struct simple_xattrs { 110 - struct rb_root rb_root; 111 - rwlock_t lock; 109 + struct rhashtable ht; 112 110 }; 113 111 114 112 struct simple_xattr { 115 - struct rb_node rb_node; 113 + struct rhash_head hash_node; 114 + struct rcu_head rcu; 116 115 char *name; 117 116 size_t size; 118 117 char value[] __counted_by(size); 119 118 }; 120 119 121 - void simple_xattrs_init(struct simple_xattrs *xattrs); 120 + #define SIMPLE_XATTR_MAX_NR 128 121 + #define SIMPLE_XATTR_MAX_SIZE (128 << 10) 122 + 123 + struct simple_xattr_limits { 124 + atomic_t nr_xattrs; /* current user.* xattr count */ 125 + atomic_t xattr_size; /* current total user.* value bytes */ 126 + }; 127 + 128 + static inline void simple_xattr_limits_init(struct simple_xattr_limits *limits) 129 + { 130 + atomic_set(&limits->nr_xattrs, 0); 131 + atomic_set(&limits->xattr_size, 0); 132 + } 133 + 134 + int simple_xattrs_init(struct simple_xattrs *xattrs); 135 + struct simple_xattrs *simple_xattrs_alloc(void); 136 + struct simple_xattrs *simple_xattrs_lazy_alloc(struct simple_xattrs **xattrsp, 137 + const void *value, int flags); 122 138 void simple_xattrs_free(struct simple_xattrs *xattrs, size_t *freed_space); 123 139 size_t simple_xattr_space(const char *name, size_t size); 124 140 struct simple_xattr *simple_xattr_alloc(const void *value, size_t size); 125 141 void simple_xattr_free(struct simple_xattr *xattr); 142 + void simple_xattr_free_rcu(struct simple_xattr *xattr); 126 143 int simple_xattr_get(struct simple_xattrs *xattrs, const char *name, 127 144 void *buffer, size_t size); 128 145 struct simple_xattr *simple_xattr_set(struct simple_xattrs *xattrs, 129 146 const char *name, const void *value, 130 147 size_t size, int flags); 148 + int simple_xattr_set_limited(struct simple_xattrs *xattrs, 149 + struct simple_xattr_limits *limits, 150 + const char *name, const void *value, 151 + size_t size, int flags); 131 152 ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, 132 153 char *buffer, size_t size); 133 - void simple_xattr_add(struct simple_xattrs *xattrs, 134 - struct simple_xattr *new_xattr); 154 + int simple_xattr_add(struct simple_xattrs *xattrs, 155 + struct simple_xattr *new_xattr); 135 156 int xattr_list_one(char **buffer, ssize_t *remaining_size, const char *name); 157 + 158 + DEFINE_CLASS(simple_xattr, 159 + struct simple_xattr *, 160 + if (!IS_ERR_OR_NULL(_T)) simple_xattr_free(_T), 161 + simple_xattr_alloc(value, size), 162 + const void *value, size_t size) 163 + 164 + DEFINE_CLASS(simple_xattrs, 165 + struct simple_xattrs *, 166 + if (!IS_ERR_OR_NULL(_T)) { simple_xattrs_free(_T, NULL); kfree(_T); }, 167 + simple_xattrs_alloc(), 168 + void) 136 169 137 170 #endif /* _LINUX_XATTR_H */
+32 -14
mm/shmem.c
··· 1425 1425 } 1426 1426 } 1427 1427 1428 - simple_xattrs_free(&info->xattrs, sbinfo->max_inodes ? &freed : NULL); 1428 + if (info->xattrs) { 1429 + simple_xattrs_free(info->xattrs, sbinfo->max_inodes ? &freed : NULL); 1430 + kfree(info->xattrs); 1431 + } 1429 1432 shmem_free_inode(inode->i_sb, freed); 1430 1433 WARN_ON(inode->i_blocks); 1431 1434 clear_inode(inode); ··· 3104 3101 shmem_set_inode_flags(inode, info->fsflags, NULL); 3105 3102 INIT_LIST_HEAD(&info->shrinklist); 3106 3103 INIT_LIST_HEAD(&info->swaplist); 3107 - simple_xattrs_init(&info->xattrs); 3108 3104 cache_no_acl(inode); 3109 3105 if (sbinfo->noswap) 3110 3106 mapping_set_unevictable(inode->i_mapping); ··· 4257 4255 struct shmem_inode_info *info = SHMEM_I(inode); 4258 4256 struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); 4259 4257 const struct xattr *xattr; 4260 - struct simple_xattr *new_xattr; 4261 4258 size_t ispace = 0; 4262 4259 size_t len; 4260 + 4261 + CLASS(simple_xattrs, xattrs)(); 4262 + if (IS_ERR(xattrs)) 4263 + return PTR_ERR(xattrs); 4263 4264 4264 4265 if (sbinfo->max_inodes) { 4265 4266 for (xattr = xattr_array; xattr->name != NULL; xattr++) { ··· 4282 4277 } 4283 4278 4284 4279 for (xattr = xattr_array; xattr->name != NULL; xattr++) { 4285 - new_xattr = simple_xattr_alloc(xattr->value, xattr->value_len); 4286 - if (!new_xattr) 4280 + CLASS(simple_xattr, new_xattr)(xattr->value, xattr->value_len); 4281 + if (IS_ERR(new_xattr)) 4287 4282 break; 4288 4283 4289 4284 len = strlen(xattr->name) + 1; 4290 4285 new_xattr->name = kmalloc(XATTR_SECURITY_PREFIX_LEN + len, 4291 4286 GFP_KERNEL_ACCOUNT); 4292 - if (!new_xattr->name) { 4293 - kvfree(new_xattr); 4287 + if (!new_xattr->name) 4294 4288 break; 4295 - } 4296 4289 4297 4290 memcpy(new_xattr->name, XATTR_SECURITY_PREFIX, 4298 4291 XATTR_SECURITY_PREFIX_LEN); 4299 4292 memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN, 4300 4293 xattr->name, len); 4301 4294 4302 - simple_xattr_add(&info->xattrs, new_xattr); 4295 + if (simple_xattr_add(xattrs, new_xattr)) 4296 + break; 4297 + retain_and_null_ptr(new_xattr); 4303 4298 } 4304 4299 4305 4300 if (xattr->name != NULL) { ··· 4308 4303 sbinfo->free_ispace += ispace; 4309 4304 raw_spin_unlock(&sbinfo->stat_lock); 4310 4305 } 4311 - simple_xattrs_free(&info->xattrs, NULL); 4312 4306 return -ENOMEM; 4313 4307 } 4314 4308 4309 + smp_store_release(&info->xattrs, no_free_ptr(xattrs)); 4315 4310 return 0; 4316 4311 } 4317 4312 ··· 4320 4315 const char *name, void *buffer, size_t size) 4321 4316 { 4322 4317 struct shmem_inode_info *info = SHMEM_I(inode); 4318 + struct simple_xattrs *xattrs; 4319 + 4320 + xattrs = READ_ONCE(info->xattrs); 4321 + if (!xattrs) 4322 + return -ENODATA; 4323 4323 4324 4324 name = xattr_full_name(handler, name); 4325 - return simple_xattr_get(&info->xattrs, name, buffer, size); 4325 + return simple_xattr_get(xattrs, name, buffer, size); 4326 4326 } 4327 4327 4328 4328 static int shmem_xattr_handler_set(const struct xattr_handler *handler, ··· 4338 4328 { 4339 4329 struct shmem_inode_info *info = SHMEM_I(inode); 4340 4330 struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); 4331 + struct simple_xattrs *xattrs; 4341 4332 struct simple_xattr *old_xattr; 4342 4333 size_t ispace = 0; 4343 4334 4344 4335 name = xattr_full_name(handler, name); 4336 + 4337 + xattrs = simple_xattrs_lazy_alloc(&info->xattrs, value, flags); 4338 + if (IS_ERR_OR_NULL(xattrs)) 4339 + return PTR_ERR(xattrs); 4340 + 4345 4341 if (value && sbinfo->max_inodes) { 4346 4342 ispace = simple_xattr_space(name, size); 4347 4343 raw_spin_lock(&sbinfo->stat_lock); ··· 4360 4344 return -ENOSPC; 4361 4345 } 4362 4346 4363 - old_xattr = simple_xattr_set(&info->xattrs, name, value, size, flags); 4347 + old_xattr = simple_xattr_set(xattrs, name, value, size, flags); 4364 4348 if (!IS_ERR(old_xattr)) { 4365 4349 ispace = 0; 4366 4350 if (old_xattr && sbinfo->max_inodes) 4367 4351 ispace = simple_xattr_space(old_xattr->name, 4368 4352 old_xattr->size); 4369 - simple_xattr_free(old_xattr); 4353 + simple_xattr_free_rcu(old_xattr); 4370 4354 old_xattr = NULL; 4371 4355 inode_set_ctime_current(inode); 4372 4356 inode_inc_iversion(inode); ··· 4407 4391 static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size) 4408 4392 { 4409 4393 struct shmem_inode_info *info = SHMEM_I(d_inode(dentry)); 4410 - return simple_xattr_list(d_inode(dentry), &info->xattrs, buffer, size); 4394 + 4395 + return simple_xattr_list(d_inode(dentry), READ_ONCE(info->xattrs), 4396 + buffer, size); 4411 4397 } 4412 4398 #endif /* CONFIG_TMPFS_XATTR */ 4413 4399
+92 -27
net/socket.c
··· 315 315 316 316 static struct kmem_cache *sock_inode_cachep __ro_after_init; 317 317 318 + struct sockfs_inode { 319 + struct simple_xattrs *xattrs; 320 + struct simple_xattr_limits xattr_limits; 321 + struct socket_alloc; 322 + }; 323 + 324 + static struct sockfs_inode *SOCKFS_I(struct inode *inode) 325 + { 326 + return container_of(inode, struct sockfs_inode, vfs_inode); 327 + } 328 + 318 329 static struct inode *sock_alloc_inode(struct super_block *sb) 319 330 { 320 - struct socket_alloc *ei; 331 + struct sockfs_inode *si; 321 332 322 - ei = alloc_inode_sb(sb, sock_inode_cachep, GFP_KERNEL); 323 - if (!ei) 333 + si = alloc_inode_sb(sb, sock_inode_cachep, GFP_KERNEL); 334 + if (!si) 324 335 return NULL; 325 - init_waitqueue_head(&ei->socket.wq.wait); 326 - ei->socket.wq.fasync_list = NULL; 327 - ei->socket.wq.flags = 0; 336 + si->xattrs = NULL; 337 + simple_xattr_limits_init(&si->xattr_limits); 328 338 329 - ei->socket.state = SS_UNCONNECTED; 330 - ei->socket.flags = 0; 331 - ei->socket.ops = NULL; 332 - ei->socket.sk = NULL; 333 - ei->socket.file = NULL; 339 + init_waitqueue_head(&si->socket.wq.wait); 340 + si->socket.wq.fasync_list = NULL; 341 + si->socket.wq.flags = 0; 334 342 335 - return &ei->vfs_inode; 343 + si->socket.state = SS_UNCONNECTED; 344 + si->socket.flags = 0; 345 + si->socket.ops = NULL; 346 + si->socket.sk = NULL; 347 + si->socket.file = NULL; 348 + 349 + return &si->vfs_inode; 350 + } 351 + 352 + static void sock_evict_inode(struct inode *inode) 353 + { 354 + struct sockfs_inode *si = SOCKFS_I(inode); 355 + struct simple_xattrs *xattrs = si->xattrs; 356 + 357 + if (xattrs) { 358 + simple_xattrs_free(xattrs, NULL); 359 + kfree(xattrs); 360 + } 361 + clear_inode(inode); 336 362 } 337 363 338 364 static void sock_free_inode(struct inode *inode) 339 365 { 340 - struct socket_alloc *ei; 366 + struct sockfs_inode *si = SOCKFS_I(inode); 341 367 342 - ei = container_of(inode, struct socket_alloc, vfs_inode); 343 - kmem_cache_free(sock_inode_cachep, ei); 368 + kmem_cache_free(sock_inode_cachep, si); 344 369 } 345 370 346 371 static void init_once(void *foo) 347 372 { 348 - struct socket_alloc *ei = (struct socket_alloc *)foo; 373 + struct sockfs_inode *si = (struct sockfs_inode *)foo; 349 374 350 - inode_init_once(&ei->vfs_inode); 375 + inode_init_once(&si->vfs_inode); 351 376 } 352 377 353 378 static void init_inodecache(void) 354 379 { 355 380 sock_inode_cachep = kmem_cache_create("sock_inode_cache", 356 - sizeof(struct socket_alloc), 381 + sizeof(struct sockfs_inode), 357 382 0, 358 383 (SLAB_HWCACHE_ALIGN | 359 384 SLAB_RECLAIM_ACCOUNT | ··· 390 365 static const struct super_operations sockfs_ops = { 391 366 .alloc_inode = sock_alloc_inode, 392 367 .free_inode = sock_free_inode, 368 + .evict_inode = sock_evict_inode, 393 369 .statfs = simple_statfs, 394 370 }; 395 371 ··· 443 417 .set = sockfs_security_xattr_set, 444 418 }; 445 419 420 + static int sockfs_user_xattr_get(const struct xattr_handler *handler, 421 + struct dentry *dentry, struct inode *inode, 422 + const char *suffix, void *value, size_t size) 423 + { 424 + const char *name = xattr_full_name(handler, suffix); 425 + struct simple_xattrs *xattrs; 426 + 427 + xattrs = READ_ONCE(SOCKFS_I(inode)->xattrs); 428 + if (!xattrs) 429 + return -ENODATA; 430 + 431 + return simple_xattr_get(xattrs, name, value, size); 432 + } 433 + 434 + static int sockfs_user_xattr_set(const struct xattr_handler *handler, 435 + struct mnt_idmap *idmap, 436 + struct dentry *dentry, struct inode *inode, 437 + const char *suffix, const void *value, 438 + size_t size, int flags) 439 + { 440 + const char *name = xattr_full_name(handler, suffix); 441 + struct sockfs_inode *si = SOCKFS_I(inode); 442 + struct simple_xattrs *xattrs; 443 + 444 + xattrs = simple_xattrs_lazy_alloc(&si->xattrs, value, flags); 445 + if (IS_ERR_OR_NULL(xattrs)) 446 + return PTR_ERR(xattrs); 447 + 448 + return simple_xattr_set_limited(xattrs, &si->xattr_limits, 449 + name, value, size, flags); 450 + } 451 + 452 + static const struct xattr_handler sockfs_user_xattr_handler = { 453 + .prefix = XATTR_USER_PREFIX, 454 + .get = sockfs_user_xattr_get, 455 + .set = sockfs_user_xattr_set, 456 + }; 457 + 446 458 static const struct xattr_handler * const sockfs_xattr_handlers[] = { 447 459 &sockfs_xattr_handler, 448 460 &sockfs_security_xattr_handler, 461 + &sockfs_user_xattr_handler, 449 462 NULL 450 463 }; 451 464 ··· 637 572 static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer, 638 573 size_t size) 639 574 { 640 - ssize_t len; 641 - ssize_t used = 0; 575 + struct sockfs_inode *si = SOCKFS_I(d_inode(dentry)); 576 + ssize_t len, used; 642 577 643 - len = security_inode_listsecurity(d_inode(dentry), buffer, size); 578 + len = simple_xattr_list(d_inode(dentry), READ_ONCE(si->xattrs), 579 + buffer, size); 644 580 if (len < 0) 645 581 return len; 646 - used += len; 582 + 583 + used = len; 647 584 if (buffer) { 648 - if (size < used) 649 - return -ERANGE; 650 585 buffer += len; 586 + size -= len; 651 587 } 652 588 653 - len = (XATTR_NAME_SOCKPROTONAME_LEN + 1); 589 + len = XATTR_NAME_SOCKPROTONAME_LEN + 1; 654 590 used += len; 655 591 if (buffer) { 656 - if (size < used) 592 + if (size < len) 657 593 return -ERANGE; 658 594 memcpy(buffer, XATTR_NAME_SOCKPROTONAME, len); 659 - buffer += len; 660 595 } 661 596 662 597 return used;
+3
tools/testing/selftests/filesystems/xattr/.gitignore
··· 1 + xattr_socket_test 2 + xattr_sockfs_test 3 + xattr_socket_types_test
+6
tools/testing/selftests/filesystems/xattr/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + CFLAGS += $(KHDR_INCLUDES) 4 + TEST_GEN_PROGS := xattr_socket_test xattr_sockfs_test xattr_socket_types_test 5 + 6 + include ../../lib.mk
+470
tools/testing/selftests/filesystems/xattr/xattr_socket_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (c) 2026 Christian Brauner <brauner@kernel.org> 3 + /* 4 + * Test extended attributes on path-based Unix domain sockets. 5 + * 6 + * Path-based Unix domain sockets are bound to a filesystem path and their 7 + * inodes live on the underlying filesystem (e.g. tmpfs). These tests verify 8 + * that user.* and trusted.* xattr operations work correctly on them using 9 + * path-based syscalls (setxattr, getxattr, etc.). 10 + * 11 + * Covers SOCK_STREAM, SOCK_DGRAM, and SOCK_SEQPACKET socket types. 12 + */ 13 + 14 + #define _GNU_SOURCE 15 + #include <errno.h> 16 + #include <limits.h> 17 + #include <stdio.h> 18 + #include <stdlib.h> 19 + #include <string.h> 20 + #include <sys/socket.h> 21 + #include <sys/stat.h> 22 + #include <sys/types.h> 23 + #include <sys/un.h> 24 + #include <sys/xattr.h> 25 + #include <unistd.h> 26 + 27 + #include "../../kselftest_harness.h" 28 + 29 + #define TEST_XATTR_NAME "user.testattr" 30 + #define TEST_XATTR_VALUE "testvalue" 31 + #define TEST_XATTR_VALUE2 "newvalue" 32 + 33 + /* 34 + * Fixture for path-based Unix domain socket tests. 35 + * Creates a SOCK_STREAM socket bound to a path in /tmp (typically tmpfs). 36 + */ 37 + FIXTURE(xattr_socket) 38 + { 39 + char socket_path[PATH_MAX]; 40 + int sockfd; 41 + }; 42 + 43 + FIXTURE_VARIANT(xattr_socket) 44 + { 45 + int sock_type; 46 + const char *name; 47 + }; 48 + 49 + FIXTURE_VARIANT_ADD(xattr_socket, stream) { 50 + .sock_type = SOCK_STREAM, 51 + .name = "stream", 52 + }; 53 + 54 + FIXTURE_VARIANT_ADD(xattr_socket, dgram) { 55 + .sock_type = SOCK_DGRAM, 56 + .name = "dgram", 57 + }; 58 + 59 + FIXTURE_VARIANT_ADD(xattr_socket, seqpacket) { 60 + .sock_type = SOCK_SEQPACKET, 61 + .name = "seqpacket", 62 + }; 63 + 64 + FIXTURE_SETUP(xattr_socket) 65 + { 66 + struct sockaddr_un addr; 67 + int ret; 68 + 69 + self->sockfd = -1; 70 + 71 + snprintf(self->socket_path, sizeof(self->socket_path), 72 + "/tmp/xattr_socket_test_%s.%d", variant->name, getpid()); 73 + unlink(self->socket_path); 74 + 75 + self->sockfd = socket(AF_UNIX, variant->sock_type, 0); 76 + ASSERT_GE(self->sockfd, 0) { 77 + TH_LOG("Failed to create socket: %s", strerror(errno)); 78 + } 79 + 80 + memset(&addr, 0, sizeof(addr)); 81 + addr.sun_family = AF_UNIX; 82 + strncpy(addr.sun_path, self->socket_path, sizeof(addr.sun_path) - 1); 83 + 84 + ret = bind(self->sockfd, (struct sockaddr *)&addr, sizeof(addr)); 85 + ASSERT_EQ(ret, 0) { 86 + TH_LOG("Failed to bind socket to %s: %s", 87 + self->socket_path, strerror(errno)); 88 + } 89 + } 90 + 91 + FIXTURE_TEARDOWN(xattr_socket) 92 + { 93 + if (self->sockfd >= 0) 94 + close(self->sockfd); 95 + unlink(self->socket_path); 96 + } 97 + 98 + TEST_F(xattr_socket, set_user_xattr) 99 + { 100 + int ret; 101 + 102 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 103 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 104 + ASSERT_EQ(ret, 0) { 105 + TH_LOG("setxattr failed: %s (errno=%d)", strerror(errno), errno); 106 + } 107 + } 108 + 109 + TEST_F(xattr_socket, get_user_xattr) 110 + { 111 + char buf[256]; 112 + ssize_t ret; 113 + 114 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 115 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 116 + ASSERT_EQ(ret, 0) { 117 + TH_LOG("setxattr failed: %s", strerror(errno)); 118 + } 119 + 120 + memset(buf, 0, sizeof(buf)); 121 + ret = getxattr(self->socket_path, TEST_XATTR_NAME, buf, sizeof(buf)); 122 + ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE)) { 123 + TH_LOG("getxattr returned %zd, expected %zu: %s", 124 + ret, strlen(TEST_XATTR_VALUE), strerror(errno)); 125 + } 126 + ASSERT_STREQ(buf, TEST_XATTR_VALUE); 127 + } 128 + 129 + TEST_F(xattr_socket, list_user_xattr) 130 + { 131 + char list[1024]; 132 + ssize_t ret; 133 + bool found = false; 134 + char *ptr; 135 + 136 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 137 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 138 + ASSERT_EQ(ret, 0) { 139 + TH_LOG("setxattr failed: %s", strerror(errno)); 140 + } 141 + 142 + memset(list, 0, sizeof(list)); 143 + ret = listxattr(self->socket_path, list, sizeof(list)); 144 + ASSERT_GT(ret, 0) { 145 + TH_LOG("listxattr failed: %s", strerror(errno)); 146 + } 147 + 148 + for (ptr = list; ptr < list + ret; ptr += strlen(ptr) + 1) { 149 + if (strcmp(ptr, TEST_XATTR_NAME) == 0) { 150 + found = true; 151 + break; 152 + } 153 + } 154 + ASSERT_TRUE(found) { 155 + TH_LOG("xattr %s not found in list", TEST_XATTR_NAME); 156 + } 157 + } 158 + 159 + TEST_F(xattr_socket, remove_user_xattr) 160 + { 161 + char buf[256]; 162 + ssize_t ret; 163 + 164 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 165 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 166 + ASSERT_EQ(ret, 0) { 167 + TH_LOG("setxattr failed: %s", strerror(errno)); 168 + } 169 + 170 + ret = removexattr(self->socket_path, TEST_XATTR_NAME); 171 + ASSERT_EQ(ret, 0) { 172 + TH_LOG("removexattr failed: %s", strerror(errno)); 173 + } 174 + 175 + ret = getxattr(self->socket_path, TEST_XATTR_NAME, buf, sizeof(buf)); 176 + ASSERT_EQ(ret, -1); 177 + ASSERT_EQ(errno, ENODATA) { 178 + TH_LOG("Expected ENODATA, got %s", strerror(errno)); 179 + } 180 + } 181 + 182 + /* 183 + * Test that xattrs persist across socket close and reopen. 184 + * The xattr is on the filesystem inode, not the socket fd. 185 + */ 186 + TEST_F(xattr_socket, xattr_persistence) 187 + { 188 + char buf[256]; 189 + ssize_t ret; 190 + 191 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 192 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 193 + ASSERT_EQ(ret, 0) { 194 + TH_LOG("setxattr failed: %s", strerror(errno)); 195 + } 196 + 197 + close(self->sockfd); 198 + self->sockfd = -1; 199 + 200 + memset(buf, 0, sizeof(buf)); 201 + ret = getxattr(self->socket_path, TEST_XATTR_NAME, buf, sizeof(buf)); 202 + ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE)) { 203 + TH_LOG("getxattr after close failed: %s", strerror(errno)); 204 + } 205 + ASSERT_STREQ(buf, TEST_XATTR_VALUE); 206 + } 207 + 208 + TEST_F(xattr_socket, update_user_xattr) 209 + { 210 + char buf[256]; 211 + ssize_t ret; 212 + 213 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 214 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 215 + ASSERT_EQ(ret, 0); 216 + 217 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 218 + TEST_XATTR_VALUE2, strlen(TEST_XATTR_VALUE2), 0); 219 + ASSERT_EQ(ret, 0); 220 + 221 + memset(buf, 0, sizeof(buf)); 222 + ret = getxattr(self->socket_path, TEST_XATTR_NAME, buf, sizeof(buf)); 223 + ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE2)); 224 + ASSERT_STREQ(buf, TEST_XATTR_VALUE2); 225 + } 226 + 227 + TEST_F(xattr_socket, xattr_create_flag) 228 + { 229 + int ret; 230 + 231 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 232 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 233 + ASSERT_EQ(ret, 0); 234 + 235 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 236 + TEST_XATTR_VALUE2, strlen(TEST_XATTR_VALUE2), XATTR_CREATE); 237 + ASSERT_EQ(ret, -1); 238 + ASSERT_EQ(errno, EEXIST); 239 + } 240 + 241 + TEST_F(xattr_socket, xattr_replace_flag) 242 + { 243 + int ret; 244 + 245 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 246 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), XATTR_REPLACE); 247 + ASSERT_EQ(ret, -1); 248 + ASSERT_EQ(errno, ENODATA); 249 + } 250 + 251 + TEST_F(xattr_socket, multiple_xattrs) 252 + { 253 + char buf[256]; 254 + ssize_t ret; 255 + int i; 256 + char name[64], value[64]; 257 + const int num_xattrs = 5; 258 + 259 + for (i = 0; i < num_xattrs; i++) { 260 + snprintf(name, sizeof(name), "user.test%d", i); 261 + snprintf(value, sizeof(value), "value%d", i); 262 + ret = setxattr(self->socket_path, name, value, strlen(value), 0); 263 + ASSERT_EQ(ret, 0) { 264 + TH_LOG("setxattr %s failed: %s", name, strerror(errno)); 265 + } 266 + } 267 + 268 + for (i = 0; i < num_xattrs; i++) { 269 + snprintf(name, sizeof(name), "user.test%d", i); 270 + snprintf(value, sizeof(value), "value%d", i); 271 + memset(buf, 0, sizeof(buf)); 272 + ret = getxattr(self->socket_path, name, buf, sizeof(buf)); 273 + ASSERT_EQ(ret, (ssize_t)strlen(value)); 274 + ASSERT_STREQ(buf, value); 275 + } 276 + } 277 + 278 + TEST_F(xattr_socket, xattr_empty_value) 279 + { 280 + char buf[256]; 281 + ssize_t ret; 282 + 283 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, "", 0, 0); 284 + ASSERT_EQ(ret, 0); 285 + 286 + ret = getxattr(self->socket_path, TEST_XATTR_NAME, buf, sizeof(buf)); 287 + ASSERT_EQ(ret, 0); 288 + } 289 + 290 + TEST_F(xattr_socket, xattr_get_size) 291 + { 292 + ssize_t ret; 293 + 294 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 295 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 296 + ASSERT_EQ(ret, 0); 297 + 298 + ret = getxattr(self->socket_path, TEST_XATTR_NAME, NULL, 0); 299 + ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE)); 300 + } 301 + 302 + TEST_F(xattr_socket, xattr_buffer_too_small) 303 + { 304 + char buf[2]; 305 + ssize_t ret; 306 + 307 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 308 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 309 + ASSERT_EQ(ret, 0); 310 + 311 + ret = getxattr(self->socket_path, TEST_XATTR_NAME, buf, sizeof(buf)); 312 + ASSERT_EQ(ret, -1); 313 + ASSERT_EQ(errno, ERANGE); 314 + } 315 + 316 + TEST_F(xattr_socket, xattr_nonexistent) 317 + { 318 + char buf[256]; 319 + ssize_t ret; 320 + 321 + ret = getxattr(self->socket_path, "user.nonexistent", buf, sizeof(buf)); 322 + ASSERT_EQ(ret, -1); 323 + ASSERT_EQ(errno, ENODATA); 324 + } 325 + 326 + TEST_F(xattr_socket, remove_nonexistent_xattr) 327 + { 328 + int ret; 329 + 330 + ret = removexattr(self->socket_path, "user.nonexistent"); 331 + ASSERT_EQ(ret, -1); 332 + ASSERT_EQ(errno, ENODATA); 333 + } 334 + 335 + TEST_F(xattr_socket, large_xattr_value) 336 + { 337 + char large_value[4096]; 338 + char read_buf[4096]; 339 + ssize_t ret; 340 + 341 + memset(large_value, 'A', sizeof(large_value)); 342 + 343 + ret = setxattr(self->socket_path, TEST_XATTR_NAME, 344 + large_value, sizeof(large_value), 0); 345 + ASSERT_EQ(ret, 0) { 346 + TH_LOG("setxattr with large value failed: %s", strerror(errno)); 347 + } 348 + 349 + memset(read_buf, 0, sizeof(read_buf)); 350 + ret = getxattr(self->socket_path, TEST_XATTR_NAME, 351 + read_buf, sizeof(read_buf)); 352 + ASSERT_EQ(ret, (ssize_t)sizeof(large_value)); 353 + ASSERT_EQ(memcmp(large_value, read_buf, sizeof(large_value)), 0); 354 + } 355 + 356 + /* 357 + * Test lsetxattr/lgetxattr (don't follow symlinks). 358 + * Socket files aren't symlinks, so this should work the same. 359 + */ 360 + TEST_F(xattr_socket, lsetxattr_lgetxattr) 361 + { 362 + char buf[256]; 363 + ssize_t ret; 364 + 365 + ret = lsetxattr(self->socket_path, TEST_XATTR_NAME, 366 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 367 + ASSERT_EQ(ret, 0) { 368 + TH_LOG("lsetxattr failed: %s", strerror(errno)); 369 + } 370 + 371 + memset(buf, 0, sizeof(buf)); 372 + ret = lgetxattr(self->socket_path, TEST_XATTR_NAME, buf, sizeof(buf)); 373 + ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE)); 374 + ASSERT_STREQ(buf, TEST_XATTR_VALUE); 375 + } 376 + 377 + /* 378 + * Fixture for trusted.* xattr tests. 379 + * These require CAP_SYS_ADMIN. 380 + */ 381 + FIXTURE(xattr_socket_trusted) 382 + { 383 + char socket_path[PATH_MAX]; 384 + int sockfd; 385 + }; 386 + 387 + FIXTURE_VARIANT(xattr_socket_trusted) 388 + { 389 + int sock_type; 390 + const char *name; 391 + }; 392 + 393 + FIXTURE_VARIANT_ADD(xattr_socket_trusted, stream) { 394 + .sock_type = SOCK_STREAM, 395 + .name = "stream", 396 + }; 397 + 398 + FIXTURE_VARIANT_ADD(xattr_socket_trusted, dgram) { 399 + .sock_type = SOCK_DGRAM, 400 + .name = "dgram", 401 + }; 402 + 403 + FIXTURE_VARIANT_ADD(xattr_socket_trusted, seqpacket) { 404 + .sock_type = SOCK_SEQPACKET, 405 + .name = "seqpacket", 406 + }; 407 + 408 + FIXTURE_SETUP(xattr_socket_trusted) 409 + { 410 + struct sockaddr_un addr; 411 + int ret; 412 + 413 + self->sockfd = -1; 414 + 415 + snprintf(self->socket_path, sizeof(self->socket_path), 416 + "/tmp/xattr_socket_trusted_%s.%d", variant->name, getpid()); 417 + unlink(self->socket_path); 418 + 419 + self->sockfd = socket(AF_UNIX, variant->sock_type, 0); 420 + ASSERT_GE(self->sockfd, 0); 421 + 422 + memset(&addr, 0, sizeof(addr)); 423 + addr.sun_family = AF_UNIX; 424 + strncpy(addr.sun_path, self->socket_path, sizeof(addr.sun_path) - 1); 425 + 426 + ret = bind(self->sockfd, (struct sockaddr *)&addr, sizeof(addr)); 427 + ASSERT_EQ(ret, 0); 428 + } 429 + 430 + FIXTURE_TEARDOWN(xattr_socket_trusted) 431 + { 432 + if (self->sockfd >= 0) 433 + close(self->sockfd); 434 + unlink(self->socket_path); 435 + } 436 + 437 + TEST_F(xattr_socket_trusted, set_trusted_xattr) 438 + { 439 + char buf[256]; 440 + ssize_t len; 441 + int ret; 442 + 443 + ret = setxattr(self->socket_path, "trusted.testattr", 444 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 445 + if (ret == -1 && errno == EPERM) 446 + SKIP(return, "Need CAP_SYS_ADMIN for trusted.* xattrs"); 447 + ASSERT_EQ(ret, 0) { 448 + TH_LOG("setxattr trusted.testattr failed: %s", strerror(errno)); 449 + } 450 + 451 + memset(buf, 0, sizeof(buf)); 452 + len = getxattr(self->socket_path, "trusted.testattr", 453 + buf, sizeof(buf)); 454 + ASSERT_EQ(len, (ssize_t)strlen(TEST_XATTR_VALUE)); 455 + ASSERT_STREQ(buf, TEST_XATTR_VALUE); 456 + } 457 + 458 + TEST_F(xattr_socket_trusted, get_trusted_xattr_unprivileged) 459 + { 460 + char buf[256]; 461 + ssize_t ret; 462 + 463 + ret = getxattr(self->socket_path, "trusted.testattr", buf, sizeof(buf)); 464 + ASSERT_EQ(ret, -1); 465 + ASSERT_TRUE(errno == ENODATA || errno == EPERM) { 466 + TH_LOG("Expected ENODATA or EPERM, got %s", strerror(errno)); 467 + } 468 + } 469 + 470 + TEST_HARNESS_MAIN
+177
tools/testing/selftests/filesystems/xattr/xattr_socket_types_test.c
··· 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
+363
tools/testing/selftests/filesystems/xattr/xattr_sockfs_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (c) 2026 Christian Brauner <brauner@kernel.org> 3 + /* 4 + * Test extended attributes on sockfs sockets. 5 + * 6 + * Sockets created via socket() have their inodes in sockfs, which supports 7 + * user.* xattrs with per-inode limits: up to 128 xattrs and 128KB total 8 + * value size. These tests verify xattr operations via fsetxattr/fgetxattr/ 9 + * flistxattr/fremovexattr on the socket fd, as well as limit enforcement. 10 + */ 11 + 12 + #define _GNU_SOURCE 13 + #include <errno.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/xattr.h> 20 + #include <unistd.h> 21 + 22 + #include "../../kselftest_harness.h" 23 + 24 + #define TEST_XATTR_NAME "user.testattr" 25 + #define TEST_XATTR_VALUE "testvalue" 26 + #define TEST_XATTR_VALUE2 "newvalue" 27 + 28 + /* Per-inode limits for user.* xattrs on sockfs (from include/linux/xattr.h) */ 29 + #define SIMPLE_XATTR_MAX_NR 128 30 + #define SIMPLE_XATTR_MAX_SIZE (128 << 10) /* 128 KB */ 31 + 32 + #ifndef XATTR_SIZE_MAX 33 + #define XATTR_SIZE_MAX 65536 34 + #endif 35 + 36 + /* 37 + * Fixture for sockfs socket xattr tests. 38 + * Creates an AF_UNIX socket (lives in sockfs, not bound to any path). 39 + */ 40 + FIXTURE(xattr_sockfs) 41 + { 42 + int sockfd; 43 + }; 44 + 45 + FIXTURE_SETUP(xattr_sockfs) 46 + { 47 + self->sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 48 + ASSERT_GE(self->sockfd, 0) { 49 + TH_LOG("Failed to create socket: %s", strerror(errno)); 50 + } 51 + } 52 + 53 + FIXTURE_TEARDOWN(xattr_sockfs) 54 + { 55 + if (self->sockfd >= 0) 56 + close(self->sockfd); 57 + } 58 + 59 + TEST_F(xattr_sockfs, set_get_user_xattr) 60 + { 61 + char buf[256]; 62 + ssize_t ret; 63 + 64 + ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, 65 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 66 + ASSERT_EQ(ret, 0) { 67 + TH_LOG("fsetxattr failed: %s", strerror(errno)); 68 + } 69 + 70 + memset(buf, 0, sizeof(buf)); 71 + ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf)); 72 + ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE)) { 73 + TH_LOG("fgetxattr returned %zd: %s", ret, strerror(errno)); 74 + } 75 + ASSERT_STREQ(buf, TEST_XATTR_VALUE); 76 + } 77 + 78 + /* 79 + * Test listing xattrs on a sockfs socket. 80 + * Should include user.* xattrs and system.sockprotoname. 81 + */ 82 + TEST_F(xattr_sockfs, list_user_xattr) 83 + { 84 + char list[4096]; 85 + ssize_t ret; 86 + char *ptr; 87 + bool found_user = false; 88 + bool found_proto = false; 89 + 90 + ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, 91 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 92 + ASSERT_EQ(ret, 0) { 93 + TH_LOG("fsetxattr failed: %s", strerror(errno)); 94 + } 95 + 96 + memset(list, 0, sizeof(list)); 97 + ret = flistxattr(self->sockfd, list, sizeof(list)); 98 + ASSERT_GT(ret, 0) { 99 + TH_LOG("flistxattr failed: %s", strerror(errno)); 100 + } 101 + 102 + for (ptr = list; ptr < list + ret; ptr += strlen(ptr) + 1) { 103 + if (strcmp(ptr, TEST_XATTR_NAME) == 0) 104 + found_user = true; 105 + if (strcmp(ptr, "system.sockprotoname") == 0) 106 + found_proto = true; 107 + } 108 + ASSERT_TRUE(found_user) { 109 + TH_LOG("user xattr not found in list"); 110 + } 111 + ASSERT_TRUE(found_proto) { 112 + TH_LOG("system.sockprotoname not found in list"); 113 + } 114 + } 115 + 116 + TEST_F(xattr_sockfs, remove_user_xattr) 117 + { 118 + char buf[256]; 119 + ssize_t ret; 120 + 121 + ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, 122 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 123 + ASSERT_EQ(ret, 0); 124 + 125 + ret = fremovexattr(self->sockfd, TEST_XATTR_NAME); 126 + ASSERT_EQ(ret, 0) { 127 + TH_LOG("fremovexattr failed: %s", strerror(errno)); 128 + } 129 + 130 + ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf)); 131 + ASSERT_EQ(ret, -1); 132 + ASSERT_EQ(errno, ENODATA); 133 + } 134 + 135 + TEST_F(xattr_sockfs, update_user_xattr) 136 + { 137 + char buf[256]; 138 + ssize_t ret; 139 + 140 + ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, 141 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 142 + ASSERT_EQ(ret, 0); 143 + 144 + ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, 145 + TEST_XATTR_VALUE2, strlen(TEST_XATTR_VALUE2), 0); 146 + ASSERT_EQ(ret, 0); 147 + 148 + memset(buf, 0, sizeof(buf)); 149 + ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf)); 150 + ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE2)); 151 + ASSERT_STREQ(buf, TEST_XATTR_VALUE2); 152 + } 153 + 154 + TEST_F(xattr_sockfs, xattr_create_flag) 155 + { 156 + int ret; 157 + 158 + ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, 159 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 160 + ASSERT_EQ(ret, 0); 161 + 162 + ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, 163 + TEST_XATTR_VALUE2, strlen(TEST_XATTR_VALUE2), 164 + XATTR_CREATE); 165 + ASSERT_EQ(ret, -1); 166 + ASSERT_EQ(errno, EEXIST); 167 + } 168 + 169 + TEST_F(xattr_sockfs, xattr_replace_flag) 170 + { 171 + int ret; 172 + 173 + ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, 174 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 175 + XATTR_REPLACE); 176 + ASSERT_EQ(ret, -1); 177 + ASSERT_EQ(errno, ENODATA); 178 + } 179 + 180 + TEST_F(xattr_sockfs, get_nonexistent) 181 + { 182 + char buf[256]; 183 + ssize_t ret; 184 + 185 + ret = fgetxattr(self->sockfd, "user.nonexistent", buf, sizeof(buf)); 186 + ASSERT_EQ(ret, -1); 187 + ASSERT_EQ(errno, ENODATA); 188 + } 189 + 190 + TEST_F(xattr_sockfs, empty_value) 191 + { 192 + ssize_t ret; 193 + 194 + ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, "", 0, 0); 195 + ASSERT_EQ(ret, 0); 196 + 197 + ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, NULL, 0); 198 + ASSERT_EQ(ret, 0); 199 + } 200 + 201 + TEST_F(xattr_sockfs, get_size) 202 + { 203 + ssize_t ret; 204 + 205 + ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, 206 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 207 + ASSERT_EQ(ret, 0); 208 + 209 + ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, NULL, 0); 210 + ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE)); 211 + } 212 + 213 + TEST_F(xattr_sockfs, buffer_too_small) 214 + { 215 + char buf[2]; 216 + ssize_t ret; 217 + 218 + ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, 219 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 220 + ASSERT_EQ(ret, 0); 221 + 222 + ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf)); 223 + ASSERT_EQ(ret, -1); 224 + ASSERT_EQ(errno, ERANGE); 225 + } 226 + 227 + /* 228 + * Test maximum number of user.* xattrs per socket. 229 + * The kernel enforces SIMPLE_XATTR_MAX_NR (128), so the 129th should 230 + * fail with ENOSPC. 231 + */ 232 + TEST_F(xattr_sockfs, max_nr_xattrs) 233 + { 234 + char name[32]; 235 + int i, ret; 236 + 237 + for (i = 0; i < SIMPLE_XATTR_MAX_NR; i++) { 238 + snprintf(name, sizeof(name), "user.test%03d", i); 239 + ret = fsetxattr(self->sockfd, name, "v", 1, 0); 240 + ASSERT_EQ(ret, 0) { 241 + TH_LOG("fsetxattr %s failed at i=%d: %s", 242 + name, i, strerror(errno)); 243 + } 244 + } 245 + 246 + ret = fsetxattr(self->sockfd, "user.overflow", "v", 1, 0); 247 + ASSERT_EQ(ret, -1); 248 + ASSERT_EQ(errno, ENOSPC) { 249 + TH_LOG("Expected ENOSPC for xattr %d, got %s", 250 + SIMPLE_XATTR_MAX_NR + 1, strerror(errno)); 251 + } 252 + } 253 + 254 + /* 255 + * Test maximum total value size for user.* xattrs. 256 + * The kernel enforces SIMPLE_XATTR_MAX_SIZE (128KB). Individual xattr 257 + * values are limited to XATTR_SIZE_MAX (64KB) by the VFS, so we need 258 + * at least two xattrs to hit the total limit. 259 + */ 260 + TEST_F(xattr_sockfs, max_xattr_size) 261 + { 262 + char *value; 263 + int ret; 264 + 265 + value = malloc(XATTR_SIZE_MAX); 266 + ASSERT_NE(value, NULL); 267 + memset(value, 'A', XATTR_SIZE_MAX); 268 + 269 + /* First 64KB xattr - total = 64KB */ 270 + ret = fsetxattr(self->sockfd, "user.big1", value, XATTR_SIZE_MAX, 0); 271 + ASSERT_EQ(ret, 0) { 272 + TH_LOG("first large xattr failed: %s", strerror(errno)); 273 + } 274 + 275 + /* Second 64KB xattr - total = 128KB (exactly at limit) */ 276 + ret = fsetxattr(self->sockfd, "user.big2", value, XATTR_SIZE_MAX, 0); 277 + free(value); 278 + ASSERT_EQ(ret, 0) { 279 + TH_LOG("second large xattr failed: %s", strerror(errno)); 280 + } 281 + 282 + /* Third xattr with 1 byte - total > 128KB, should fail */ 283 + ret = fsetxattr(self->sockfd, "user.big3", "v", 1, 0); 284 + ASSERT_EQ(ret, -1); 285 + ASSERT_EQ(errno, ENOSPC) { 286 + TH_LOG("Expected ENOSPC when exceeding size limit, got %s", 287 + strerror(errno)); 288 + } 289 + } 290 + 291 + /* 292 + * Test that removing an xattr frees limit space, allowing re-addition. 293 + */ 294 + TEST_F(xattr_sockfs, limit_remove_readd) 295 + { 296 + char name[32]; 297 + int i, ret; 298 + 299 + /* Fill up to the maximum count */ 300 + for (i = 0; i < SIMPLE_XATTR_MAX_NR; i++) { 301 + snprintf(name, sizeof(name), "user.test%03d", i); 302 + ret = fsetxattr(self->sockfd, name, "v", 1, 0); 303 + ASSERT_EQ(ret, 0); 304 + } 305 + 306 + /* Verify we're at the limit */ 307 + ret = fsetxattr(self->sockfd, "user.overflow", "v", 1, 0); 308 + ASSERT_EQ(ret, -1); 309 + ASSERT_EQ(errno, ENOSPC); 310 + 311 + /* Remove one xattr */ 312 + ret = fremovexattr(self->sockfd, "user.test000"); 313 + ASSERT_EQ(ret, 0); 314 + 315 + /* Now we should be able to add one more */ 316 + ret = fsetxattr(self->sockfd, "user.newattr", "v", 1, 0); 317 + ASSERT_EQ(ret, 0) { 318 + TH_LOG("re-add after remove failed: %s", strerror(errno)); 319 + } 320 + } 321 + 322 + /* 323 + * Test that two different sockets have independent xattr limits. 324 + */ 325 + TEST_F(xattr_sockfs, limits_per_inode) 326 + { 327 + char buf[256]; 328 + int sock2; 329 + ssize_t ret; 330 + 331 + sock2 = socket(AF_UNIX, SOCK_STREAM, 0); 332 + ASSERT_GE(sock2, 0); 333 + 334 + /* Set xattr on first socket */ 335 + ret = fsetxattr(self->sockfd, TEST_XATTR_NAME, 336 + TEST_XATTR_VALUE, strlen(TEST_XATTR_VALUE), 0); 337 + ASSERT_EQ(ret, 0); 338 + 339 + /* First socket's xattr should not be visible on second socket */ 340 + ret = fgetxattr(sock2, TEST_XATTR_NAME, NULL, 0); 341 + ASSERT_EQ(ret, -1); 342 + ASSERT_EQ(errno, ENODATA); 343 + 344 + /* Second socket should independently accept xattrs */ 345 + ret = fsetxattr(sock2, TEST_XATTR_NAME, 346 + TEST_XATTR_VALUE2, strlen(TEST_XATTR_VALUE2), 0); 347 + ASSERT_EQ(ret, 0); 348 + 349 + /* Verify each socket has its own value */ 350 + memset(buf, 0, sizeof(buf)); 351 + ret = fgetxattr(self->sockfd, TEST_XATTR_NAME, buf, sizeof(buf)); 352 + ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE)); 353 + ASSERT_STREQ(buf, TEST_XATTR_VALUE); 354 + 355 + memset(buf, 0, sizeof(buf)); 356 + ret = fgetxattr(sock2, TEST_XATTR_NAME, buf, sizeof(buf)); 357 + ASSERT_EQ(ret, (ssize_t)strlen(TEST_XATTR_VALUE2)); 358 + ASSERT_STREQ(buf, TEST_XATTR_VALUE2); 359 + 360 + close(sock2); 361 + } 362 + 363 + TEST_HARNESS_MAIN