Browse Source

Merge remote-tracking branch 'origin/hardened/current/tmpfs_extattr' into hardened/current/master

hardened/current/safestack
Shawn Webb 1 month ago
parent
commit
114c00dbd0
3 changed files with 226 additions and 0 deletions
  1. +28
    -0
      sys/fs/tmpfs/tmpfs.h
  2. +7
    -0
      sys/fs/tmpfs/tmpfs_subr.c
  3. +191
    -0
      sys/fs/tmpfs/tmpfs_vnops.c

+ 28
- 0
sys/fs/tmpfs/tmpfs.h View File

@@ -130,6 +130,28 @@ RB_HEAD(tmpfs_dir, tmpfs_dirent);
#define TMPFS_DIRCOOKIE_DUP_MAX \
(TMPFS_DIRCOOKIE_DUP | TMPFS_DIRCOOKIE_MASK)

/*
* Extended attribute support.
*
* A good portion of this support is based upon the UFS
* implementation. Stand on the shoulders of giants. This
* implementation aims to only provide support for applying extended
* attributes to files (VREG).
*/

#define TMPFS_EXTATTR_MAXNAME 33 /* Includes terminating NUL */
#define TMPFS_EXTATTR_MAXVALUESIZE 64

struct tmpfs_extattr_list_entry {
LIST_ENTRY(tmpfs_extattr_list_entry) tele_entries;
int tele_attrnamespace;
char tele_attrname[TMPFS_EXTATTR_MAXNAME];
void *tele_value;
size_t tele_value_size;
};

LIST_HEAD(tmpfs_extattr_list_head, tmpfs_extattr_list_entry);

/*
* Internal representation of a tmpfs file system node.
*
@@ -287,6 +309,12 @@ struct tmpfs_node {
* a position within the file is accessed.
*/
vm_object_t tn_aobj; /* (c) */

/*
* The extended attributes list, which may be
* empty.
*/
struct tmpfs_extattr_list_head tn_extattr_list; /* (i) */
} tn_reg;
} tn_spec; /* (v) */
};

+ 7
- 0
sys/fs/tmpfs/tmpfs_subr.c View File

@@ -336,6 +336,7 @@ tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount *tmp, enum vtype type,
break;

case VREG:
LIST_INIT(&(nnode->tn_reg.tn_extattr_list));
obj = nnode->tn_reg.tn_aobj =
vm_pager_allocate(OBJT_SWAP, NULL, 0, VM_PROT_DEFAULT, 0,
NULL /* XXXKIB - tmpfs needs swap reservation */);
@@ -381,6 +382,7 @@ bool
tmpfs_free_node_locked(struct tmpfs_mount *tmp, struct tmpfs_node *node,
bool detach)
{
struct tmpfs_extattr_list_entry *attr, *tattr;
vm_object_t uobj;

TMPFS_MP_ASSERT_LOCKED(tmp);
@@ -421,6 +423,11 @@ tmpfs_free_node_locked(struct tmpfs_mount *tmp, struct tmpfs_node *node,
break;

case VREG:
LIST_FOREACH_SAFE(attr, &(node->tn_reg.tn_extattr_list),
tele_entries, tattr) {
free(attr->tele_value, M_TEMP);
free(attr, M_TEMP);
}
uobj = node->tn_reg.tn_aobj;
if (uobj != NULL) {
if (uobj->size != 0)

+ 191
- 0
sys/fs/tmpfs/tmpfs_vnops.c View File

@@ -70,6 +70,20 @@ SYSCTL_INT(_vfs_tmpfs, OID_AUTO, rename_restarts, CTLFLAG_RD,
__DEVOLATILE(int *, &tmpfs_rename_restarts), 0,
"Times rename had to restart due to lock contention");

static struct tmpfs_extattr_list_entry *tmpfs_node_has_extattr(
struct tmpfs_node *, int, const char *);

static int tmpfs_extattr_set(struct vnode *, int, const char *,
struct uio *, struct ucred *, struct thread *);

static int tmpfs_extattr_get(struct vnode *, int, const char *,
struct uio *, size_t *, struct ucred *, struct thread *);

static int tmpfs_listextattr(struct vop_listextattr_args *);

static int tmpfs_extattr_list(struct vnode *, int, struct uio *,
size_t *, struct ucred *, struct thread *);

static int
tmpfs_vn_get_ino_alloc(struct mount *mp, void *arg, int lkflags,
struct vnode **rvp)
@@ -1610,6 +1624,180 @@ restart:
return (ENOENT);
}

static struct tmpfs_extattr_list_entry *
tmpfs_node_has_extattr(struct tmpfs_node *node, int attrnamespace,
const char *name)
{
struct tmpfs_extattr_list_entry *entry, *tentry;

LIST_FOREACH_SAFE(entry, &(node->tn_reg.tn_extattr_list),
tele_entries, tentry) {
if (attrnamespace != entry->tele_attrnamespace) {
continue;
}

if (!strcmp(name, entry->tele_attrname)) {
return (entry);
}
}

return (NULL);
}

static int
tmpfs_getextattr(struct vop_getextattr_args *ap)
{

return (tmpfs_extattr_get(ap->a_vp, ap->a_attrnamespace,
ap->a_name, ap->a_uio, ap->a_size, ap->a_cred, ap->a_td));
}

static int
tmpfs_extattr_get(struct vnode *vp, int attrnamespace, const char *name,
struct uio *uio, size_t *size, struct ucred *cred, struct thread *td)
{
struct tmpfs_extattr_list_entry *attr;
struct tmpfs_node *node;
size_t len;
int error;

error = 0;

if (vp->v_type != VREG) {
return (EOPNOTSUPP);
}

node = VP_TO_TMPFS_NODE(vp);

attr = tmpfs_node_has_extattr(node, attrnamespace, name);
if (attr == NULL) {
return (ENOATTR);
}

if (size) {
*size = attr->tele_value_size;
}

if (uio != NULL) {
len = MIN(attr->tele_value_size, uio->uio_resid);
uio->uio_resid = len;
uio->uio_offset = 0;
error = uiomove(attr->tele_value, len, uio);
}

return (error);
}

static int
tmpfs_setextattr(struct vop_setextattr_args *ap)
{

return (tmpfs_extattr_set(ap->a_vp, ap->a_attrnamespace,
ap->a_name, ap->a_uio, ap->a_cred, ap->a_td));
}

static int
tmpfs_extattr_set(struct vnode *vp, int attrnamespace, const char *name,
struct uio *uio, struct ucred *cred, struct thread *td)
{
struct tmpfs_extattr_list_entry *attr;
struct tmpfs_node *node;
size_t sz;

if (vp->v_type != VREG) {
return (EOPNOTSUPP);
}

if (uio->uio_resid > TMPFS_EXTATTR_MAXVALUESIZE) {
return (EINVAL);
}

if (strlen(name) == 0) {
return (EINVAL);
}

if (strlen(name) >= TMPFS_EXTATTR_MAXNAME) {
return (EINVAL);
}

node = VP_TO_TMPFS_NODE(vp);

attr = tmpfs_node_has_extattr(node, attrnamespace, name);
if (attr == NULL) {
sz = MIN(TMPFS_EXTATTR_MAXVALUESIZE, uio->uio_resid);
attr = malloc(sizeof(*attr), M_TEMP, M_WAITOK|M_ZERO);

attr->tele_value = malloc(sz, M_TEMP, M_WAITOK);
attr->tele_value_size = sz;
attr->tele_attrnamespace = attrnamespace;
strncpy(attr->tele_attrname, name,
sizeof(attr->tele_attrname)-1);

uiomove(attr->tele_value, sz, uio);

LIST_INSERT_HEAD(&(node->tn_reg.tn_extattr_list),
attr, tele_entries);
}

return (0);
}

static int
tmpfs_listextattr(struct vop_listextattr_args *ap)
{

return tmpfs_extattr_list(ap->a_vp, ap->a_attrnamespace,
ap->a_uio, ap->a_size, ap->a_cred, ap->a_td);
}

static int
tmpfs_extattr_list(struct vnode *vp, int attrnamespace, struct uio *uio,
size_t *size, struct ucred *cred, struct thread *td)
{
struct tmpfs_extattr_list_entry *attr, *tattr;
struct tmpfs_node *node;
size_t namelen;
uint8_t namelen8;
int error;

error = 0;

if (vp->v_type != VREG) {
return (EOPNOTSUPP);
}

node = VP_TO_TMPFS_NODE(vp);

if (size) {
*size = 0;
}

LIST_FOREACH_SAFE(attr, &(node->tn_reg.tn_extattr_list),
tele_entries, tattr) {
if (attr->tele_attrnamespace != attrnamespace) {
continue;
}

namelen = strlen(attr->tele_attrname);
if (size) {
*size += namelen + namelen8;
} else if (uio != NULL) {
namelen8 = namelen;
error = uiomove(&namelen8, sizeof(namelen8), uio);
if (error) {
break;
}
error = uiomove(attr->tele_attrname, namelen, uio);
}

if (error) {
break;
}
}

return (error);
}

/*
* Vnode operations vector used for files stored in a tmpfs file system.
*/
@@ -1624,6 +1812,9 @@ struct vop_vector tmpfs_vnodeop_entries = {
.vop_access = tmpfs_access,
.vop_getattr = tmpfs_getattr,
.vop_setattr = tmpfs_setattr,
.vop_getextattr = tmpfs_getextattr,
.vop_setextattr = tmpfs_setextattr,
.vop_listextattr = tmpfs_listextattr,
.vop_read = tmpfs_read,
.vop_write = tmpfs_write,
.vop_fsync = tmpfs_fsync,

Loading…
Cancel
Save