191094Sdes// SPDX-License-Identifier: GPL-2.0 291094Sdes/* 391094Sdes * Copyright (C) 2008 Christoph Hellwig. 491094Sdes * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc. 591094Sdes */ 691094Sdes 791094Sdes#include "xfs.h" 891094Sdes#include "xfs_shared.h" 991094Sdes#include "xfs_format.h" 1091094Sdes#include "xfs_log_format.h" 1191094Sdes#include "xfs_da_format.h" 1291094Sdes#include "xfs_trans_resv.h" 1391094Sdes#include "xfs_mount.h" 1491094Sdes#include "xfs_inode.h" 1591094Sdes#include "xfs_da_btree.h" 1691094Sdes#include "xfs_attr.h" 1791094Sdes#include "xfs_acl.h" 1891094Sdes#include "xfs_log.h" 1991094Sdes#include "xfs_xattr.h" 2091094Sdes 2191094Sdes#include <linux/posix_acl_xattr.h> 2291094Sdes 2391094Sdes/* 2491094Sdes * Get permission to use log-assisted atomic exchange of file extents. 2591094Sdes * 2691094Sdes * Callers must not be running any transactions or hold any inode locks, and 2791094Sdes * they must release the permission by calling xlog_drop_incompat_feat 2891094Sdes * when they're done. 2991094Sdes */ 3091094Sdesstatic inline int 3191094Sdesxfs_attr_grab_log_assist( 3291094Sdes struct xfs_mount *mp) 3391094Sdes{ 3491094Sdes int error = 0; 3591094Sdes 3691094Sdes /* 3791094Sdes * Protect ourselves from an idle log clearing the logged xattrs log 3891094Sdes * incompat feature bit. 3991094Sdes */ 4091094Sdes xlog_use_incompat_feat(mp->m_log); 4191094Sdes 4291094Sdes /* 4391094Sdes * If log-assisted xattrs are already enabled, the caller can use the 4491094Sdes * log assisted swap functions with the log-incompat reference we got. 4591094Sdes */ 4691094Sdes if (xfs_sb_version_haslogxattrs(&mp->m_sb)) 4791094Sdes return 0; 4891094Sdes 4991094Sdes /* 5091094Sdes * Check if the filesystem featureset is new enough to set this log 5191094Sdes * incompat feature bit. Strictly speaking, the minimum requirement is 5291094Sdes * a V5 filesystem for the superblock field, but we'll require rmap 5391094Sdes * or reflink to avoid having to deal with really old kernels. 5491094Sdes */ 5591094Sdes if (!xfs_has_reflink(mp) && !xfs_has_rmapbt(mp)) { 5691094Sdes error = -EOPNOTSUPP; 5791094Sdes goto drop_incompat; 5891094Sdes } 5991094Sdes 6091094Sdes /* Enable log-assisted xattrs. */ 6191094Sdes error = xfs_add_incompat_log_feature(mp, 6291094Sdes XFS_SB_FEAT_INCOMPAT_LOG_XATTRS); 6391094Sdes if (error) 6491094Sdes goto drop_incompat; 6591094Sdes 6691094Sdes xfs_warn_mount(mp, XFS_OPSTATE_WARNED_LARP, 6791094Sdes "EXPERIMENTAL logged extended attributes feature in use. Use at your own risk!"); 6891094Sdes 6991094Sdes return 0; 7091094Sdesdrop_incompat: 7191094Sdes xlog_drop_incompat_feat(mp->m_log); 7291094Sdes return error; 7391094Sdes} 7491094Sdes 7591094Sdesstatic inline void 7691094Sdesxfs_attr_rele_log_assist( 7791094Sdes struct xfs_mount *mp) 7891094Sdes{ 7991094Sdes xlog_drop_incompat_feat(mp->m_log); 8091094Sdes} 8191094Sdes 8291094Sdesstatic inline bool 8391094Sdesxfs_attr_want_log_assist( 8491094Sdes struct xfs_mount *mp) 8591094Sdes{ 8691094Sdes#ifdef DEBUG 8791094Sdes /* Logged xattrs require a V5 super for log_incompat */ 8891094Sdes return xfs_has_crc(mp) && xfs_globals.larp; 89#else 90 return false; 91#endif 92} 93 94/* 95 * Set or remove an xattr, having grabbed the appropriate logging resources 96 * prior to calling libxfs. 97 */ 98int 99xfs_attr_change( 100 struct xfs_da_args *args) 101{ 102 struct xfs_mount *mp = args->dp->i_mount; 103 bool use_logging = false; 104 int error; 105 106 ASSERT(!(args->op_flags & XFS_DA_OP_LOGGED)); 107 108 if (xfs_attr_want_log_assist(mp)) { 109 error = xfs_attr_grab_log_assist(mp); 110 if (error) 111 return error; 112 113 args->op_flags |= XFS_DA_OP_LOGGED; 114 use_logging = true; 115 } 116 117 error = xfs_attr_set(args); 118 119 if (use_logging) 120 xfs_attr_rele_log_assist(mp); 121 return error; 122} 123 124 125static int 126xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused, 127 struct inode *inode, const char *name, void *value, size_t size) 128{ 129 struct xfs_da_args args = { 130 .dp = XFS_I(inode), 131 .attr_filter = handler->flags, 132 .name = name, 133 .namelen = strlen(name), 134 .value = value, 135 .valuelen = size, 136 }; 137 int error; 138 139 if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK)) 140 return -EIO; 141 142 error = xfs_attr_get(&args); 143 if (error) 144 return error; 145 return args.valuelen; 146} 147 148static int 149xfs_xattr_set(const struct xattr_handler *handler, 150 struct mnt_idmap *idmap, struct dentry *unused, 151 struct inode *inode, const char *name, const void *value, 152 size_t size, int flags) 153{ 154 struct xfs_da_args args = { 155 .dp = XFS_I(inode), 156 .attr_filter = handler->flags, 157 .attr_flags = flags, 158 .name = name, 159 .namelen = strlen(name), 160 .value = (void *)value, 161 .valuelen = size, 162 }; 163 int error; 164 165 error = xfs_attr_change(&args); 166 if (!error && (handler->flags & XFS_ATTR_ROOT)) 167 xfs_forget_acl(inode, name); 168 return error; 169} 170 171static const struct xattr_handler xfs_xattr_user_handler = { 172 .prefix = XATTR_USER_PREFIX, 173 .flags = 0, /* no flags implies user namespace */ 174 .get = xfs_xattr_get, 175 .set = xfs_xattr_set, 176}; 177 178static const struct xattr_handler xfs_xattr_trusted_handler = { 179 .prefix = XATTR_TRUSTED_PREFIX, 180 .flags = XFS_ATTR_ROOT, 181 .get = xfs_xattr_get, 182 .set = xfs_xattr_set, 183}; 184 185static const struct xattr_handler xfs_xattr_security_handler = { 186 .prefix = XATTR_SECURITY_PREFIX, 187 .flags = XFS_ATTR_SECURE, 188 .get = xfs_xattr_get, 189 .set = xfs_xattr_set, 190}; 191 192const struct xattr_handler * const xfs_xattr_handlers[] = { 193 &xfs_xattr_user_handler, 194 &xfs_xattr_trusted_handler, 195 &xfs_xattr_security_handler, 196 NULL 197}; 198 199static void 200__xfs_xattr_put_listent( 201 struct xfs_attr_list_context *context, 202 char *prefix, 203 int prefix_len, 204 unsigned char *name, 205 int namelen) 206{ 207 char *offset; 208 int arraytop; 209 210 if (context->count < 0 || context->seen_enough) 211 return; 212 213 if (!context->buffer) 214 goto compute_size; 215 216 arraytop = context->count + prefix_len + namelen + 1; 217 if (arraytop > context->firstu) { 218 context->count = -1; /* insufficient space */ 219 context->seen_enough = 1; 220 return; 221 } 222 offset = context->buffer + context->count; 223 memcpy(offset, prefix, prefix_len); 224 offset += prefix_len; 225 strncpy(offset, (char *)name, namelen); /* real name */ 226 offset += namelen; 227 *offset = '\0'; 228 229compute_size: 230 context->count += prefix_len + namelen + 1; 231 return; 232} 233 234static void 235xfs_xattr_put_listent( 236 struct xfs_attr_list_context *context, 237 int flags, 238 unsigned char *name, 239 int namelen, 240 int valuelen) 241{ 242 char *prefix; 243 int prefix_len; 244 245 ASSERT(context->count >= 0); 246 247 if (flags & XFS_ATTR_ROOT) { 248#ifdef CONFIG_XFS_POSIX_ACL 249 if (namelen == SGI_ACL_FILE_SIZE && 250 strncmp(name, SGI_ACL_FILE, 251 SGI_ACL_FILE_SIZE) == 0) { 252 __xfs_xattr_put_listent( 253 context, XATTR_SYSTEM_PREFIX, 254 XATTR_SYSTEM_PREFIX_LEN, 255 XATTR_POSIX_ACL_ACCESS, 256 strlen(XATTR_POSIX_ACL_ACCESS)); 257 } else if (namelen == SGI_ACL_DEFAULT_SIZE && 258 strncmp(name, SGI_ACL_DEFAULT, 259 SGI_ACL_DEFAULT_SIZE) == 0) { 260 __xfs_xattr_put_listent( 261 context, XATTR_SYSTEM_PREFIX, 262 XATTR_SYSTEM_PREFIX_LEN, 263 XATTR_POSIX_ACL_DEFAULT, 264 strlen(XATTR_POSIX_ACL_DEFAULT)); 265 } 266#endif 267 268 /* 269 * Only show root namespace entries if we are actually allowed to 270 * see them. 271 */ 272 if (!capable(CAP_SYS_ADMIN)) 273 return; 274 275 prefix = XATTR_TRUSTED_PREFIX; 276 prefix_len = XATTR_TRUSTED_PREFIX_LEN; 277 } else if (flags & XFS_ATTR_SECURE) { 278 prefix = XATTR_SECURITY_PREFIX; 279 prefix_len = XATTR_SECURITY_PREFIX_LEN; 280 } else { 281 prefix = XATTR_USER_PREFIX; 282 prefix_len = XATTR_USER_PREFIX_LEN; 283 } 284 285 __xfs_xattr_put_listent(context, prefix, prefix_len, name, 286 namelen); 287 return; 288} 289 290ssize_t 291xfs_vn_listxattr( 292 struct dentry *dentry, 293 char *data, 294 size_t size) 295{ 296 struct xfs_attr_list_context context; 297 struct inode *inode = d_inode(dentry); 298 int error; 299 300 if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK)) 301 return -EIO; 302 303 /* 304 * First read the regular on-disk attributes. 305 */ 306 memset(&context, 0, sizeof(context)); 307 context.dp = XFS_I(inode); 308 context.resynch = 1; 309 context.buffer = size ? data : NULL; 310 context.bufsize = size; 311 context.firstu = context.bufsize; 312 context.put_listent = xfs_xattr_put_listent; 313 314 error = xfs_attr_list(&context); 315 if (error) 316 return error; 317 if (context.count < 0) 318 return -ERANGE; 319 320 return context.count; 321} 322