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