272 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Squashfs - a compressed read only filesystem for Linux4 *5 * Copyright (c) 20106 * Phillip Lougher <phillip@squashfs.org.uk>7 *8 * xattr.c9 */10 11#include <linux/init.h>12#include <linux/module.h>13#include <linux/string.h>14#include <linux/fs.h>15#include <linux/vfs.h>16#include <linux/xattr.h>17#include <linux/slab.h>18 19#include "squashfs_fs.h"20#include "squashfs_fs_sb.h"21#include "squashfs_fs_i.h"22#include "squashfs.h"23 24static const struct xattr_handler *squashfs_xattr_handler(int);25 26ssize_t squashfs_listxattr(struct dentry *d, char *buffer,27 size_t buffer_size)28{29 struct inode *inode = d_inode(d);30 struct super_block *sb = inode->i_sb;31 struct squashfs_sb_info *msblk = sb->s_fs_info;32 u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr)33 + msblk->xattr_table;34 int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr);35 int count = squashfs_i(inode)->xattr_count;36 size_t rest = buffer_size;37 int err;38 39 /* check that the file system has xattrs */40 if (msblk->xattr_id_table == NULL)41 return -EOPNOTSUPP;42 43 /* loop reading each xattr name */44 while (count--) {45 struct squashfs_xattr_entry entry;46 struct squashfs_xattr_val val;47 const struct xattr_handler *handler;48 int name_size;49 50 err = squashfs_read_metadata(sb, &entry, &start, &offset,51 sizeof(entry));52 if (err < 0)53 goto failed;54 55 name_size = le16_to_cpu(entry.size);56 handler = squashfs_xattr_handler(le16_to_cpu(entry.type));57 if (handler && (!handler->list || handler->list(d))) {58 const char *prefix = handler->prefix ?: handler->name;59 size_t prefix_size = strlen(prefix);60 61 if (buffer) {62 if (prefix_size + name_size + 1 > rest) {63 err = -ERANGE;64 goto failed;65 }66 memcpy(buffer, prefix, prefix_size);67 buffer += prefix_size;68 }69 err = squashfs_read_metadata(sb, buffer, &start,70 &offset, name_size);71 if (err < 0)72 goto failed;73 if (buffer) {74 buffer[name_size] = '\0';75 buffer += name_size + 1;76 }77 rest -= prefix_size + name_size + 1;78 } else {79 /* no handler or insuffficient privileges, so skip */80 err = squashfs_read_metadata(sb, NULL, &start,81 &offset, name_size);82 if (err < 0)83 goto failed;84 }85 86 87 /* skip remaining xattr entry */88 err = squashfs_read_metadata(sb, &val, &start, &offset,89 sizeof(val));90 if (err < 0)91 goto failed;92 93 err = squashfs_read_metadata(sb, NULL, &start, &offset,94 le32_to_cpu(val.vsize));95 if (err < 0)96 goto failed;97 }98 err = buffer_size - rest;99 100failed:101 return err;102}103 104 105static int squashfs_xattr_get(struct inode *inode, int name_index,106 const char *name, void *buffer, size_t buffer_size)107{108 struct super_block *sb = inode->i_sb;109 struct squashfs_sb_info *msblk = sb->s_fs_info;110 u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr)111 + msblk->xattr_table;112 int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr);113 int count = squashfs_i(inode)->xattr_count;114 int name_len = strlen(name);115 int err, vsize;116 char *target = kmalloc(name_len, GFP_KERNEL);117 118 if (target == NULL)119 return -ENOMEM;120 121 /* loop reading each xattr name */122 for (; count; count--) {123 struct squashfs_xattr_entry entry;124 struct squashfs_xattr_val val;125 int type, prefix, name_size;126 127 err = squashfs_read_metadata(sb, &entry, &start, &offset,128 sizeof(entry));129 if (err < 0)130 goto failed;131 132 name_size = le16_to_cpu(entry.size);133 type = le16_to_cpu(entry.type);134 prefix = type & SQUASHFS_XATTR_PREFIX_MASK;135 136 if (prefix == name_index && name_size == name_len)137 err = squashfs_read_metadata(sb, target, &start,138 &offset, name_size);139 else140 err = squashfs_read_metadata(sb, NULL, &start,141 &offset, name_size);142 if (err < 0)143 goto failed;144 145 if (prefix == name_index && name_size == name_len &&146 strncmp(target, name, name_size) == 0) {147 /* found xattr */148 if (type & SQUASHFS_XATTR_VALUE_OOL) {149 __le64 xattr_val;150 u64 xattr;151 /* val is a reference to the real location */152 err = squashfs_read_metadata(sb, &val, &start,153 &offset, sizeof(val));154 if (err < 0)155 goto failed;156 err = squashfs_read_metadata(sb, &xattr_val,157 &start, &offset, sizeof(xattr_val));158 if (err < 0)159 goto failed;160 xattr = le64_to_cpu(xattr_val);161 start = SQUASHFS_XATTR_BLK(xattr) +162 msblk->xattr_table;163 offset = SQUASHFS_XATTR_OFFSET(xattr);164 }165 /* read xattr value */166 err = squashfs_read_metadata(sb, &val, &start, &offset,167 sizeof(val));168 if (err < 0)169 goto failed;170 171 vsize = le32_to_cpu(val.vsize);172 if (buffer) {173 if (vsize > buffer_size) {174 err = -ERANGE;175 goto failed;176 }177 err = squashfs_read_metadata(sb, buffer, &start,178 &offset, vsize);179 if (err < 0)180 goto failed;181 }182 break;183 }184 185 /* no match, skip remaining xattr entry */186 err = squashfs_read_metadata(sb, &val, &start, &offset,187 sizeof(val));188 if (err < 0)189 goto failed;190 err = squashfs_read_metadata(sb, NULL, &start, &offset,191 le32_to_cpu(val.vsize));192 if (err < 0)193 goto failed;194 }195 err = count ? vsize : -ENODATA;196 197failed:198 kfree(target);199 return err;200}201 202 203static int squashfs_xattr_handler_get(const struct xattr_handler *handler,204 struct dentry *unused,205 struct inode *inode,206 const char *name,207 void *buffer, size_t size)208{209 return squashfs_xattr_get(inode, handler->flags, name,210 buffer, size);211}212 213/*214 * User namespace support215 */216static const struct xattr_handler squashfs_xattr_user_handler = {217 .prefix = XATTR_USER_PREFIX,218 .flags = SQUASHFS_XATTR_USER,219 .get = squashfs_xattr_handler_get220};221 222/*223 * Trusted namespace support224 */225static bool squashfs_trusted_xattr_handler_list(struct dentry *d)226{227 return capable(CAP_SYS_ADMIN);228}229 230static const struct xattr_handler squashfs_xattr_trusted_handler = {231 .prefix = XATTR_TRUSTED_PREFIX,232 .flags = SQUASHFS_XATTR_TRUSTED,233 .list = squashfs_trusted_xattr_handler_list,234 .get = squashfs_xattr_handler_get235};236 237/*238 * Security namespace support239 */240static const struct xattr_handler squashfs_xattr_security_handler = {241 .prefix = XATTR_SECURITY_PREFIX,242 .flags = SQUASHFS_XATTR_SECURITY,243 .get = squashfs_xattr_handler_get244};245 246static const struct xattr_handler *squashfs_xattr_handler(int type)247{248 if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL))249 /* ignore unrecognised type */250 return NULL;251 252 switch (type & SQUASHFS_XATTR_PREFIX_MASK) {253 case SQUASHFS_XATTR_USER:254 return &squashfs_xattr_user_handler;255 case SQUASHFS_XATTR_TRUSTED:256 return &squashfs_xattr_trusted_handler;257 case SQUASHFS_XATTR_SECURITY:258 return &squashfs_xattr_security_handler;259 default:260 /* ignore unrecognised type */261 return NULL;262 }263}264 265const struct xattr_handler * const squashfs_xattr_handlers[] = {266 &squashfs_xattr_user_handler,267 &squashfs_xattr_trusted_handler,268 &squashfs_xattr_security_handler,269 NULL270};271 272