xattr.c (6862B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Squashfs - a compressed read only filesystem for Linux 4 * 5 * Copyright (c) 2010 6 * Phillip Lougher <phillip@squashfs.org.uk> 7 * 8 * xattr.c 9 */ 10 11#include <linux/init.h> 12#include <linux/module.h> 13#include <linux/string.h> 14#include <linux/fs.h> 15#include <linux/vfs.h> 16#include <linux/xattr.h> 17#include <linux/slab.h> 18 19#include "squashfs_fs.h" 20#include "squashfs_fs_sb.h" 21#include "squashfs_fs_i.h" 22#include "squashfs.h" 23 24static const struct xattr_handler *squashfs_xattr_handler(int); 25 26ssize_t squashfs_listxattr(struct dentry *d, char *buffer, 27 size_t buffer_size) 28{ 29 struct inode *inode = d_inode(d); 30 struct super_block *sb = inode->i_sb; 31 struct squashfs_sb_info *msblk = sb->s_fs_info; 32 u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr) 33 + msblk->xattr_table; 34 int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr); 35 int count = squashfs_i(inode)->xattr_count; 36 size_t rest = buffer_size; 37 int err; 38 39 /* check that the file system has xattrs */ 40 if (msblk->xattr_id_table == NULL) 41 return -EOPNOTSUPP; 42 43 /* loop reading each xattr name */ 44 while (count--) { 45 struct squashfs_xattr_entry entry; 46 struct squashfs_xattr_val val; 47 const struct xattr_handler *handler; 48 int name_size; 49 50 err = squashfs_read_metadata(sb, &entry, &start, &offset, 51 sizeof(entry)); 52 if (err < 0) 53 goto failed; 54 55 name_size = le16_to_cpu(entry.size); 56 handler = squashfs_xattr_handler(le16_to_cpu(entry.type)); 57 if (handler && (!handler->list || handler->list(d))) { 58 const char *prefix = handler->prefix ?: handler->name; 59 size_t prefix_size = strlen(prefix); 60 61 if (buffer) { 62 if (prefix_size + name_size + 1 > rest) { 63 err = -ERANGE; 64 goto failed; 65 } 66 memcpy(buffer, prefix, prefix_size); 67 buffer += prefix_size; 68 } 69 err = squashfs_read_metadata(sb, buffer, &start, 70 &offset, name_size); 71 if (err < 0) 72 goto failed; 73 if (buffer) { 74 buffer[name_size] = '\0'; 75 buffer += name_size + 1; 76 } 77 rest -= prefix_size + name_size + 1; 78 } else { 79 /* no handler or insuffficient privileges, so skip */ 80 err = squashfs_read_metadata(sb, NULL, &start, 81 &offset, name_size); 82 if (err < 0) 83 goto failed; 84 } 85 86 87 /* skip remaining xattr entry */ 88 err = squashfs_read_metadata(sb, &val, &start, &offset, 89 sizeof(val)); 90 if (err < 0) 91 goto failed; 92 93 err = squashfs_read_metadata(sb, NULL, &start, &offset, 94 le32_to_cpu(val.vsize)); 95 if (err < 0) 96 goto failed; 97 } 98 err = buffer_size - rest; 99 100failed: 101 return err; 102} 103 104 105static int squashfs_xattr_get(struct inode *inode, int name_index, 106 const char *name, void *buffer, size_t buffer_size) 107{ 108 struct super_block *sb = inode->i_sb; 109 struct squashfs_sb_info *msblk = sb->s_fs_info; 110 u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr) 111 + msblk->xattr_table; 112 int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr); 113 int count = squashfs_i(inode)->xattr_count; 114 int name_len = strlen(name); 115 int err, vsize; 116 char *target = kmalloc(name_len, GFP_KERNEL); 117 118 if (target == NULL) 119 return -ENOMEM; 120 121 /* loop reading each xattr name */ 122 for (; count; count--) { 123 struct squashfs_xattr_entry entry; 124 struct squashfs_xattr_val val; 125 int type, prefix, name_size; 126 127 err = squashfs_read_metadata(sb, &entry, &start, &offset, 128 sizeof(entry)); 129 if (err < 0) 130 goto failed; 131 132 name_size = le16_to_cpu(entry.size); 133 type = le16_to_cpu(entry.type); 134 prefix = type & SQUASHFS_XATTR_PREFIX_MASK; 135 136 if (prefix == name_index && name_size == name_len) 137 err = squashfs_read_metadata(sb, target, &start, 138 &offset, name_size); 139 else 140 err = squashfs_read_metadata(sb, NULL, &start, 141 &offset, name_size); 142 if (err < 0) 143 goto failed; 144 145 if (prefix == name_index && name_size == name_len && 146 strncmp(target, name, name_size) == 0) { 147 /* found xattr */ 148 if (type & SQUASHFS_XATTR_VALUE_OOL) { 149 __le64 xattr_val; 150 u64 xattr; 151 /* val is a reference to the real location */ 152 err = squashfs_read_metadata(sb, &val, &start, 153 &offset, sizeof(val)); 154 if (err < 0) 155 goto failed; 156 err = squashfs_read_metadata(sb, &xattr_val, 157 &start, &offset, sizeof(xattr_val)); 158 if (err < 0) 159 goto failed; 160 xattr = le64_to_cpu(xattr_val); 161 start = SQUASHFS_XATTR_BLK(xattr) + 162 msblk->xattr_table; 163 offset = SQUASHFS_XATTR_OFFSET(xattr); 164 } 165 /* read xattr value */ 166 err = squashfs_read_metadata(sb, &val, &start, &offset, 167 sizeof(val)); 168 if (err < 0) 169 goto failed; 170 171 vsize = le32_to_cpu(val.vsize); 172 if (buffer) { 173 if (vsize > buffer_size) { 174 err = -ERANGE; 175 goto failed; 176 } 177 err = squashfs_read_metadata(sb, buffer, &start, 178 &offset, vsize); 179 if (err < 0) 180 goto failed; 181 } 182 break; 183 } 184 185 /* no match, skip remaining xattr entry */ 186 err = squashfs_read_metadata(sb, &val, &start, &offset, 187 sizeof(val)); 188 if (err < 0) 189 goto failed; 190 err = squashfs_read_metadata(sb, NULL, &start, &offset, 191 le32_to_cpu(val.vsize)); 192 if (err < 0) 193 goto failed; 194 } 195 err = count ? vsize : -ENODATA; 196 197failed: 198 kfree(target); 199 return err; 200} 201 202 203static int squashfs_xattr_handler_get(const struct xattr_handler *handler, 204 struct dentry *unused, 205 struct inode *inode, 206 const char *name, 207 void *buffer, size_t size) 208{ 209 return squashfs_xattr_get(inode, handler->flags, name, 210 buffer, size); 211} 212 213/* 214 * User namespace support 215 */ 216static const struct xattr_handler squashfs_xattr_user_handler = { 217 .prefix = XATTR_USER_PREFIX, 218 .flags = SQUASHFS_XATTR_USER, 219 .get = squashfs_xattr_handler_get 220}; 221 222/* 223 * Trusted namespace support 224 */ 225static bool squashfs_trusted_xattr_handler_list(struct dentry *d) 226{ 227 return capable(CAP_SYS_ADMIN); 228} 229 230static const struct xattr_handler squashfs_xattr_trusted_handler = { 231 .prefix = XATTR_TRUSTED_PREFIX, 232 .flags = SQUASHFS_XATTR_TRUSTED, 233 .list = squashfs_trusted_xattr_handler_list, 234 .get = squashfs_xattr_handler_get 235}; 236 237/* 238 * Security namespace support 239 */ 240static const struct xattr_handler squashfs_xattr_security_handler = { 241 .prefix = XATTR_SECURITY_PREFIX, 242 .flags = SQUASHFS_XATTR_SECURITY, 243 .get = squashfs_xattr_handler_get 244}; 245 246static const struct xattr_handler *squashfs_xattr_handler(int type) 247{ 248 if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL)) 249 /* ignore unrecognised type */ 250 return NULL; 251 252 switch (type & SQUASHFS_XATTR_PREFIX_MASK) { 253 case SQUASHFS_XATTR_USER: 254 return &squashfs_xattr_user_handler; 255 case SQUASHFS_XATTR_TRUSTED: 256 return &squashfs_xattr_trusted_handler; 257 case SQUASHFS_XATTR_SECURITY: 258 return &squashfs_xattr_security_handler; 259 default: 260 /* ignore unrecognised type */ 261 return NULL; 262 } 263} 264 265const struct xattr_handler *squashfs_xattr_handlers[] = { 266 &squashfs_xattr_user_handler, 267 &squashfs_xattr_trusted_handler, 268 &squashfs_xattr_security_handler, 269 NULL 270}; 271