438 lines
12 KiB
Groff
438 lines
12 KiB
Groff
.\" $NetBSD: fileassoc.9,v 1.8 2006/08/20 10:38:23 blymn Exp $
|
|
.\"
|
|
.\" Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
|
|
.\" All rights reserved.
|
|
.\"
|
|
.\" Redistribution and use in source and binary forms, with or without
|
|
.\" modification, are permitted provided that the following conditions
|
|
.\" are met:
|
|
.\" 1. Redistributions of source code must retain the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer.
|
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer in the
|
|
.\" documentation and/or other materials provided with the distribution.
|
|
.\" 3. All advertising materials mentioning features or use of this software
|
|
.\" must display the following acknowledgement:
|
|
.\" This product includes software developed by Elad Efrat.
|
|
.\" 4. The name of the author may not be used to endorse or promote products
|
|
.\" derived from this software without specific prior written permission.
|
|
.\"
|
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
.\"
|
|
.Dd August 19, 2006
|
|
.Dt FILEASSOC 9
|
|
.Os
|
|
.Sh NAME
|
|
.Nm fileassoc
|
|
.Nd in-kernel, file-system independent, file-meta data association
|
|
.Sh SYNOPSIS
|
|
.In sys/fileassoc.h
|
|
.Sh DESCRIPTION
|
|
The
|
|
.Nm
|
|
KPI allows association of meta-data with files independent of file-system
|
|
support for such elaborate meta-data.
|
|
.Pp
|
|
A system can have a maximum number of
|
|
.Dv FILEASSOC_NHOOKS
|
|
fileassocs associated with each file.
|
|
.Pp
|
|
When plugging a new fileassoc to the system, a developer can specify private
|
|
data to be associated with every file, as well as (potentially different)
|
|
private data to be associated with every file-system mount.
|
|
.Pp
|
|
For example, a developer might choose to associate a custom ACL with every
|
|
file, and a count of total files with ACLs with the mount.
|
|
.Ss Kernel Programming Interface
|
|
Designed with simplicity in mind, the
|
|
.Nm
|
|
KPI usually accepts four different types of parameters to the most commonly
|
|
used routines:
|
|
.Bl -tag -width "123456"
|
|
.It Ft struct mount * Ar mp
|
|
Describing a mount on which to take action.
|
|
.It Ft struct vnode * Ar vp
|
|
Describing a file on which to take action.
|
|
.It Ft fileassoc_t Ar id
|
|
Describing an id, as returned from a successful call to
|
|
.Fn fileassoc_register .
|
|
.It Ft void * Ar data
|
|
Describing a custom private data block, attached to either a file or a mount.
|
|
.El
|
|
.Pp
|
|
Before using the
|
|
.Nm
|
|
KPI it is important to keep in mind that the interface provides memory
|
|
management only for
|
|
.Nm
|
|
internal memory.
|
|
Any additional memory stored in the tables (such as private data-structures
|
|
used by custom fileassocs) should be allocated and freed by the developer.
|
|
.Pp
|
|
.Nm
|
|
provides the ability to specify a
|
|
.Dq cleanup
|
|
routine to
|
|
.Fn fileassoc_register
|
|
(see below)
|
|
to be called whenever an entry for a file or a mount is deleted.
|
|
.Ss Fileassoc Registration and Deregistration Routines
|
|
These routines allow a developer to allocate a
|
|
.Nm
|
|
slot to be used for private data.
|
|
.Bl -tag -width "123456"
|
|
.It Ft int Fn fileassoc_register "const char *name" "fileassoc_cleanup_cb cleanup_cb"
|
|
Registers a new fileassoc as
|
|
.Ar name ,
|
|
and returns an
|
|
.Ft int
|
|
to be used as a metahhook-id in subsequent calls to the
|
|
.Nm
|
|
subsystem to identify the fileassoc, or \-1 on failure.
|
|
.Pp
|
|
If
|
|
.Ar cleanup_cb
|
|
is not
|
|
.Dv NULL ,
|
|
it will be called during delete/clear operations (see routines below) with
|
|
indication whether the passed data is file- or mount-specific.
|
|
.Pp
|
|
.Ar cleanup_cb
|
|
should be a function receiving a
|
|
.Ft void *
|
|
and an
|
|
.Ft int ,
|
|
returning
|
|
.Ft void .
|
|
See the
|
|
.Sx EXAMPLES
|
|
section for illustration.
|
|
.Pp
|
|
.It Ft int Fn fileassoc_deregister "fileassoc_t id"
|
|
Deregisters a
|
|
.Nm fileassoc
|
|
whose id is
|
|
.Ar id .
|
|
.Pp
|
|
Note that calling
|
|
.Fn fileassoc_deregister
|
|
only frees the associated slot in the
|
|
.Nm
|
|
subsystem.
|
|
It is up to the developer to take care of garbage collection.
|
|
.El
|
|
.Ss Lookup Routines
|
|
These routines allow lookup of
|
|
.Nm
|
|
mounts, files, and private data attached to them.
|
|
.Bl -tag -width "123456"
|
|
.It Ft void * Fn fileassoc_tabledata_lookup "struct mount *mp" "fileassoc_t id"
|
|
Return table-wide private data in
|
|
.Ar mp
|
|
for
|
|
.Ar id .
|
|
.Pp
|
|
.It Ft void * Fn fileassoc_lookup "struct vnode *vp" "fileassoc_t id"
|
|
Returns the private data for the file/id combination
|
|
or
|
|
.Dv NULL
|
|
if not found.
|
|
.It Ft void * Fn fileassoc_lookup_hint "struct vnode *vp" "fileassoc_t id" \
|
|
"uint64_t hint"
|
|
Returns the private data for the file/id combination or
|
|
.Dv NULL
|
|
if not found.
|
|
.Pp
|
|
.Ar hint
|
|
is used to save calculation.
|
|
.Pp
|
|
While this routine can be used to bypass internal calculation for critical
|
|
code paths, it exposes implementation internals and will require special
|
|
care if the
|
|
.Nm
|
|
implementation changes.
|
|
.El
|
|
.Ss Mount-wide Routines
|
|
.Bl -tag -width "123456"
|
|
.It Ft int Fn fileassoc_table_add "struct mount *mp" "size_t size"
|
|
Creates a new fileassoc table for
|
|
.Ar mp
|
|
with at least
|
|
.Ar size
|
|
slots.
|
|
.Pp
|
|
.It Ft int Fn fileassoc_table_delete "struct mount *mp"
|
|
Deletes a fileassoc table for
|
|
.Ar mp .
|
|
.Pp
|
|
If specified, the fileassoc's
|
|
.Dq cleanup routine
|
|
will be called with a pointer to the private data-structure and indication of
|
|
.Dv FILEASSOC_CLEANUP_TABLE .
|
|
.Pp
|
|
.It Ft int Fn fileassoc_table_clear "struct mount *mp" "fileassoc_t id"
|
|
Clear all table entries for
|
|
.Ar fileassoc
|
|
from
|
|
.Ar mp .
|
|
.Pp
|
|
If specified, the fileassoc's
|
|
.Dq cleanup routine
|
|
will be called with a pointer to the private data-structure and indication of
|
|
either
|
|
.Dv FILEASSOC_CLEANUP_FILE
|
|
or
|
|
.Dv FILEASSOC_CLEANUP_TABLE
|
|
as appropriate.
|
|
.Pp
|
|
.It Ft int Fn fileassoc_tabledata_add "struct mount *mp" "fileassoc_t id" "void *data"
|
|
Add table-wide fileassoc-specific data in
|
|
.Ar data
|
|
to
|
|
.Ar mp
|
|
for
|
|
.Ar id .
|
|
.Pp
|
|
.It Ft int Fn fileassoc_tabledata_clear "struct mount *mp" "fileassoc_t id"
|
|
Clear table-wide fileassoc-specific data in
|
|
.Ar mp
|
|
for
|
|
.Ar id .
|
|
.It Ft int Fn fileassoc_table_run "struct mount *mp" "fileassoc_t id" \
|
|
"fileassoc_cb_t cb"
|
|
For each entry for
|
|
.Ar id ,
|
|
call
|
|
.Ar cb
|
|
with the entry being the argument.
|
|
.Pp
|
|
.Ar cb
|
|
is a function returning
|
|
.Ft void
|
|
and receiving one
|
|
.Ft "void *"
|
|
parameter.
|
|
.El
|
|
.Ss File-specific Routines
|
|
.Bl -tag -width "123456"
|
|
.It Ft int Fn fileassoc_file_delete "struct vnode *vp"
|
|
Delete the fileassoc entry for
|
|
.Ar vp .
|
|
.Pp
|
|
If specified, the fileassoc's
|
|
.Dq cleanup routine
|
|
will be called with a pointer to the private data-structure and indication of
|
|
.Dv FILEASSOC_CLEANUP_FILE .
|
|
.El
|
|
.Ss Fileassoc-specific Routines
|
|
.Bl -tag -width "123456"
|
|
.It Ft int Fn fileassoc_add "struct vnode *vp" "fileassoc_t id" "void *data"
|
|
Add private data in
|
|
.Ar data
|
|
for
|
|
.Ar vp ,
|
|
for the fileassoc specified by
|
|
.Ar id .
|
|
.Pp
|
|
.It Ft int Fn fileassoc_add_hint "struct vnode *vp" "fileassoc_t id" \
|
|
"void *data" "uint64_t hint"
|
|
Add private data in
|
|
.Ar data
|
|
for
|
|
.Ar vp
|
|
for the fileassoc specified by
|
|
.Ar id
|
|
using
|
|
.Ar hint
|
|
to save calculation.
|
|
.Pp
|
|
While this routine can be used to bypass internal calculation for critical
|
|
code paths, it exposes implementation internals and will require special
|
|
care if the
|
|
.Nm
|
|
implementation changes.
|
|
.Pp
|
|
.It Ft int Fn fileassoc_clear "struct vnode *vp" "fileassoc_t id"
|
|
Clear the private data for
|
|
.Ar vp ,
|
|
for the fileassoc specified by
|
|
.Ar id .
|
|
.Pp
|
|
If specified, the fileassoc's
|
|
.Dq cleanup routine
|
|
will be called with a pointer to the private data-structure and indication of
|
|
.Dv FILEASSOC_CLEANUP_FILE .
|
|
.El
|
|
.Ss Misc. Routines
|
|
.Bl -tag -width "123456"
|
|
.It Ft void Fn fileassoc_init "void"
|
|
Initializes the
|
|
.Nm
|
|
subsystem.
|
|
.Fn fileassoc_init
|
|
is called once during system boot.
|
|
.El
|
|
.Sh EXAMPLES
|
|
The following code examples should give you a clue on using
|
|
.Nm
|
|
for your purposes.
|
|
.Pp
|
|
First, we'll begin with registering a new id.
|
|
We need to do that to save a slot for private data storage with each mount
|
|
and/or file:
|
|
.Bd -literal -offset indent
|
|
fileassoc_t myhook_id;
|
|
|
|
myhook_id = fileassoc_register("my_hook", myhook_cleanup);
|
|
if (myhook_id == -1)
|
|
...handle error...
|
|
.Ed
|
|
.Pp
|
|
In the above example we pass a
|
|
.Fn myhook_cleanup
|
|
routine.
|
|
It could look something like this:
|
|
.Bd -literal -offset indent
|
|
void
|
|
myhook_cleanup(void *data, int what)
|
|
{
|
|
if (what == FILEASSOC_CLEANUP_FILE) {
|
|
printf("Myhook: Removing entry for file.\n");
|
|
...handle file entry removal...
|
|
free(data, M_TEMP);
|
|
} else if (what == FILEASSOC_CLEANUP_TABLE) {
|
|
printf("Myhook: Removing entry for mount.\n");
|
|
...handle mount entry removal...
|
|
free(data, M_TEMP);
|
|
}
|
|
}
|
|
.Ed
|
|
.Pp
|
|
Another useful thing would be to add our private data to a file.
|
|
For example, let's assume we keep a custom ACL with each file:
|
|
.Bd -literal -offset indent
|
|
int
|
|
myhook_acl_add(struct vnode *vp, struct myhook_acl *acl)
|
|
{
|
|
int error;
|
|
|
|
error = fileassoc_add(vp, myhook_id, acl);
|
|
if (error) {
|
|
printf("Myhook: Could not add ACL.\n");
|
|
...handle error...
|
|
}
|
|
|
|
printf("Myhook: Added ACL.\n");
|
|
|
|
return (0);
|
|
}
|
|
.Ed
|
|
.Pp
|
|
Adding an entry will override any entry that previously exists.
|
|
.Pp
|
|
The above can fail, usually when there is no table for the mount.
|
|
Creating a new table is simple:
|
|
.Bd -literal -offset indent
|
|
int error;
|
|
|
|
error = fileassoc_table_add(vp-\*[Gt]v_mount, nentries);
|
|
if (error)
|
|
...handle error...
|
|
.Ed
|
|
.Pp
|
|
The second argument to
|
|
.Fn fileassoc_table_add ,
|
|
.Ar nentries ,
|
|
should be approximately the number of files it is predicted that will
|
|
have entries in the table, although you can provide a pseudo-safe constant
|
|
value (like 128, for example).
|
|
.Pp
|
|
Whatever your plug is, eventually you'll want to access the private data you
|
|
store with each file.
|
|
To do that you can use the following:
|
|
.Bd -literal -offset indent
|
|
int
|
|
myhook_acl_access(struct vnode *vp, int access_flags)
|
|
{
|
|
struct myhook_acl *acl;
|
|
|
|
acl = fileassoc_lookup(vp, myhook_id);
|
|
if (acl == NULL)
|
|
return (0);
|
|
|
|
error = myhook_acl_eval(acl, access_flags);
|
|
if (error) {
|
|
printf("Myhook: Denying access based on ACL decision.\n");
|
|
return (error);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
.Ed
|
|
.Pp
|
|
And, in some cases, it may be desired to remove private data associated with
|
|
an file:
|
|
.Bd -literal -offset indent
|
|
int error;
|
|
|
|
error = fileassoc_clear(vp, myhook_id);
|
|
if (error) {
|
|
printf("Myhook: Error occured during fileassoc removal.\n");
|
|
...handle error...
|
|
}
|
|
.Ed
|
|
.Pp
|
|
As mentioned previously, the call to
|
|
.Fn fileassoc_clear
|
|
will result in a call to the
|
|
.Dq cleanup routine
|
|
specified in the initial call to
|
|
.Fn fileassoc_register .
|
|
.Pp
|
|
The above should be enough to get you started.
|
|
.Pp
|
|
For example usage of
|
|
.Nm ,
|
|
see the Veriexec code.
|
|
.Sh CODE REFERENCES
|
|
.Pa src/sys/kern/kern_verifiedexec.c
|
|
.Sh HISTORY
|
|
The
|
|
.Nm
|
|
KPI first appeared in
|
|
.Nx 4.0 .
|
|
.Sh AUTHORS
|
|
.An Elad Efrat Aq elad@NetBSD.org
|
|
designed and implemented the
|
|
.Nm
|
|
KPI.
|
|
.Sh CAVEATS
|
|
The current implementation of
|
|
.Nm
|
|
uses the file-id as returned from a
|
|
.Fn VOP_GETATTR
|
|
call to uniquely identify a file inside a mount.
|
|
KPI routines that can result in a call to
|
|
.Fn VOP_GETATTR
|
|
are
|
|
.Fn fileassoc_lookup ,
|
|
.Fn fileassoc_add ,
|
|
.Fn fileassoc_file_delete ,
|
|
and
|
|
.Fn fileassoc_clear .
|
|
This should be taken into consideration when using the interface.
|
|
.Pp
|
|
For critical code paths, a hinted version of the routines is supplied as a
|
|
mean to bypass internal calculation.
|
|
.Pp
|
|
This limitation is planned on being removed.
|