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, prefix_size = 0; 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) 71 prefix_size = handler->list(handler, d, buffer, rest, 72 NULL, name_size); 73 if (prefix_size) { 74 if (buffer) { 75 if (prefix_size + name_size + 1 > rest) { 76 err = -ERANGE; 77 goto failed; 78 } 79 buffer += prefix_size; 80 } 81 err = squashfs_read_metadata(sb, buffer, &start, 82 &offset, name_size); 83 if (err < 0) 84 goto failed; 85 if (buffer) { 86 buffer[name_size] = '\0'; 87 buffer += name_size + 1; 88 } 89 rest -= prefix_size + name_size + 1; 90 } else { 91 /* no handler or insuffficient privileges, so skip */ 92 err = squashfs_read_metadata(sb, NULL, &start, 93 &offset, name_size); 94 if (err < 0) 95 goto failed; 96 } 97 98 99 /* skip remaining xattr entry */ 100 err = squashfs_read_metadata(sb, &val, &start, &offset, 101 sizeof(val)); 102 if (err < 0) 103 goto failed; 104 105 err = squashfs_read_metadata(sb, NULL, &start, &offset, 106 le32_to_cpu(val.vsize)); 107 if (err < 0) 108 goto failed; 109 } 110 err = buffer_size - rest; 111 112 failed: 113 return err; 114 } 115 116 117 static int squashfs_xattr_get(struct inode *inode, int name_index, 118 const char *name, void *buffer, size_t buffer_size) 119 { 120 struct super_block *sb = inode->i_sb; 121 struct squashfs_sb_info *msblk = sb->s_fs_info; 122 u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr) 123 + msblk->xattr_table; 124 int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr); 125 int count = squashfs_i(inode)->xattr_count; 126 int name_len = strlen(name); 127 int err, vsize; 128 char *target = kmalloc(name_len, GFP_KERNEL); 129 130 if (target == NULL) 131 return -ENOMEM; 132 133 /* loop reading each xattr name */ 134 for (; count; count--) { 135 struct squashfs_xattr_entry entry; 136 struct squashfs_xattr_val val; 137 int type, prefix, name_size; 138 139 err = squashfs_read_metadata(sb, &entry, &start, &offset, 140 sizeof(entry)); 141 if (err < 0) 142 goto failed; 143 144 name_size = le16_to_cpu(entry.size); 145 type = le16_to_cpu(entry.type); 146 prefix = type & SQUASHFS_XATTR_PREFIX_MASK; 147 148 if (prefix == name_index && name_size == name_len) 149 err = squashfs_read_metadata(sb, target, &start, 150 &offset, name_size); 151 else 152 err = squashfs_read_metadata(sb, NULL, &start, 153 &offset, name_size); 154 if (err < 0) 155 goto failed; 156 157 if (prefix == name_index && name_size == name_len && 158 strncmp(target, name, name_size) == 0) { 159 /* found xattr */ 160 if (type & SQUASHFS_XATTR_VALUE_OOL) { 161 __le64 xattr_val; 162 u64 xattr; 163 /* val is a reference to the real location */ 164 err = squashfs_read_metadata(sb, &val, &start, 165 &offset, sizeof(val)); 166 if (err < 0) 167 goto failed; 168 err = squashfs_read_metadata(sb, &xattr_val, 169 &start, &offset, sizeof(xattr_val)); 170 if (err < 0) 171 goto failed; 172 xattr = le64_to_cpu(xattr_val); 173 start = SQUASHFS_XATTR_BLK(xattr) + 174 msblk->xattr_table; 175 offset = SQUASHFS_XATTR_OFFSET(xattr); 176 } 177 /* read xattr value */ 178 err = squashfs_read_metadata(sb, &val, &start, &offset, 179 sizeof(val)); 180 if (err < 0) 181 goto failed; 182 183 vsize = le32_to_cpu(val.vsize); 184 if (buffer) { 185 if (vsize > buffer_size) { 186 err = -ERANGE; 187 goto failed; 188 } 189 err = squashfs_read_metadata(sb, buffer, &start, 190 &offset, vsize); 191 if (err < 0) 192 goto failed; 193 } 194 break; 195 } 196 197 /* no match, skip remaining xattr entry */ 198 err = squashfs_read_metadata(sb, &val, &start, &offset, 199 sizeof(val)); 200 if (err < 0) 201 goto failed; 202 err = squashfs_read_metadata(sb, NULL, &start, &offset, 203 le32_to_cpu(val.vsize)); 204 if (err < 0) 205 goto failed; 206 } 207 err = count ? vsize : -ENODATA; 208 209 failed: 210 kfree(target); 211 return err; 212 } 213 214 215 static size_t squashfs_xattr_handler_list(const struct xattr_handler *handler, 216 struct dentry *d, char *list, 217 size_t list_size, const char *name, 218 size_t name_len) 219 { 220 int len = strlen(handler->prefix); 221 222 if (list && len <= list_size) 223 memcpy(list, handler->prefix, len); 224 return len; 225 } 226 227 static int squashfs_xattr_handler_get(const struct xattr_handler *handler, 228 struct dentry *d, const char *name, 229 void *buffer, size_t size) 230 { 231 if (name[0] == '\0') 232 return -EINVAL; 233 234 return squashfs_xattr_get(d_inode(d), handler->flags, name, 235 buffer, size); 236 } 237 238 /* 239 * User namespace support 240 */ 241 static const struct xattr_handler squashfs_xattr_user_handler = { 242 .prefix = XATTR_USER_PREFIX, 243 .flags = SQUASHFS_XATTR_USER, 244 .list = squashfs_xattr_handler_list, 245 .get = squashfs_xattr_handler_get 246 }; 247 248 /* 249 * Trusted namespace support 250 */ 251 static size_t squashfs_trusted_xattr_handler_list(const struct xattr_handler *handler, 252 struct dentry *d, char *list, 253 size_t list_size, const char *name, 254 size_t name_len) 255 { 256 if (!capable(CAP_SYS_ADMIN)) 257 return 0; 258 return squashfs_xattr_handler_list(handler, d, list, list_size, name, 259 name_len); 260 } 261 262 static const struct xattr_handler squashfs_xattr_trusted_handler = { 263 .prefix = XATTR_TRUSTED_PREFIX, 264 .flags = SQUASHFS_XATTR_TRUSTED, 265 .list = squashfs_trusted_xattr_handler_list, 266 .get = squashfs_xattr_handler_get 267 }; 268 269 /* 270 * Security namespace support 271 */ 272 static const struct xattr_handler squashfs_xattr_security_handler = { 273 .prefix = XATTR_SECURITY_PREFIX, 274 .flags = SQUASHFS_XATTR_SECURITY, 275 .list = squashfs_xattr_handler_list, 276 .get = squashfs_xattr_handler_get 277 }; 278 279 static const struct xattr_handler *squashfs_xattr_handler(int type) 280 { 281 if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL)) 282 /* ignore unrecognised type */ 283 return NULL; 284 285 switch (type & SQUASHFS_XATTR_PREFIX_MASK) { 286 case SQUASHFS_XATTR_USER: 287 return &squashfs_xattr_user_handler; 288 case SQUASHFS_XATTR_TRUSTED: 289 return &squashfs_xattr_trusted_handler; 290 case SQUASHFS_XATTR_SECURITY: 291 return &squashfs_xattr_security_handler; 292 default: 293 /* ignore unrecognised type */ 294 return NULL; 295 } 296 } 297 298 const struct xattr_handler *squashfs_xattr_handlers[] = { 299 &squashfs_xattr_user_handler, 300 &squashfs_xattr_trusted_handler, 301 &squashfs_xattr_security_handler, 302 NULL 303 }; 304 305