Commit f41d207cbedecd82f797adcce83890aa96f1c9e9

Authored by Phillip Lougher
1 parent 4b5397dc24

squashfs: add support for xattr reading

Add support for listxattr and getxattr.  Also add xattr definitions.

Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>

Showing 4 changed files with 342 additions and 1 deletions Side-by-side Diff

fs/squashfs/Makefile
... ... @@ -5,5 +5,5 @@
5 5 obj-$(CONFIG_SQUASHFS) += squashfs.o
6 6 squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
7 7 squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
8   -squashfs-y += xattr_id.o
  8 +squashfs-y += xattr.o xattr_id.o
fs/squashfs/squashfs_fs.h
... ... @@ -46,6 +46,7 @@
46 46 #define SQUASHFS_NAME_LEN 256
47 47  
48 48 #define SQUASHFS_INVALID_FRAG (0xffffffffU)
  49 +#define SQUASHFS_INVALID_XATTR (0xffffffffU)
49 50 #define SQUASHFS_INVALID_BLK (-1LL)
50 51  
51 52 /* Filesystem flags */
... ... @@ -96,6 +97,13 @@
96 97 #define SQUASHFS_LFIFO_TYPE 13
97 98 #define SQUASHFS_LSOCKET_TYPE 14
98 99  
  100 +/* Xattr types */
  101 +#define SQUASHFS_XATTR_USER 0
  102 +#define SQUASHFS_XATTR_TRUSTED 1
  103 +#define SQUASHFS_XATTR_SECURITY 2
  104 +#define SQUASHFS_XATTR_VALUE_OOL 256
  105 +#define SQUASHFS_XATTR_PREFIX_MASK 0xff
  106 +
99 107 /* Flag whether block is compressed or uncompressed, bit is set if block is
100 108 * uncompressed */
101 109 #define SQUASHFS_COMPRESSED_BIT (1 << 15)
... ... @@ -393,6 +401,17 @@
393 401 __le64 start_block;
394 402 __le32 size;
395 403 unsigned int unused;
  404 +};
  405 +
  406 +struct squashfs_xattr_entry {
  407 + __le16 type;
  408 + __le16 size;
  409 + char data[0];
  410 +};
  411 +
  412 +struct squashfs_xattr_val {
  413 + __le32 vsize;
  414 + char value[0];
396 415 };
397 416  
398 417 struct squashfs_xattr_id {
fs/squashfs/squashfs_fs_i.h
... ... @@ -26,6 +26,9 @@
26 26 struct squashfs_inode_info {
27 27 u64 start;
28 28 int offset;
  29 + u64 xattr;
  30 + unsigned int xattr_size;
  31 + int xattr_count;
29 32 union {
30 33 struct {
31 34 u64 fragment_block;
  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_id.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 inline 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 + 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 + err = squashfs_read_metadata(sb, target, &start, &offset,
  149 + name_size);
  150 + if (err < 0)
  151 + goto failed;
  152 +
  153 + if (prefix == name_index && name_size == name_len &&
  154 + strncmp(target, name, name_size) == 0) {
  155 + /* found xattr */
  156 + if (type & SQUASHFS_XATTR_VALUE_OOL) {
  157 + __le64 xattr;
  158 + /* val is a reference to the real location */
  159 + err = squashfs_read_metadata(sb, &val, &start,
  160 + &offset, sizeof(val));
  161 + if (err < 0)
  162 + goto failed;
  163 + err = squashfs_read_metadata(sb, &xattr, &start,
  164 + &offset, sizeof(xattr));
  165 + if (err < 0)
  166 + goto failed;
  167 + xattr = le64_to_cpu(xattr);
  168 + start = SQUASHFS_XATTR_BLK(xattr) +
  169 + msblk->xattr_table;
  170 + offset = SQUASHFS_XATTR_OFFSET(xattr);
  171 + }
  172 + /* read xattr value */
  173 + err = squashfs_read_metadata(sb, &val, &start, &offset,
  174 + sizeof(val));
  175 + if (err < 0)
  176 + goto failed;
  177 +
  178 + vsize = le32_to_cpu(val.vsize);
  179 + if (buffer) {
  180 + if (vsize > buffer_size) {
  181 + err = -ERANGE;
  182 + goto failed;
  183 + }
  184 + err = squashfs_read_metadata(sb, buffer, &start,
  185 + &offset, vsize);
  186 + if (err < 0)
  187 + goto failed;
  188 + }
  189 + break;
  190 + }
  191 +
  192 + /* no match, skip remaining xattr entry */
  193 + err = squashfs_read_metadata(sb, &val, &start, &offset,
  194 + sizeof(val));
  195 + if (err < 0)
  196 + goto failed;
  197 + err = squashfs_read_metadata(sb, NULL, &start, &offset,
  198 + le32_to_cpu(val.vsize));
  199 + if (err < 0)
  200 + goto failed;
  201 + }
  202 + err = count ? vsize : -ENODATA;
  203 +
  204 +failed:
  205 + kfree(target);
  206 + return err;
  207 +}
  208 +
  209 +
  210 +/*
  211 + * User namespace support
  212 + */
  213 +static size_t squashfs_user_list(struct dentry *d, char *list, size_t list_size,
  214 + const char *name, size_t name_len, int type)
  215 +{
  216 + if (list && XATTR_USER_PREFIX_LEN <= list_size)
  217 + memcpy(list, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
  218 + return XATTR_USER_PREFIX_LEN;
  219 +}
  220 +
  221 +static int squashfs_user_get(struct dentry *d, const char *name, void *buffer,
  222 + size_t size, int type)
  223 +{
  224 + if (name[0] == '\0')
  225 + return -EINVAL;
  226 +
  227 + return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_USER, name,
  228 + buffer, size);
  229 +}
  230 +
  231 +struct xattr_handler squashfs_xattr_user_handler = {
  232 + .prefix = XATTR_USER_PREFIX,
  233 + .list = squashfs_user_list,
  234 + .get = squashfs_user_get
  235 +};
  236 +
  237 +/*
  238 + * Trusted namespace support
  239 + */
  240 +static size_t squashfs_trusted_list(struct dentry *d, char *list,
  241 + size_t list_size, const char *name, size_t name_len, int type)
  242 +{
  243 + if (!capable(CAP_SYS_ADMIN))
  244 + return 0;
  245 +
  246 + if (list && XATTR_TRUSTED_PREFIX_LEN <= list_size)
  247 + memcpy(list, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
  248 + return XATTR_TRUSTED_PREFIX_LEN;
  249 +}
  250 +
  251 +static int squashfs_trusted_get(struct dentry *d, const char *name,
  252 + void *buffer, size_t size, int type)
  253 +{
  254 + if (name[0] == '\0')
  255 + return -EINVAL;
  256 +
  257 + return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_TRUSTED, name,
  258 + buffer, size);
  259 +}
  260 +
  261 +struct xattr_handler squashfs_xattr_trusted_handler = {
  262 + .prefix = XATTR_TRUSTED_PREFIX,
  263 + .list = squashfs_trusted_list,
  264 + .get = squashfs_trusted_get
  265 +};
  266 +
  267 +/*
  268 + * Security namespace support
  269 + */
  270 +static size_t squashfs_security_list(struct dentry *d, char *list,
  271 + size_t list_size, const char *name, size_t name_len, int type)
  272 +{
  273 + if (list && XATTR_SECURITY_PREFIX_LEN <= list_size)
  274 + memcpy(list, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN);
  275 + return XATTR_SECURITY_PREFIX_LEN;
  276 +}
  277 +
  278 +static int squashfs_security_get(struct dentry *d, const char *name,
  279 + void *buffer, size_t size, int type)
  280 +{
  281 + if (name[0] == '\0')
  282 + return -EINVAL;
  283 +
  284 + return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_SECURITY, name,
  285 + buffer, size);
  286 +}
  287 +
  288 +struct xattr_handler squashfs_xattr_security_handler = {
  289 + .prefix = XATTR_SECURITY_PREFIX,
  290 + .list = squashfs_security_list,
  291 + .get = squashfs_security_get
  292 +};
  293 +
  294 +static inline struct xattr_handler *squashfs_xattr_handler(int type)
  295 +{
  296 + if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL))
  297 + /* ignore unrecognised type */
  298 + return NULL;
  299 +
  300 + switch (type & SQUASHFS_XATTR_PREFIX_MASK) {
  301 + case SQUASHFS_XATTR_USER:
  302 + return &squashfs_xattr_user_handler;
  303 + case SQUASHFS_XATTR_TRUSTED:
  304 + return &squashfs_xattr_trusted_handler;
  305 + case SQUASHFS_XATTR_SECURITY:
  306 + return &squashfs_xattr_security_handler;
  307 + default:
  308 + /* ignore unrecognised type */
  309 + return NULL;
  310 + }
  311 +}
  312 +
  313 +struct xattr_handler *squashfs_xattr_handlers[] = {
  314 + &squashfs_xattr_user_handler,
  315 + &squashfs_xattr_trusted_handler,
  316 + &squashfs_xattr_security_handler,
  317 + NULL
  318 +};