linux/fs/squashfs/xattr.c
<<
>>
Prefs
   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
  37static const struct xattr_handler *squashfs_xattr_handler(int);
  38
  39ssize_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(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
 112failed:
 113        return err;
 114}
 115
 116
 117static 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
 209failed:
 210        kfree(target);
 211        return err;
 212}
 213
 214
 215/*
 216 * User namespace support
 217 */
 218static 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
 226static 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_inode(d), SQUASHFS_XATTR_USER, name,
 233                buffer, size);
 234}
 235
 236static 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 */
 245static 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
 256static 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_inode(d), SQUASHFS_XATTR_TRUSTED, name,
 263                buffer, size);
 264}
 265
 266static 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 */
 275static 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
 283static 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_inode(d), SQUASHFS_XATTR_SECURITY, name,
 290                buffer, size);
 291}
 292
 293static 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
 299static 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
 318const 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