Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Squashfs - a compressed read only filesystem for Linux
0004  *
0005  * Copyright (c) 2010
0006  * Phillip Lougher <phillip@squashfs.org.uk>
0007  *
0008  * xattr.c
0009  */
0010 
0011 #include <linux/init.h>
0012 #include <linux/module.h>
0013 #include <linux/string.h>
0014 #include <linux/fs.h>
0015 #include <linux/vfs.h>
0016 #include <linux/xattr.h>
0017 #include <linux/slab.h>
0018 
0019 #include "squashfs_fs.h"
0020 #include "squashfs_fs_sb.h"
0021 #include "squashfs_fs_i.h"
0022 #include "squashfs.h"
0023 
0024 static const struct xattr_handler *squashfs_xattr_handler(int);
0025 
0026 ssize_t squashfs_listxattr(struct dentry *d, char *buffer,
0027     size_t buffer_size)
0028 {
0029     struct inode *inode = d_inode(d);
0030     struct super_block *sb = inode->i_sb;
0031     struct squashfs_sb_info *msblk = sb->s_fs_info;
0032     u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr)
0033                          + msblk->xattr_table;
0034     int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr);
0035     int count = squashfs_i(inode)->xattr_count;
0036     size_t rest = buffer_size;
0037     int err;
0038 
0039     /* check that the file system has xattrs */
0040     if (msblk->xattr_id_table == NULL)
0041         return -EOPNOTSUPP;
0042 
0043     /* loop reading each xattr name */
0044     while (count--) {
0045         struct squashfs_xattr_entry entry;
0046         struct squashfs_xattr_val val;
0047         const struct xattr_handler *handler;
0048         int name_size;
0049 
0050         err = squashfs_read_metadata(sb, &entry, &start, &offset,
0051                             sizeof(entry));
0052         if (err < 0)
0053             goto failed;
0054 
0055         name_size = le16_to_cpu(entry.size);
0056         handler = squashfs_xattr_handler(le16_to_cpu(entry.type));
0057         if (handler && (!handler->list || handler->list(d))) {
0058             const char *prefix = handler->prefix ?: handler->name;
0059             size_t prefix_size = strlen(prefix);
0060 
0061             if (buffer) {
0062                 if (prefix_size + name_size + 1 > rest) {
0063                     err = -ERANGE;
0064                     goto failed;
0065                 }
0066                 memcpy(buffer, prefix, prefix_size);
0067                 buffer += prefix_size;
0068             }
0069             err = squashfs_read_metadata(sb, buffer, &start,
0070                 &offset, name_size);
0071             if (err < 0)
0072                 goto failed;
0073             if (buffer) {
0074                 buffer[name_size] = '\0';
0075                 buffer += name_size + 1;
0076             }
0077             rest -= prefix_size + name_size + 1;
0078         } else  {
0079             /* no handler or insuffficient privileges, so skip */
0080             err = squashfs_read_metadata(sb, NULL, &start,
0081                 &offset, name_size);
0082             if (err < 0)
0083                 goto failed;
0084         }
0085 
0086 
0087         /* skip remaining xattr entry */
0088         err = squashfs_read_metadata(sb, &val, &start, &offset,
0089                         sizeof(val));
0090         if (err < 0)
0091             goto failed;
0092 
0093         err = squashfs_read_metadata(sb, NULL, &start, &offset,
0094                         le32_to_cpu(val.vsize));
0095         if (err < 0)
0096             goto failed;
0097     }
0098     err = buffer_size - rest;
0099 
0100 failed:
0101     return err;
0102 }
0103 
0104 
0105 static int squashfs_xattr_get(struct inode *inode, int name_index,
0106     const char *name, void *buffer, size_t buffer_size)
0107 {
0108     struct super_block *sb = inode->i_sb;
0109     struct squashfs_sb_info *msblk = sb->s_fs_info;
0110     u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr)
0111                          + msblk->xattr_table;
0112     int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr);
0113     int count = squashfs_i(inode)->xattr_count;
0114     int name_len = strlen(name);
0115     int err, vsize;
0116     char *target = kmalloc(name_len, GFP_KERNEL);
0117 
0118     if (target == NULL)
0119         return  -ENOMEM;
0120 
0121     /* loop reading each xattr name */
0122     for (; count; count--) {
0123         struct squashfs_xattr_entry entry;
0124         struct squashfs_xattr_val val;
0125         int type, prefix, name_size;
0126 
0127         err = squashfs_read_metadata(sb, &entry, &start, &offset,
0128                             sizeof(entry));
0129         if (err < 0)
0130             goto failed;
0131 
0132         name_size = le16_to_cpu(entry.size);
0133         type = le16_to_cpu(entry.type);
0134         prefix = type & SQUASHFS_XATTR_PREFIX_MASK;
0135 
0136         if (prefix == name_index && name_size == name_len)
0137             err = squashfs_read_metadata(sb, target, &start,
0138                         &offset, name_size);
0139         else
0140             err = squashfs_read_metadata(sb, NULL, &start,
0141                         &offset, name_size);
0142         if (err < 0)
0143             goto failed;
0144 
0145         if (prefix == name_index && name_size == name_len &&
0146                     strncmp(target, name, name_size) == 0) {
0147             /* found xattr */
0148             if (type & SQUASHFS_XATTR_VALUE_OOL) {
0149                 __le64 xattr_val;
0150                 u64 xattr;
0151                 /* val is a reference to the real location */
0152                 err = squashfs_read_metadata(sb, &val, &start,
0153                         &offset, sizeof(val));
0154                 if (err < 0)
0155                     goto failed;
0156                 err = squashfs_read_metadata(sb, &xattr_val,
0157                     &start, &offset, sizeof(xattr_val));
0158                 if (err < 0)
0159                     goto failed;
0160                 xattr = le64_to_cpu(xattr_val);
0161                 start = SQUASHFS_XATTR_BLK(xattr) +
0162                             msblk->xattr_table;
0163                 offset = SQUASHFS_XATTR_OFFSET(xattr);
0164             }
0165             /* read xattr value */
0166             err = squashfs_read_metadata(sb, &val, &start, &offset,
0167                             sizeof(val));
0168             if (err < 0)
0169                 goto failed;
0170 
0171             vsize = le32_to_cpu(val.vsize);
0172             if (buffer) {
0173                 if (vsize > buffer_size) {
0174                     err = -ERANGE;
0175                     goto failed;
0176                 }
0177                 err = squashfs_read_metadata(sb, buffer, &start,
0178                      &offset, vsize);
0179                 if (err < 0)
0180                     goto failed;
0181             }
0182             break;
0183         }
0184 
0185         /* no match, skip remaining xattr entry */
0186         err = squashfs_read_metadata(sb, &val, &start, &offset,
0187                             sizeof(val));
0188         if (err < 0)
0189             goto failed;
0190         err = squashfs_read_metadata(sb, NULL, &start, &offset,
0191                         le32_to_cpu(val.vsize));
0192         if (err < 0)
0193             goto failed;
0194     }
0195     err = count ? vsize : -ENODATA;
0196 
0197 failed:
0198     kfree(target);
0199     return err;
0200 }
0201 
0202 
0203 static int squashfs_xattr_handler_get(const struct xattr_handler *handler,
0204                       struct dentry *unused,
0205                       struct inode *inode,
0206                       const char *name,
0207                       void *buffer, size_t size)
0208 {
0209     return squashfs_xattr_get(inode, handler->flags, name,
0210         buffer, size);
0211 }
0212 
0213 /*
0214  * User namespace support
0215  */
0216 static const struct xattr_handler squashfs_xattr_user_handler = {
0217     .prefix = XATTR_USER_PREFIX,
0218     .flags  = SQUASHFS_XATTR_USER,
0219     .get    = squashfs_xattr_handler_get
0220 };
0221 
0222 /*
0223  * Trusted namespace support
0224  */
0225 static bool squashfs_trusted_xattr_handler_list(struct dentry *d)
0226 {
0227     return capable(CAP_SYS_ADMIN);
0228 }
0229 
0230 static const struct xattr_handler squashfs_xattr_trusted_handler = {
0231     .prefix = XATTR_TRUSTED_PREFIX,
0232     .flags  = SQUASHFS_XATTR_TRUSTED,
0233     .list   = squashfs_trusted_xattr_handler_list,
0234     .get    = squashfs_xattr_handler_get
0235 };
0236 
0237 /*
0238  * Security namespace support
0239  */
0240 static const struct xattr_handler squashfs_xattr_security_handler = {
0241     .prefix = XATTR_SECURITY_PREFIX,
0242     .flags  = SQUASHFS_XATTR_SECURITY,
0243     .get    = squashfs_xattr_handler_get
0244 };
0245 
0246 static const struct xattr_handler *squashfs_xattr_handler(int type)
0247 {
0248     if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL))
0249         /* ignore unrecognised type */
0250         return NULL;
0251 
0252     switch (type & SQUASHFS_XATTR_PREFIX_MASK) {
0253     case SQUASHFS_XATTR_USER:
0254         return &squashfs_xattr_user_handler;
0255     case SQUASHFS_XATTR_TRUSTED:
0256         return &squashfs_xattr_trusted_handler;
0257     case SQUASHFS_XATTR_SECURITY:
0258         return &squashfs_xattr_security_handler;
0259     default:
0260         /* ignore unrecognised type */
0261         return NULL;
0262     }
0263 }
0264 
0265 const struct xattr_handler *squashfs_xattr_handlers[] = {
0266     &squashfs_xattr_user_handler,
0267     &squashfs_xattr_trusted_handler,
0268     &squashfs_xattr_security_handler,
0269     NULL
0270 };
0271