1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2008 Christoph Hellwig. 4 * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc. 5 */ 6 7 #include "xfs.h" 8 #include "xfs_shared.h" 9 #include "xfs_format.h" 10 #include "xfs_log_format.h" 11 #include "xfs_da_format.h" 12 #include "xfs_trans_resv.h" 13 #include "xfs_mount.h" 14 #include "xfs_inode.h" 15 #include "xfs_da_btree.h" 16 #include "xfs_attr.h" 17 #include "xfs_acl.h" 18 #include "xfs_log.h" 19 #include "xfs_xattr.h" 20 21 #include <linux/posix_acl_xattr.h> 22 23 /* 24 * Get permission to use log-assisted atomic exchange of file extents. 25 * 26 * Callers must not be running any transactions or hold any inode locks, and 27 * they must release the permission by calling xlog_drop_incompat_feat 28 * when they're done. 29 */ 30 static inline int 31 xfs_attr_grab_log_assist( 32 struct xfs_mount *mp) 33 { 34 int error = 0; 35 36 /* 37 * Protect ourselves from an idle log clearing the logged xattrs log 38 * incompat feature bit. 39 */ 40 xlog_use_incompat_feat(mp->m_log); 41 42 /* 43 * If log-assisted xattrs are already enabled, the caller can use the 44 * log assisted swap functions with the log-incompat reference we got. 45 */ 46 if (xfs_sb_version_haslogxattrs(&mp->m_sb)) 47 return 0; 48 49 /* Enable log-assisted xattrs. */ 50 error = xfs_add_incompat_log_feature(mp, 51 XFS_SB_FEAT_INCOMPAT_LOG_XATTRS); 52 if (error) 53 goto drop_incompat; 54 55 xfs_warn_mount(mp, XFS_OPSTATE_WARNED_LARP, 56 "EXPERIMENTAL logged extended attributes feature in use. Use at your own risk!"); 57 58 return 0; 59 drop_incompat: 60 xlog_drop_incompat_feat(mp->m_log); 61 return error; 62 } 63 64 static inline void 65 xfs_attr_rele_log_assist( 66 struct xfs_mount *mp) 67 { 68 xlog_drop_incompat_feat(mp->m_log); 69 } 70 71 /* 72 * Set or remove an xattr, having grabbed the appropriate logging resources 73 * prior to calling libxfs. 74 */ 75 int 76 xfs_attr_change( 77 struct xfs_da_args *args) 78 { 79 struct xfs_mount *mp = args->dp->i_mount; 80 bool use_logging = false; 81 int error; 82 83 if (xfs_has_larp(mp)) { 84 error = xfs_attr_grab_log_assist(mp); 85 if (error) 86 return error; 87 88 use_logging = true; 89 } 90 91 error = xfs_attr_set(args); 92 93 if (use_logging) 94 xfs_attr_rele_log_assist(mp); 95 return error; 96 } 97 98 99 static int 100 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused, 101 struct inode *inode, const char *name, void *value, size_t size) 102 { 103 struct xfs_da_args args = { 104 .dp = XFS_I(inode), 105 .attr_filter = handler->flags, 106 .name = name, 107 .namelen = strlen(name), 108 .value = value, 109 .valuelen = size, 110 }; 111 int error; 112 113 error = xfs_attr_get(&args); 114 if (error) 115 return error; 116 return args.valuelen; 117 } 118 119 static int 120 xfs_xattr_set(const struct xattr_handler *handler, 121 struct user_namespace *mnt_userns, struct dentry *unused, 122 struct inode *inode, const char *name, const void *value, 123 size_t size, int flags) 124 { 125 struct xfs_da_args args = { 126 .dp = XFS_I(inode), 127 .attr_filter = handler->flags, 128 .attr_flags = flags, 129 .name = name, 130 .namelen = strlen(name), 131 .value = (void *)value, 132 .valuelen = size, 133 }; 134 int error; 135 136 error = xfs_attr_change(&args); 137 if (!error && (handler->flags & XFS_ATTR_ROOT)) 138 xfs_forget_acl(inode, name); 139 return error; 140 } 141 142 static const struct xattr_handler xfs_xattr_user_handler = { 143 .prefix = XATTR_USER_PREFIX, 144 .flags = 0, /* no flags implies user namespace */ 145 .get = xfs_xattr_get, 146 .set = xfs_xattr_set, 147 }; 148 149 static const struct xattr_handler xfs_xattr_trusted_handler = { 150 .prefix = XATTR_TRUSTED_PREFIX, 151 .flags = XFS_ATTR_ROOT, 152 .get = xfs_xattr_get, 153 .set = xfs_xattr_set, 154 }; 155 156 static const struct xattr_handler xfs_xattr_security_handler = { 157 .prefix = XATTR_SECURITY_PREFIX, 158 .flags = XFS_ATTR_SECURE, 159 .get = xfs_xattr_get, 160 .set = xfs_xattr_set, 161 }; 162 163 const struct xattr_handler *xfs_xattr_handlers[] = { 164 &xfs_xattr_user_handler, 165 &xfs_xattr_trusted_handler, 166 &xfs_xattr_security_handler, 167 #ifdef CONFIG_XFS_POSIX_ACL 168 &posix_acl_access_xattr_handler, 169 &posix_acl_default_xattr_handler, 170 #endif 171 NULL 172 }; 173 174 static void 175 __xfs_xattr_put_listent( 176 struct xfs_attr_list_context *context, 177 char *prefix, 178 int prefix_len, 179 unsigned char *name, 180 int namelen) 181 { 182 char *offset; 183 int arraytop; 184 185 if (context->count < 0 || context->seen_enough) 186 return; 187 188 if (!context->buffer) 189 goto compute_size; 190 191 arraytop = context->count + prefix_len + namelen + 1; 192 if (arraytop > context->firstu) { 193 context->count = -1; /* insufficient space */ 194 context->seen_enough = 1; 195 return; 196 } 197 offset = context->buffer + context->count; 198 strncpy(offset, prefix, prefix_len); 199 offset += prefix_len; 200 strncpy(offset, (char *)name, namelen); /* real name */ 201 offset += namelen; 202 *offset = '\0'; 203 204 compute_size: 205 context->count += prefix_len + namelen + 1; 206 return; 207 } 208 209 static void 210 xfs_xattr_put_listent( 211 struct xfs_attr_list_context *context, 212 int flags, 213 unsigned char *name, 214 int namelen, 215 int valuelen) 216 { 217 char *prefix; 218 int prefix_len; 219 220 ASSERT(context->count >= 0); 221 222 if (flags & XFS_ATTR_ROOT) { 223 #ifdef CONFIG_XFS_POSIX_ACL 224 if (namelen == SGI_ACL_FILE_SIZE && 225 strncmp(name, SGI_ACL_FILE, 226 SGI_ACL_FILE_SIZE) == 0) { 227 __xfs_xattr_put_listent( 228 context, XATTR_SYSTEM_PREFIX, 229 XATTR_SYSTEM_PREFIX_LEN, 230 XATTR_POSIX_ACL_ACCESS, 231 strlen(XATTR_POSIX_ACL_ACCESS)); 232 } else if (namelen == SGI_ACL_DEFAULT_SIZE && 233 strncmp(name, SGI_ACL_DEFAULT, 234 SGI_ACL_DEFAULT_SIZE) == 0) { 235 __xfs_xattr_put_listent( 236 context, XATTR_SYSTEM_PREFIX, 237 XATTR_SYSTEM_PREFIX_LEN, 238 XATTR_POSIX_ACL_DEFAULT, 239 strlen(XATTR_POSIX_ACL_DEFAULT)); 240 } 241 #endif 242 243 /* 244 * Only show root namespace entries if we are actually allowed to 245 * see them. 246 */ 247 if (!capable(CAP_SYS_ADMIN)) 248 return; 249 250 prefix = XATTR_TRUSTED_PREFIX; 251 prefix_len = XATTR_TRUSTED_PREFIX_LEN; 252 } else if (flags & XFS_ATTR_SECURE) { 253 prefix = XATTR_SECURITY_PREFIX; 254 prefix_len = XATTR_SECURITY_PREFIX_LEN; 255 } else { 256 prefix = XATTR_USER_PREFIX; 257 prefix_len = XATTR_USER_PREFIX_LEN; 258 } 259 260 __xfs_xattr_put_listent(context, prefix, prefix_len, name, 261 namelen); 262 return; 263 } 264 265 ssize_t 266 xfs_vn_listxattr( 267 struct dentry *dentry, 268 char *data, 269 size_t size) 270 { 271 struct xfs_attr_list_context context; 272 struct inode *inode = d_inode(dentry); 273 int error; 274 275 /* 276 * First read the regular on-disk attributes. 277 */ 278 memset(&context, 0, sizeof(context)); 279 context.dp = XFS_I(inode); 280 context.resynch = 1; 281 context.buffer = size ? data : NULL; 282 context.bufsize = size; 283 context.firstu = context.bufsize; 284 context.put_listent = xfs_xattr_put_listent; 285 286 error = xfs_attr_list(&context); 287 if (error) 288 return error; 289 if (context.count < 0) 290 return -ERANGE; 291 292 return context.count; 293 } 294