o Change the API and ABI of the Extended Attribute kernel interfaces to

introduce a new argument, "namespace", rather than relying on a first-
  character namespace indicator.  This is in line with more recent
  thinking on EA interfaces on various mailing lists, including the
  posix1e, Linux acl-devel, and trustedbsd-discuss forums.  Two namespaces
  are defined by default, EXTATTR_NAMESPACE_SYSTEM and
  EXTATTR_NAMESPACE_USER, where the primary distinction lies in the
  access control model: user EAs are accessible based on the normal
  MAC and DAC file/directory protections, and system attributes are
  limited to kernel-originated or appropriately privileged userland
  requests.

o These API changes occur at several levels: the namespace argument is
  introduced in the extattr_{get,set}_file() system call interfaces,
  at the vnode operation level in the vop_{get,set}extattr() interfaces,
  and in the UFS extended attribute implementation.  Changes are also
  introduced in the VFS extattrctl() interface (system call, VFS,
  and UFS implementation), where the arguments are modified to include
  a namespace field, as well as modified to advoid direct access to
  userspace variables from below the VFS layer (in the style of recent
  changes to mount by adrian@FreeBSD.org).  This required some cleanup
  and bug fixing regarding VFS locks and the VFS interface, as a vnode
  pointer may now be optionally submitted to the VFS_EXTATTRCTL()
  call.  Updated documentation for the VFS interface will be committed
  shortly.

o In the near future, the auto-starting feature will be updated to
  search two sub-directories to the ".attribute" directory in appropriate
  file systems: "user" and "system" to locate attributes intended for
  those namespaces, as the single filename is no longer sufficient
  to indicate what namespace the attribute is intended for.  Until this
  is committed, all attributes auto-started by UFS will be placed in
  the EXTATTR_NAMESPACE_SYSTEM namespace.

o The default POSIX.1e attribute names for ACLs and Capabilities have
  been updated to no longer include the '$' in their filename.  As such,
  if you're using these features, you'll need to rename the attribute
  backing files to the same names without '$' symbols in front.

o Note that these changes will require changes in userland, which will
  be committed shortly.  These include modifications to the extended
  attribute utilities, as well as to libutil for new namespace
  string conversion routines.  Once the matching userland changes are
  committed, a buildworld is recommended to update all the necessary
  include files and verify that the kernel and userland environments
  are in sync.  Note: If you do not use extended attributes (most people
  won't), upgrading is not imperative although since the system call
  API has changed, the new userland extended attribute code will no longer
  compile with old include files.

o Couple of minor cleanups while I'm there: make more code compilation
  conditional on FFS_EXTATTR, which should recover a bit of space on
  kernels running without EA's, as well as update copyright dates.

Obtained from:	TrustedBSD Project
This commit is contained in:
Robert Watson 2001-03-15 02:54:29 +00:00
parent fff8dac495
commit 70f3685105
17 changed files with 335 additions and 174 deletions

View File

@ -73,7 +73,9 @@ static int nullfs_unmount(struct mount *mp, int mntflags, struct proc *p);
static int nullfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp);
static int nullfs_vptofh(struct vnode *vp, struct fid *fhp);
static int nullfs_extattrctl(struct mount *mp, int cmd,
const char *attrname, caddr_t arg, struct proc *p);
struct vnode *filename_vp,
int namespace, const char *attrname,
struct proc *p);
/*
* Mount null layer
@ -408,15 +410,16 @@ nullfs_vptofh(vp, fhp)
}
static int
nullfs_extattrctl(mp, cmd, attrname, arg, p)
nullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, p)
struct mount *mp;
int cmd;
struct vnode *filename_vp;
int namespace;
const char *attrname;
caddr_t arg;
struct proc *p;
{
return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, attrname,
arg, p);
return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp,
namespace, attrname, p);
}

View File

@ -74,7 +74,8 @@ static int umapfs_vget __P((struct mount *mp, ino_t ino,
struct vnode **vpp));
static int umapfs_vptofh __P((struct vnode *vp, struct fid *fhp));
static int umapfs_extattrctl __P((struct mount *mp, int cmd,
const char *attrname, caddr_t arg,
struct vnode *filename_vp,
int namespace, const char *attrname,
struct proc *p));
/*
@ -430,15 +431,16 @@ umapfs_vptofh(vp, fhp)
}
static int
umapfs_extattrctl(mp, cmd, attrname, arg, p)
umapfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, p)
struct mount *mp;
int cmd;
struct vnode *filename_vp;
int namespace;
const char *attrname;
caddr_t arg;
struct proc *p;
{
return (VFS_EXTATTRCTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, attrname,
arg, p));
return (VFS_EXTATTRCTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd,
filename_vp, namespace, attrname, p));
}

View File

@ -508,15 +508,16 @@
354 STD BSD { int __acl_aclcheck_fd(int filedes, acl_type_t type, \
struct acl *aclp); }
355 STD BSD { int extattrctl(const char *path, int cmd, \
const char *attrname, char *arg); }
356 STD BSD { int extattr_set_file(const char *path, \
const char *attrname, struct iovec *iovp, \
unsigned iovcnt); }
357 STD BSD { int extattr_get_file(const char *path, \
const char *attrname, struct iovec *iovp, \
unsigned iovcnt); }
358 STD BSD { int extattr_delete_file(const char *path, \
const char *filename, int namespace, \
const char *attrname); }
356 STD BSD { int extattr_set_file(const char *path, \
int namespace, const char *attrname, \
struct iovec *iovp, unsigned iovcnt); }
357 STD BSD { int extattr_get_file(const char *path, \
int namespace, const char *attrname, \
struct iovec *iovp, unsigned iovcnt); }
358 STD BSD { int extattr_delete_file(const char *path, \
int namespace, const char *attrname); }
359 STD BSD { int aio_waitcomplete(struct aiocb **aiocbp, struct timespec *timeout); }
360 STD BSD { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); }
361 STD BSD { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); }

View File

@ -739,11 +739,12 @@ vfs_stduninit (vfsp)
}
int
vfs_stdextattrctl(mp, cmd, attrname, arg, p)
vfs_stdextattrctl(mp, cmd, filename_vp, namespace, attrname, p)
struct mount *mp;
int cmd;
struct vnode *filename_vp;
int namespace;
const char *attrname;
caddr_t arg;
struct proc *p;
{
return(EOPNOTSUPP);

View File

@ -3681,20 +3681,65 @@ extattrctl(p, uap)
struct proc *p;
struct extattrctl_args *uap;
{
struct vnode *filename_vp;
struct nameidata nd;
struct mount *mp;
char attrname[EXTATTR_MAXNAMELEN];
int error;
/*
* SCARG(uap, attrname) not always defined. We check again later
* when we invoke the VFS call so as to pass in NULL there if needed.
*/
if (SCARG(uap, attrname) != NULL) {
error = copyinstr(SCARG(uap, attrname), attrname,
EXTATTR_MAXNAMELEN, NULL);
if (error)
return (error);
}
/*
* SCARG(uap, filename) not always defined. If it is, grab
* a vnode lock, which VFS_EXTATTRCTL() will later release.
*/
filename_vp = NULL;
if (SCARG(uap, filename) != NULL) {
NDINIT(&nd, LOOKUP | LOCKLEAF, FOLLOW, UIO_USERSPACE,
SCARG(uap, filename), p);
if ((error = namei(&nd)) != 0)
return (error);
filename_vp = nd.ni_vp;
NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK);
}
/* SCARG(uap, path) always defined. */
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
NDFREE(&nd, 0);
if (error)
if (error) {
if (filename_vp)
vrele(filename_vp);
return (error);
error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname),
SCARG(uap, arg), p);
}
if (SCARG(uap, attrname) != NULL) {
error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp,
SCARG(uap, namespace), attrname, p);
} else {
error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp,
SCARG(uap, namespace), NULL, p);
}
vn_finished_write(mp);
/*
* VFS_EXTATTRCTL will have unlocked, but not de-ref'd,
* filename_vp, so vrele it if it is defined.
*/
if (filename_vp != NULL)
vrele(filename_vp);
return (error);
}
@ -3756,8 +3801,8 @@ extattr_set_file(p, uap)
iov++;
}
cnt = auio.uio_resid;
error = VOP_SETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred,
p);
error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, namespace), attrname,
&auio, p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
@ -3823,8 +3868,8 @@ extattr_get_file(p, uap)
iov++;
}
cnt = auio.uio_resid;
error = VOP_GETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred,
p);
error = VOP_GETEXTATTR(nd.ni_vp, SCARG(uap, namespace), attrname,
&auio, p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
@ -3859,8 +3904,8 @@ extattr_delete_file(p, uap)
NDFREE(&nd, 0);
return (error);
}
error = VOP_SETEXTATTR(nd.ni_vp, attrname, NULL, p->p_cred->pc_ucred,
p);
error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, namespace), attrname,
NULL, p->p_cred->pc_ucred, p);
NDFREE(&nd, 0);
vn_finished_write(mp);
return(error);

View File

@ -3681,20 +3681,65 @@ extattrctl(p, uap)
struct proc *p;
struct extattrctl_args *uap;
{
struct vnode *filename_vp;
struct nameidata nd;
struct mount *mp;
char attrname[EXTATTR_MAXNAMELEN];
int error;
/*
* SCARG(uap, attrname) not always defined. We check again later
* when we invoke the VFS call so as to pass in NULL there if needed.
*/
if (SCARG(uap, attrname) != NULL) {
error = copyinstr(SCARG(uap, attrname), attrname,
EXTATTR_MAXNAMELEN, NULL);
if (error)
return (error);
}
/*
* SCARG(uap, filename) not always defined. If it is, grab
* a vnode lock, which VFS_EXTATTRCTL() will later release.
*/
filename_vp = NULL;
if (SCARG(uap, filename) != NULL) {
NDINIT(&nd, LOOKUP | LOCKLEAF, FOLLOW, UIO_USERSPACE,
SCARG(uap, filename), p);
if ((error = namei(&nd)) != 0)
return (error);
filename_vp = nd.ni_vp;
NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK);
}
/* SCARG(uap, path) always defined. */
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
NDFREE(&nd, 0);
if (error)
if (error) {
if (filename_vp)
vrele(filename_vp);
return (error);
error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname),
SCARG(uap, arg), p);
}
if (SCARG(uap, attrname) != NULL) {
error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp,
SCARG(uap, namespace), attrname, p);
} else {
error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp,
SCARG(uap, namespace), NULL, p);
}
vn_finished_write(mp);
/*
* VFS_EXTATTRCTL will have unlocked, but not de-ref'd,
* filename_vp, so vrele it if it is defined.
*/
if (filename_vp != NULL)
vrele(filename_vp);
return (error);
}
@ -3756,8 +3801,8 @@ extattr_set_file(p, uap)
iov++;
}
cnt = auio.uio_resid;
error = VOP_SETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred,
p);
error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, namespace), attrname,
&auio, p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
@ -3823,8 +3868,8 @@ extattr_get_file(p, uap)
iov++;
}
cnt = auio.uio_resid;
error = VOP_GETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred,
p);
error = VOP_GETEXTATTR(nd.ni_vp, SCARG(uap, namespace), attrname,
&auio, p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
@ -3859,8 +3904,8 @@ extattr_delete_file(p, uap)
NDFREE(&nd, 0);
return (error);
}
error = VOP_SETEXTATTR(nd.ni_vp, attrname, NULL, p->p_cred->pc_ucred,
p);
error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, namespace), attrname,
NULL, p->p_cred->pc_ucred, p);
NDFREE(&nd, 0);
vn_finished_write(mp);
return(error);

View File

@ -808,8 +808,8 @@ vn_kqfilter(struct file *fp, struct knote *kn)
* Set IO_NODELOCKED in ioflg if the vnode is already locked.
*/
int
vn_extattr_get(struct vnode *vp, int ioflg, const char *attrname, int *buflen,
char *buf, struct proc *p)
vn_extattr_get(struct vnode *vp, int ioflg, int namespace,
const char *attrname, int *buflen, char *buf, struct proc *p)
{
struct uio auio;
struct iovec iov;
@ -830,7 +830,7 @@ vn_extattr_get(struct vnode *vp, int ioflg, const char *attrname, int *buflen,
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
/* authorize attribute retrieval as kernel */
error = VOP_GETEXTATTR(vp, attrname, &auio, NULL, p);
error = VOP_GETEXTATTR(vp, namespace, attrname, &auio, NULL, p);
if ((ioflg & IO_NODELOCKED) == 0)
VOP_UNLOCK(vp, 0, p);
@ -846,8 +846,8 @@ vn_extattr_get(struct vnode *vp, int ioflg, const char *attrname, int *buflen,
* XXX failure mode if partially written?
*/
int
vn_extattr_set(struct vnode *vp, int ioflg, const char *attrname, int buflen,
char *buf, struct proc *p)
vn_extattr_set(struct vnode *vp, int ioflg, int namespace,
const char *attrname, int buflen, char *buf, struct proc *p)
{
struct uio auio;
struct iovec iov;
@ -872,7 +872,7 @@ vn_extattr_set(struct vnode *vp, int ioflg, const char *attrname, int buflen,
}
/* authorize attribute setting as kernel */
error = VOP_SETEXTATTR(vp, attrname, &auio, NULL, p);
error = VOP_SETEXTATTR(vp, namespace, attrname, &auio, NULL, p);
if ((ioflg & IO_NODELOCKED) == 0) {
vn_finished_write(mp);
@ -883,7 +883,8 @@ vn_extattr_set(struct vnode *vp, int ioflg, const char *attrname, int buflen,
}
int
vn_extattr_rm(struct vnode *vp, int ioflg, const char *attrname, struct proc *p)
vn_extattr_rm(struct vnode *vp, int ioflg, int namespace, const char *attrname,
struct proc *p)
{
struct mount *mp;
int error;
@ -895,7 +896,7 @@ vn_extattr_rm(struct vnode *vp, int ioflg, const char *attrname, struct proc *p)
}
/* authorize attribute removal as kernel */
error = VOP_SETEXTATTR(vp, attrname, NULL, NULL, p);
error = VOP_SETEXTATTR(vp, namespace, attrname, NULL, NULL, p);
if ((ioflg & IO_NODELOCKED) == 0) {
vn_finished_write(mp);

View File

@ -529,6 +529,7 @@ vop_aclcheck {
#
vop_getextattr {
IN struct vnode *vp;
IN int namespace;
IN const char *name;
INOUT struct uio *uio;
IN struct ucred *cred;
@ -540,6 +541,7 @@ vop_getextattr {
#
vop_setextattr {
IN struct vnode *vp;
IN int namespace;
IN const char *name;
INOUT struct uio *uio;
IN struct ucred *cred;

View File

@ -73,7 +73,9 @@ static int nullfs_unmount(struct mount *mp, int mntflags, struct proc *p);
static int nullfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp);
static int nullfs_vptofh(struct vnode *vp, struct fid *fhp);
static int nullfs_extattrctl(struct mount *mp, int cmd,
const char *attrname, caddr_t arg, struct proc *p);
struct vnode *filename_vp,
int namespace, const char *attrname,
struct proc *p);
/*
* Mount null layer
@ -408,15 +410,16 @@ nullfs_vptofh(vp, fhp)
}
static int
nullfs_extattrctl(mp, cmd, attrname, arg, p)
nullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, p)
struct mount *mp;
int cmd;
struct vnode *filename_vp;
int namespace;
const char *attrname;
caddr_t arg;
struct proc *p;
{
return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, attrname,
arg, p);
return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp,
namespace, attrname, p);
}

View File

@ -74,7 +74,8 @@ static int umapfs_vget __P((struct mount *mp, ino_t ino,
struct vnode **vpp));
static int umapfs_vptofh __P((struct vnode *vp, struct fid *fhp));
static int umapfs_extattrctl __P((struct mount *mp, int cmd,
const char *attrname, caddr_t arg,
struct vnode *filename_vp,
int namespace, const char *attrname,
struct proc *p));
/*
@ -430,15 +431,16 @@ umapfs_vptofh(vp, fhp)
}
static int
umapfs_extattrctl(mp, cmd, attrname, arg, p)
umapfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, p)
struct mount *mp;
int cmd;
struct vnode *filename_vp;
int namespace;
const char *attrname;
caddr_t arg;
struct proc *p;
{
return (VFS_EXTATTRCTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, attrname,
arg, p));
return (VFS_EXTATTRCTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd,
filename_vp, namespace, attrname, p));
}

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1999-2001 Robert N. M. Watson
* Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -37,8 +37,10 @@
* POSIX.1e ACL types and related constants.
*/
#define POSIX1E_ACL_ACCESS_EXTATTR_NAME "$posix1e.acl_access"
#define POSIX1E_ACL_DEFAULT_EXTATTR_NAME "$posix1e.acl_default"
#define POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM
#define POSIX1E_ACL_ACCESS_EXTATTR_NAME "posix1e.acl_access"
#define POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM
#define POSIX1E_ACL_DEFAULT_EXTATTR_NAME "posix1e.acl_default"
#define ACL_MAX_ENTRIES 32 /* maximum entries in an ACL */
#define _POSIX_ACL_PATH_MAX ACL_MAX_ENTRIES

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000 Robert N. M. Watson
* Copyright (c) 2000, 2001 Robert N. M. Watson
* All rights reserved.
*
* Copyright (c) 1999 Ilmar S. Habibulin
@ -36,7 +36,8 @@
#ifndef _SYS_CAPABILITY_H
#define _SYS_CAPABILITY_H
#define POSIX1E_CAPABILITY_EXTATTR_NAME "$posix1e.cap"
#define POSIX1E_CAPABILITY_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM
#define POSIX1E_CAPABILITY_EXTATTR_NAME "posix1e.cap"
typedef int cap_flag_t;
typedef int cap_flag_value_t;

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1999 Robert N. M. Watson
* Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -41,6 +41,12 @@
#ifndef _SYS_EXTATTR_H_
#define _SYS_EXTATTR_H_
#define EXTATTR_NAMESPACE_USER 0x00000001
#define EXTATTR_NAMESPACE_USER_STRING "user"
#define EXTATTR_NAMESPACE_SYSTEM 0x00000002
#define EXTATTR_NAMESPACE_SYSTEM_STRING "system"
#ifdef _KERNEL
#define EXTATTR_MAXNAMELEN NAME_MAX
@ -51,12 +57,14 @@
struct iovec;
__BEGIN_DECLS
int extattrctl(const char *path, int cmd, const char *attrname, char *arg);
int extattr_delete_file(const char *path, const char *attrname);
int extattr_get_file(const char *path, const char *attrname,
struct iovec *iovp, unsigned iovcnt);
int extattr_set_file(const char *path, const char *attrname,
struct iovec *iovp, unsigned iovcnt);
int extattrctl(const char *path, int cmd, const char *filename,
int namespace, const char *attrname);
int extattr_delete_file(const char *path, int namespace,
const char *attrname);
int extattr_get_file(const char *path, int namespace,
const char *attrname, struct iovec *iovp, unsigned iovcnt);
int extattr_set_file(const char *path, int namespace,
const char *attrname, struct iovec *iovp, unsigned iovcnt);
__END_DECLS
#endif /* !_KERNEL */

View File

@ -339,7 +339,8 @@ struct vfsops {
int (*vfs_init) __P((struct vfsconf *));
int (*vfs_uninit) __P((struct vfsconf *));
int (*vfs_extattrctl) __P((struct mount *mp, int cmd,
const char *attrname, caddr_t arg,
struct vnode *filename_vp,
int namespace, const char *attrname,
struct proc *p));
};
@ -357,8 +358,8 @@ struct vfsops {
#define VFS_VPTOFH(VP, FIDP) (*(VP)->v_mount->mnt_op->vfs_vptofh)(VP, FIDP)
#define VFS_CHECKEXP(MP, NAM, EXFLG, CRED) \
(*(MP)->mnt_op->vfs_checkexp)(MP, NAM, EXFLG, CRED)
#define VFS_EXTATTRCTL(MP, C, N, A, P) \
(*(MP)->mnt_op->vfs_extattrctl)(MP, C, N, A, P)
#define VFS_EXTATTRCTL(MP, C, FN, NS, N, P) \
(*(MP)->mnt_op->vfs_extattrctl)(MP, C, FN, NS, N, P)
#include <sys/module.h>
@ -453,8 +454,9 @@ int vfs_stdcheckexp __P((struct mount *mp, struct sockaddr *nam,
int vfs_stdvptofh __P((struct vnode *vp, struct fid *fhp));
int vfs_stdinit __P((struct vfsconf *));
int vfs_stduninit __P((struct vfsconf *));
int vfs_stdextattrctl __P((struct mount *mp, int cmd, const char *attrname,
caddr_t arg, struct proc *p));
int vfs_stdextattrctl __P((struct mount *mp, int cmd,
struct vnode *filename_vp, int namespace, const char *attrname,
struct proc *p));
/* XXX - these should be indirect functions!!! */
int softdep_process_worklist __P((struct mount *));

View File

@ -607,12 +607,12 @@ dev_t vn_todev __P((struct vnode *vp));
int vn_write_suspend_wait __P((struct vnode *vp, struct mount *mp,
int flags));
int vn_writechk __P((struct vnode *vp));
int vn_extattr_get __P((struct vnode *vp, int ioflg, const char *attrname,
int *buflen, char *buf, struct proc *p));
int vn_extattr_set __P((struct vnode *vp, int ioflg, const char *attrname,
int buflen, char *buf, struct proc *p));
int vn_extattr_rm(struct vnode *vp, int ioflg, const char *attrname,
struct proc *p);
int vn_extattr_get __P((struct vnode *vp, int ioflg, int namespace,
const char *attrname, int *buflen, char *buf, struct proc *p));
int vn_extattr_set __P((struct vnode *vp, int ioflg, int namespace,
const char *attrname, int buflen, char *buf, struct proc *p));
int vn_extattr_rm(struct vnode *vp, int ioflg, int namespace,
const char *attrname, struct proc *p);
int vfs_cache_lookup __P((struct vop_lookup_args *ap));
int vfs_object_create __P((struct vnode *vp, struct proc *p,
struct ucred *cred));

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1999, 2000 Robert N. M. Watson
* Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -73,8 +73,9 @@ MALLOC_DECLARE(M_EXTATTR);
struct vnode;
LIST_HEAD(ufs_extattr_list_head, ufs_extattr_list_entry);
struct ufs_extattr_list_entry {
LIST_ENTRY(ufs_extattr_list_entry) uele_entries;
struct ufs_extattr_fileheader uele_fileheader;
LIST_ENTRY(ufs_extattr_list_entry) uele_entries;
struct ufs_extattr_fileheader uele_fileheader;
int uele_namespace;
char uele_attrname[UFS_EXTATTR_MAXEXTATTRNAME];
struct vnode *uele_backing_vnode;
};
@ -93,8 +94,8 @@ void ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm);
int ufs_extattr_start(struct mount *mp, struct proc *p);
int ufs_extattr_autostart(struct mount *mp, struct proc *p);
int ufs_extattr_stop(struct mount *mp, struct proc *p);
int ufs_extattrctl(struct mount *mp, int cmd, const char *attrname,
caddr_t arg, struct proc *p);
int ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename,
int namespace, const char *attrname, struct proc *p);
int ufs_vop_getextattr(struct vop_getextattr_args *ap);
int ufs_vop_setextattr(struct vop_setextattr_args *ap);
void ufs_extattr_vnode_inactive(struct vnode *vp, struct proc *p);

View File

@ -40,6 +40,7 @@
#include <sys/mount.h>
#include <sys/lock.h>
#include <sys/dirent.h>
#include <sys/extattr.h>
#include <vm/vm_zone.h>
@ -52,6 +53,8 @@
#include "opt_ffs.h"
#ifdef FFS_EXTATTR
#define MIN(a,b) (((a)<(b))?(a):(b))
static MALLOC_DEFINE(M_UFS_EXTATTR, "ufs_extattr", "ufs extended attribute");
@ -60,16 +63,18 @@ static int ufs_extattr_valid_attrname(const char *attrname);
static int ufs_extattr_credcheck(struct vnode *vp,
struct ufs_extattr_list_entry *uele, struct ucred *cred, struct proc *p,
int access);
static int ufs_extattr_enable(struct ufsmount *ump, const char *attrname,
struct vnode *backing_vnode, struct proc *p);
static int ufs_extattr_disable(struct ufsmount *ump, const char *attrname,
struct proc *p);
static int ufs_extattr_get(struct vnode *vp, const char *name,
struct uio *uio, struct ucred *cred, struct proc *p);
static int ufs_extattr_set(struct vnode *vp, const char *name,
struct uio *uio, struct ucred *cred, struct proc *p);
static int ufs_extattr_rm(struct vnode *vp, const char *name,
struct ucred *cred, struct proc *p);
static int ufs_extattr_enable_with_open(struct ufsmount *ump,
struct vnode *vp, int namespace, const char *attrname, struct proc *p);
static int ufs_extattr_enable(struct ufsmount *ump, int namespace,
const char *attrname, struct vnode *backing_vnode, struct proc *p);
static int ufs_extattr_disable(struct ufsmount *ump, int namespace,
const char *attrname, struct proc *p);
static int ufs_extattr_get(struct vnode *vp, int namespace,
const char *name, struct uio *uio, struct ucred *cred, struct proc *p);
static int ufs_extattr_set(struct vnode *vp, int namespace,
const char *name, struct uio *uio, struct ucred *cred, struct proc *p);
static int ufs_extattr_rm(struct vnode *vp, int namespace,
const char *name, struct ucred *cred, struct proc *p);
/*
* Per-FS attribute lock protecting attribute operations.
@ -119,7 +124,8 @@ ufs_extattr_valid_attrname(const char *attrname)
* Must be holding uepm lock for the mount point.
*/
static struct ufs_extattr_list_entry *
ufs_extattr_find_attr(struct ufsmount *ump, const char *attrname)
ufs_extattr_find_attr(struct ufsmount *ump, int namespace,
const char *attrname)
{
struct ufs_extattr_list_entry *search_attribute;
@ -127,7 +133,8 @@ ufs_extattr_find_attr(struct ufsmount *ump, const char *attrname)
search_attribute;
search_attribute = LIST_NEXT(search_attribute, uele_entries)) {
if (!(strncmp(attrname, search_attribute->uele_attrname,
UFS_EXTATTR_MAXEXTATTRNAME))) {
UFS_EXTATTR_MAXEXTATTRNAME)) &&
(namespace == search_attribute->uele_namespace)) {
return (search_attribute);
}
}
@ -291,17 +298,18 @@ ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, char *dirname,
*vp = target_vp;
return (0);
}
#endif /* !FFS_EXTATTR_AUTOSTART */
/*
* Enable an EA using the passed file system, backing vnode, attribute name,
* and proc. Will perform a VOP_OPEN() on the vp, so expects vp to be locked
* when passed in. Will unlock vp, and grab its own reference, so the caller
* needs to vrele(), just not vput(). If the call fails, the lock is not
* released.
* namespace, and proc. Will perform a VOP_OPEN() on the vp, so expects vp
* to be locked when passed in. Will unlock vp, and grab its own reference,
* so the caller needs to vrele(), just not vput(). The unlock the vnode
* regardless of call success or failure.
*/
static int
ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp,
char *attrname, struct proc *p)
int namespace, const char *attrname, struct proc *p)
{
int error;
@ -309,6 +317,7 @@ ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp,
if (error) {
printf("ufs_extattr_enable_with_open.VOP_OPEN(): failed "
"with %d\n", error);
VOP_UNLOCK(vp, 0, p);
return (error);
}
@ -322,6 +331,7 @@ ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp,
* XXX: bug replicated from vn_open(): should
* VOP_CLOSE() here.
*/
VOP_UNLOCK(vp, 0, p);
return (error);
}
@ -331,9 +341,10 @@ ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp,
VOP_UNLOCK(vp, 0, p);
return (ufs_extattr_enable(ump, attrname, vp, p));
return (ufs_extattr_enable(ump, namespace, attrname, vp, p));
}
#ifdef FFS_EXTATTR_AUTOSTART
/*
* Given a locked directory vnode, iterate over the names in the directory
* and use ufs_extattr_lookup() to retrieve locked vnodes of potential
@ -344,7 +355,7 @@ ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp,
*/
static int
ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp,
struct proc *p)
int namespace, struct proc *p)
{
struct vop_readdir_args vargs;
struct dirent *dp, *edp;
@ -412,19 +423,18 @@ ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp,
vput(attr_vp);
} else {
error = ufs_extattr_enable_with_open(ump,
attr_vp, dp->d_name, p);
attr_vp, namespace, dp->d_name, p);
vrele(attr_vp);
if (error) {
printf("ufs_extattr_iterate_directory: "
"enable %s %d\n", dp->d_name,
error);
vput(attr_vp);
} else {
/*
* While it's nice to have some visual output here, skip for the time-being.
* Probably should be enabled by -v at boot.
printf("Autostarted %s\n", dp->d_name);
*/
vrele(attr_vp);
}
}
dp = (struct dirent *) ((char *)dp + dp->d_reclen);
@ -448,8 +458,8 @@ ufs_extattr_autostart(struct mount *mp, struct proc *p)
int error;
/*
* Does ".attribute" exist off the file system root? If so,
* automatically start EA's.
* Does UFS_EXTATTR_FSROOTSUBDIR exist off the file system root?
* If so, automatically start EA's.
*/
error = VFS_ROOT(mp, &rvp);
if (error) {
@ -458,7 +468,7 @@ ufs_extattr_autostart(struct mount *mp, struct proc *p)
}
error = ufs_extattr_lookup(rvp, UE_GETDIR_LOCKPARENT_DONT,
".attribute", &attr_dvp, p);
UFS_EXTATTR_FSROOTSUBDIR, &attr_dvp, p);
if (error) {
/* rvp ref'd but now unlocked */
vrele(rvp);
@ -473,7 +483,8 @@ ufs_extattr_autostart(struct mount *mp, struct proc *p)
vrele(rvp);
if (attr_dvp->v_type != VDIR) {
printf("ufs_extattr_autostart: .attribute != VDIR\n");
printf("ufs_extattr_autostart: %s != VDIR\n",
UFS_EXTATTR_FSROOTSUBDIR);
goto return_vput;
}
@ -485,10 +496,15 @@ ufs_extattr_autostart(struct mount *mp, struct proc *p)
}
/*
* Iterate over the directory. Eventually we may lookup sub-directories
* and iterate over them independently.
* Iterate over the directory. Eventually we will lookup sub-
* directories and iterate over them independently with different
* EA namespaces.
*
* XXX: Right now, assert that all attributes are in the system
* namespace.
*/
error = ufs_extattr_iterate_directory(VFSTOUFS(mp), attr_dvp, p);
error = ufs_extattr_iterate_directory(VFSTOUFS(mp), attr_dvp,
EXTATTR_NAMESPACE_SYSTEM, p);
if (error)
printf("ufs_extattr_iterate_directory returned %d\n", error);
@ -521,7 +537,8 @@ ufs_extattr_stop(struct mount *mp, struct proc *p)
while (LIST_FIRST(&ump->um_extattr.uepm_list) != NULL) {
uele = LIST_FIRST(&ump->um_extattr.uepm_list);
ufs_extattr_disable(ump, uele->uele_attrname, p);
ufs_extattr_disable(ump, uele->uele_namespace,
uele->uele_attrname, p);
}
ump->um_extattr.uepm_flags &= ~UFS_EXTATTR_UEPM_STARTED;
@ -536,11 +553,11 @@ ufs_extattr_stop(struct mount *mp, struct proc *p)
}
/*
* Enable a named attribute on the specified file system; provide a
* backing vnode to hold the attribute data.
* Enable a named attribute on the specified file system; provide an
* unlocked backing vnode to hold the attribute data.
*/
static int
ufs_extattr_enable(struct ufsmount *ump, const char *attrname,
ufs_extattr_enable(struct ufsmount *ump, int namespace, const char *attrname,
struct vnode *backing_vnode, struct proc *p)
{
struct ufs_extattr_list_entry *attribute;
@ -563,12 +580,13 @@ ufs_extattr_enable(struct ufsmount *ump, const char *attrname,
goto free_exit;
}
if (ufs_extattr_find_attr(ump, attrname)) {
if (ufs_extattr_find_attr(ump, namespace, attrname)) {
error = EEXIST;
goto free_exit;
}
strncpy(attribute->uele_attrname, attrname, UFS_EXTATTR_MAXEXTATTRNAME);
attribute->uele_namespace = namespace;
bzero(&attribute->uele_fileheader,
sizeof(struct ufs_extattr_fileheader));
@ -590,9 +608,8 @@ ufs_extattr_enable(struct ufsmount *ump, const char *attrname,
ump->um_extattr.uepm_ucred);
VOP_UNLOCK(backing_vnode, 0, p);
if (error) {
if (error)
goto free_exit;
}
if (auio.uio_resid != 0) {
printf("ufs_extattr_enable: malformed attribute header\n");
@ -627,7 +644,8 @@ ufs_extattr_enable(struct ufsmount *ump, const char *attrname,
* Disable extended attribute support on an FS.
*/
static int
ufs_extattr_disable(struct ufsmount *ump, const char *attrname, struct proc *p)
ufs_extattr_disable(struct ufsmount *ump, int namespace, const char *attrname,
struct proc *p)
{
struct ufs_extattr_list_entry *uele;
int error = 0;
@ -635,7 +653,7 @@ ufs_extattr_disable(struct ufsmount *ump, const char *attrname, struct proc *p)
if (!ufs_extattr_valid_attrname(attrname))
return (EINVAL);
uele = ufs_extattr_find_attr(ump, attrname);
uele = ufs_extattr_find_attr(ump, namespace, attrname);
if (!uele)
return (ENOENT);
@ -650,65 +668,83 @@ ufs_extattr_disable(struct ufsmount *ump, const char *attrname, struct proc *p)
}
/*
* VFS call to manage extended attributes in UFS.
* attrname, arg are userspace pointers from the syscall.
* VFS call to manage extended attributes in UFS. If filename_vp is
* non-NULL, it must be passed in locked, and regardless of errors in
* processing, will be unlocked.
*/
int
ufs_extattrctl(struct mount *mp, int cmd, const char *attrname,
caddr_t arg, struct proc *p)
ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
int namespace, const char *attrname, struct proc *p)
{
struct nameidata nd;
struct ufsmount *ump = VFSTOUFS(mp);
struct vnode *vp;
char local_attrname[UFS_EXTATTR_MAXEXTATTRNAME]; /* Incl. null. */
char *filename;
int error, flags;
size_t len;
int error;
/*
* Processes with privilege, but in jail, are not allowed to
* configure extended attributes.
*/
if ((error = suser_xxx(p->p_cred->pc_ucred, p, 0)))
if ((error = suser_xxx(p->p_cred->pc_ucred, p, 0))) {
if (filename_vp != NULL)
VOP_UNLOCK(filename_vp, 0, p);
return (error);
}
switch(cmd) {
case UFS_EXTATTR_CMD_START:
if (filename_vp != NULL) {
VOP_UNLOCK(filename_vp, 0, p);
return (EINVAL);
}
if (attrname != NULL)
return (EINVAL);
error = ufs_extattr_start(mp, p);
return (error);
case UFS_EXTATTR_CMD_STOP:
return (ufs_extattr_stop(mp, p));
if (filename_vp != NULL) {
VOP_UNLOCK(filename_vp, 0, p);
return (EINVAL);
}
if (attrname != NULL)
return (EINVAL);
error = ufs_extattr_stop(mp, p);
return (error);
case UFS_EXTATTR_CMD_ENABLE:
error = copyinstr(attrname, local_attrname,
UFS_EXTATTR_MAXEXTATTRNAME, &len);
if (error)
return (error);
filename = (char *) arg;
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, filename, p);
flags = FREAD | FWRITE;
error = vn_open(&nd, &flags, 0);
if (error)
return (error);
if (filename_vp == NULL)
return (EINVAL);
if (attrname == NULL) {
VOP_UNLOCK(filename_vp, 0, p);
return (EINVAL);
}
vp = nd.ni_vp;
VOP_UNLOCK(vp, 0, p);
/*
* ufs_extattr_enable_with_open() will always unlock the
* vnode, regardless of failure.
*/
ufs_extattr_uepm_lock(ump, p);
error = ufs_extattr_enable(ump, local_attrname, vp, p);
error = ufs_extattr_enable_with_open(ump, filename_vp,
namespace, attrname, p);
ufs_extattr_uepm_unlock(ump, p);
return (error);
case UFS_EXTATTR_CMD_DISABLE:
error = copyinstr(attrname, local_attrname,
UFS_EXTATTR_MAXEXTATTRNAME, &len);
if (filename_vp != NULL) {
VOP_UNLOCK(filename_vp, 0, p);
return (EINVAL);
}
if (attrname == NULL)
return (EINVAL);
ufs_extattr_uepm_lock(ump, p);
error = ufs_extattr_disable(ump, local_attrname, p);
error = ufs_extattr_disable(ump, namespace, attrname, p);
ufs_extattr_uepm_unlock(ump, p);
return (error);
@ -726,10 +762,6 @@ static int
ufs_extattr_credcheck(struct vnode *vp, struct ufs_extattr_list_entry *uele,
struct ucred *cred, struct proc *p, int access)
{
int system_namespace;
system_namespace = (strlen(uele->uele_attrname) >= 1 &&
uele->uele_attrname[0] == '$');
/*
* Kernel-invoked always succeeds.
@ -744,10 +776,14 @@ ufs_extattr_credcheck(struct vnode *vp, struct ufs_extattr_list_entry *uele,
* XXX What capability should apply here?
* Probably CAP_SYS_SETFFLAG.
*/
if (system_namespace)
switch (uele->uele_namespace) {
case EXTATTR_NAMESPACE_SYSTEM:
return (suser_xxx(cred, p, 0));
else
case EXTATTR_NAMESPACE_USER:
return (VOP_ACCESS(vp, access, cred, p));
default:
return (EPERM);
}
}
/*
@ -758,6 +794,7 @@ ufs_vop_getextattr(struct vop_getextattr_args *ap)
/*
vop_getextattr {
IN struct vnode *a_vp;
IN int a_namespace;
IN const char *a_name;
INOUT struct uio *a_uio;
IN struct ucred *a_cred;
@ -771,8 +808,8 @@ vop_getextattr {
ufs_extattr_uepm_lock(ump, ap->a_p);
error = ufs_extattr_get(ap->a_vp, ap->a_name, ap->a_uio, ap->a_cred,
ap->a_p);
error = ufs_extattr_get(ap->a_vp, ap->a_namespace, ap->a_name,
ap->a_uio, ap->a_cred, ap->a_p);
ufs_extattr_uepm_unlock(ump, ap->a_p);
@ -784,8 +821,8 @@ vop_getextattr {
* the attribute lock has already been grabbed.
*/
static int
ufs_extattr_get(struct vnode *vp, const char *name, struct uio *uio,
struct ucred *cred, struct proc *p)
ufs_extattr_get(struct vnode *vp, int namespace, const char *name,
struct uio *uio, struct ucred *cred, struct proc *p)
{
struct ufs_extattr_list_entry *attribute;
struct ufs_extattr_header ueh;
@ -801,12 +838,13 @@ ufs_extattr_get(struct vnode *vp, const char *name, struct uio *uio,
if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
return (EOPNOTSUPP);
if (strlen(name) == 0 || (strlen(name) == 1 && name[0] == '$')) {
if (strlen(name) == 0) {
/* XXX retrieve attribute lists. */
/* XXX should probably be checking for name == NULL? */
return (EINVAL);
}
attribute = ufs_extattr_find_attr(ump, name);
attribute = ufs_extattr_find_attr(ump, namespace, name);
if (!attribute)
return (ENOENT);
@ -923,6 +961,7 @@ ufs_vop_setextattr(struct vop_setextattr_args *ap)
/*
vop_setextattr {
IN struct vnode *a_vp;
IN int a_namespace;
IN const char *a_name;
INOUT struct uio *a_uio;
IN struct ucred *a_cred;
@ -938,11 +977,11 @@ vop_setextattr {
ufs_extattr_uepm_lock(ump, ap->a_p);
if (ap->a_uio != NULL)
error = ufs_extattr_set(ap->a_vp, ap->a_name, ap->a_uio,
ap->a_cred, ap->a_p);
error = ufs_extattr_set(ap->a_vp, ap->a_namespace, ap->a_name,
ap->a_uio, ap->a_cred, ap->a_p);
else
error = ufs_extattr_rm(ap->a_vp, ap->a_name, ap->a_cred,
ap->a_p);
error = ufs_extattr_rm(ap->a_vp, ap->a_namespace, ap->a_name,
ap->a_cred, ap->a_p);
ufs_extattr_uepm_unlock(ump, ap->a_p);
@ -954,8 +993,8 @@ vop_setextattr {
* assumes that the attribute lock has already been grabbed.
*/
static int
ufs_extattr_set(struct vnode *vp, const char *name, struct uio *uio,
struct ucred *cred, struct proc *p)
ufs_extattr_set(struct vnode *vp, int namespace, const char *name,
struct uio *uio, struct ucred *cred, struct proc *p)
{
struct ufs_extattr_list_entry *attribute;
struct ufs_extattr_header ueh;
@ -974,7 +1013,7 @@ ufs_extattr_set(struct vnode *vp, const char *name, struct uio *uio,
if (!ufs_extattr_valid_attrname(name))
return (EINVAL);
attribute = ufs_extattr_find_attr(ump, name);
attribute = ufs_extattr_find_attr(ump, namespace, name);
if (!attribute)
return (ENOENT);
@ -1059,8 +1098,8 @@ ufs_extattr_set(struct vnode *vp, const char *name, struct uio *uio,
* Assumes the attribute lock has already been grabbed.
*/
static int
ufs_extattr_rm(struct vnode *vp, const char *name, struct ucred *cred,
struct proc *p)
ufs_extattr_rm(struct vnode *vp, int namespace, const char *name,
struct ucred *cred, struct proc *p)
{
struct ufs_extattr_list_entry *attribute;
struct ufs_extattr_header ueh;
@ -1079,7 +1118,7 @@ ufs_extattr_rm(struct vnode *vp, const char *name, struct ucred *cred,
if (!ufs_extattr_valid_attrname(name))
return (EINVAL);
attribute = ufs_extattr_find_attr(ump, name);
attribute = ufs_extattr_find_attr(ump, namespace, name);
if (!attribute)
return (ENOENT);
@ -1191,7 +1230,10 @@ ufs_extattr_vnode_inactive(struct vnode *vp, struct proc *p)
}
LIST_FOREACH(uele, &ump->um_extattr.uepm_list, uele_entries)
ufs_extattr_rm(vp, uele->uele_attrname, NULL, p);
ufs_extattr_rm(vp, uele->uele_namespace, uele->uele_attrname,
NULL, p);
ufs_extattr_uepm_unlock(ump, p);
}
#endif /* !FFS_EXTATTR */