1 /* 2 * Squashfs - a compressed read only filesystem for Linux 3 * 4 * Copyright (c) 2010 5 * Phillip Lougher <phillip@lougher.demon.co.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->d_inode; 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(d, buffer, rest, NULL, 72 name_size, handler->flags); 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 /* 216 * User namespace support 217 */ 218 static size_t squashfs_user_list(struct dentry *d, char *list, size_t list_size, 219 const char *name, size_t name_len, int type) 220 { 221 if (list && XATTR_USER_PREFIX_LEN <= list_size) 222 memcpy(list, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); 223 return XATTR_USER_PREFIX_LEN; 224 } 225 226 static int squashfs_user_get(struct dentry *d, const char *name, void *buffer, 227 size_t size, int type) 228 { 229 if (name[0] == '\0') 230 return -EINVAL; 231 232 return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_USER, name, 233 buffer, size); 234 } 235 236 static const struct xattr_handler squashfs_xattr_user_handler = { 237 .prefix = XATTR_USER_PREFIX, 238 .list = squashfs_user_list, 239 .get = squashfs_user_get 240 }; 241 242 /* 243 * Trusted namespace support 244 */ 245 static size_t squashfs_trusted_list(struct dentry *d, char *list, 246 size_t list_size, const char *name, size_t name_len, int type) 247 { 248 if (!capable(CAP_SYS_ADMIN)) 249 return 0; 250 251 if (list && XATTR_TRUSTED_PREFIX_LEN <= list_size) 252 memcpy(list, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN); 253 return XATTR_TRUSTED_PREFIX_LEN; 254 } 255 256 static int squashfs_trusted_get(struct dentry *d, const char *name, 257 void *buffer, size_t size, int type) 258 { 259 if (name[0] == '\0') 260 return -EINVAL; 261 262 return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_TRUSTED, name, 263 buffer, size); 264 } 265 266 static const struct xattr_handler squashfs_xattr_trusted_handler = { 267 .prefix = XATTR_TRUSTED_PREFIX, 268 .list = squashfs_trusted_list, 269 .get = squashfs_trusted_get 270 }; 271 272 /* 273 * Security namespace support 274 */ 275 static size_t squashfs_security_list(struct dentry *d, char *list, 276 size_t list_size, const char *name, size_t name_len, int type) 277 { 278 if (list && XATTR_SECURITY_PREFIX_LEN <= list_size) 279 memcpy(list, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN); 280 return XATTR_SECURITY_PREFIX_LEN; 281 } 282 283 static int squashfs_security_get(struct dentry *d, const char *name, 284 void *buffer, size_t size, int type) 285 { 286 if (name[0] == '\0') 287 return -EINVAL; 288 289 return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_SECURITY, name, 290 buffer, size); 291 } 292 293 static const struct xattr_handler squashfs_xattr_security_handler = { 294 .prefix = XATTR_SECURITY_PREFIX, 295 .list = squashfs_security_list, 296 .get = squashfs_security_get 297 }; 298 299 static const struct xattr_handler *squashfs_xattr_handler(int type) 300 { 301 if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL)) 302 /* ignore unrecognised type */ 303 return NULL; 304 305 switch (type & SQUASHFS_XATTR_PREFIX_MASK) { 306 case SQUASHFS_XATTR_USER: 307 return &squashfs_xattr_user_handler; 308 case SQUASHFS_XATTR_TRUSTED: 309 return &squashfs_xattr_trusted_handler; 310 case SQUASHFS_XATTR_SECURITY: 311 return &squashfs_xattr_security_handler; 312 default: 313 /* ignore unrecognised type */ 314 return NULL; 315 } 316 } 317 318 const struct xattr_handler *squashfs_xattr_handlers[] = { 319 &squashfs_xattr_user_handler, 320 &squashfs_xattr_trusted_handler, 321 &squashfs_xattr_security_handler, 322 NULL 323 }; 324 325