okay, since there was no way to divide this to two commits, here it goes..
introduce fileassoc(9), a kernel interface for associating meta-data with files using in-kernel memory. this is very similar to what we had in veriexec till now, only abstracted so it can be used more easily by more consumers. this also prompted the redesign of the interface, making it work on vnodes and mounts and not directly on devices and inodes. internally, we still use file-id but that's gonna change soon... the interface will remain consistent. as a result, veriexec went under some heavy changes to conform to the new interface. since we no longer use device numbers to identify file-systems, the veriexec sysctl stuff changed too: kern.veriexec.count.dev_N is now kern.veriexec.tableN.* where 'N' is NOT the device number but rather a way to distinguish several mounts. also worth noting is the plugging of unmount/delete operations wrt/fileassoc and veriexec. tons of input from yamt@, wrstuden@, martin@, and christos@.
This commit is contained in:
parent
a1c2fd0906
commit
b5d09ef065
@ -1,4 +1,4 @@
|
||||
# $NetBSD: mi,v 1.898 2006/07/13 11:43:54 he Exp $
|
||||
# $NetBSD: mi,v 1.899 2006/07/14 18:41:41 elad Exp $
|
||||
./etc/mtree/set.comp comp-sys-root
|
||||
./usr/bin/addr2line comp-debug-bin bfd
|
||||
./usr/bin/ar comp-util-bin bfd
|
||||
@ -5852,6 +5852,7 @@
|
||||
./usr/share/man/cat9/ffree.0 comp-sys-catman .cat
|
||||
./usr/share/man/cat9/fgetown.0 comp-sys-catman .cat
|
||||
./usr/share/man/cat9/file.0 comp-sys-catman .cat
|
||||
./usr/share/man/cat9/fileassoc.0 comp-sys-catman .cat
|
||||
./usr/share/man/cat9/filedesc.0 comp-sys-catman .cat
|
||||
./usr/share/man/cat9/firmload.0 comp-sys-catman .cat
|
||||
./usr/share/man/cat9/firmware_close.0 comp-sys-catman .cat
|
||||
@ -9980,6 +9981,7 @@
|
||||
./usr/share/man/man9/ffree.9 comp-sys-man .man
|
||||
./usr/share/man/man9/fgetown.9 comp-sys-man .man
|
||||
./usr/share/man/man9/file.9 comp-sys-man .man
|
||||
./usr/share/man/man9/fileassoc.9 comp-sys-man .man
|
||||
./usr/share/man/man9/filedesc.9 comp-sys-man .man
|
||||
./usr/share/man/man9/firmload.9 comp-sys-man .man
|
||||
./usr/share/man/man9/firmware_close.9 comp-sys-man .man
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: sysctl.3,v 1.170 2006/05/16 00:08:24 elad Exp $
|
||||
.\" $NetBSD: sysctl.3,v 1.171 2006/07/14 18:41:40 elad Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@ -29,7 +29,7 @@
|
||||
.\"
|
||||
.\" @(#)sysctl.3 8.4 (Berkeley) 5/9/95
|
||||
.\"
|
||||
.Dd April 26, 2006
|
||||
.Dd July 14, 2006
|
||||
.Dt SYSCTL 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -953,16 +953,12 @@ The variables are as follows:
|
||||
Returns a string with the supported algorithms in Verified Exec.
|
||||
.It Li VERIEXEC_COUNT
|
||||
Variables are added to this node as new hash tables are created to
|
||||
contain Verified Exec data for a new device.
|
||||
Each variable in the node
|
||||
will have a name in the form of
|
||||
.No dev_ Ns Aq id
|
||||
where
|
||||
.Aq id
|
||||
is the device id.
|
||||
For example, the variable for the root device may be dev_0.
|
||||
The value of this
|
||||
variable will be the amount of fingerprinted files on the device.
|
||||
contain Veriexec data for a new mount.
|
||||
Each mount will be under its own
|
||||
.No tableN
|
||||
node.
|
||||
Under each node there will be three variables, indicating the mount
|
||||
point, the file-system type, and the number of entries.
|
||||
.It Li VERIEXEC_STRICT
|
||||
Controls the strict level of Verified Exec.
|
||||
The strict level defines how
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: sysctl.8,v 1.147 2006/05/29 19:35:31 liamjfoy Exp $
|
||||
.\" $NetBSD: sysctl.8,v 1.148 2006/07/14 18:41:40 elad Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2004 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
@ -61,7 +61,7 @@
|
||||
.\"
|
||||
.\" @(#)sysctl.8 8.1 (Berkeley) 6/6/93
|
||||
.\"
|
||||
.Dd May 29, 2006
|
||||
.Dd July 14, 2006
|
||||
.Dt SYSCTL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -371,7 +371,10 @@ privilege can change the value.
|
||||
.It kern.veriexec.verbose integer yes
|
||||
.It kern.veriexec.strict integer raise only
|
||||
.It kern.veriexec.algorithms string no
|
||||
.It kern.veriexec.count.dev_\*[Lt]id\*[Gt] quad no
|
||||
.It kern.veriexec.count.table\*[Lt]N\*[Gt] quad no
|
||||
.It kern.veriexec.count.table\*[Lt]N\*[Gt].mntpt string no
|
||||
.It kern.veriexec.count.table\*[Lt]N\*[Gt].fstype string no
|
||||
.It kern.veriexec.count.table\*[Lt]N\*[Gt].nentries quad no
|
||||
.It kern.version string no
|
||||
.It kern.vnode struct no
|
||||
.It machdep.console_device dev_t no
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: veriexecctl.c,v 1.20 2005/12/13 10:56:16 dsl Exp $ */
|
||||
/* $NetBSD: veriexecctl.c,v 1.21 2006/07/14 18:41:40 elad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright 2005 Elad Efrat <elad@bsd.org.il>
|
||||
@ -73,27 +73,29 @@ openlock(const char *path)
|
||||
}
|
||||
|
||||
struct veriexec_up *
|
||||
dev_lookup(dev_t d)
|
||||
/* dev_lookup(dev_t d) */
|
||||
dev_lookup(char *vfs)
|
||||
{
|
||||
struct veriexec_up *p;
|
||||
|
||||
CIRCLEQ_FOREACH(p, ¶ms_list, vu_list)
|
||||
if (p->vu_param.dev == d)
|
||||
if (strcmp(p->vu_param.file, vfs) == 0)
|
||||
return (p);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct veriexec_up *
|
||||
dev_add(dev_t d)
|
||||
/* dev_add(dev_t d) */
|
||||
dev_add(dev_t d, char *vfs)
|
||||
{
|
||||
struct veriexec_up *up;
|
||||
|
||||
if ((up = calloc((size_t)1, sizeof(*up))) == NULL)
|
||||
err(1, "No memory");
|
||||
|
||||
up->vu_param.dev = d;
|
||||
up->vu_param.hash_size = 1;
|
||||
strlcpy(up->vu_param.file, vfs, sizeof(up->vu_param.file));
|
||||
|
||||
CIRCLEQ_INSERT_TAIL(¶ms_list, up, vu_list);
|
||||
|
||||
@ -115,13 +117,13 @@ phase1_preload(void)
|
||||
if (ioctl(gfd, VERIEXEC_TABLESIZE, &(vup->vu_param)) == -1) {
|
||||
if (errno != EEXIST)
|
||||
err(1, "Error in phase 1: Can't "
|
||||
"set hash table size for device %d",
|
||||
vup->vu_param.dev);
|
||||
"set hash table size for mount %s",
|
||||
vup->vu_param.file);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf(" => Hash table sizing successful for device "
|
||||
"%d. (%zu entries)\n", vup->vu_param.dev,
|
||||
printf(" => Hash table sizing successful for mount "
|
||||
"%s. (%zu entries)\n", vup->vu_param.file,
|
||||
vup->vu_param.hash_size);
|
||||
}
|
||||
|
||||
@ -302,19 +304,15 @@ main(int argc, char **argv)
|
||||
if (stat(argv[1], &sb) == -1)
|
||||
err(1, "Can't stat `%s'", argv[1]);
|
||||
|
||||
strlcpy(dp.file, argv[1], sizeof(dp.file));
|
||||
|
||||
/*
|
||||
* If it's a regular file, remove it. If it's a directory,
|
||||
* remove the entire table. If it's neither, abort.
|
||||
*/
|
||||
if (S_ISDIR(sb.st_mode))
|
||||
dp.ino = 0;
|
||||
else if (S_ISREG(sb.st_mode))
|
||||
dp.ino = sb.st_ino;
|
||||
else
|
||||
if (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode))
|
||||
errx(1, "`%s' is not a regular file or directory.", argv[1]);
|
||||
|
||||
dp.dev = sb.st_dev;
|
||||
|
||||
if (ioctl(gfd, VERIEXEC_DELETE, &dp) == -1)
|
||||
err(1, "Error deleting `%s'", argv[1]);
|
||||
} else if (argc == 2 && strcasecmp(argv[0], "query") == 0) {
|
||||
@ -331,6 +329,8 @@ main(int argc, char **argv)
|
||||
if (!S_ISREG(sb.st_mode))
|
||||
errx(1, "`%s' is not a regular file.", argv[1]);
|
||||
|
||||
strlcpy(qp.file, argv[1], sizeof(qp.file));
|
||||
|
||||
qp.ino = sb.st_ino;
|
||||
qp.dev = sb.st_dev;
|
||||
memset(fp, 0, sizeof(fp));
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: veriexecctl.h,v 1.5 2005/12/12 21:47:58 elad Exp $ */
|
||||
/* $NetBSD: veriexecctl.h,v 1.6 2006/07/14 18:41:40 elad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright 2005 Elad Efrat <elad@bsd.org.il>
|
||||
@ -56,8 +56,12 @@ int yywrap(void);
|
||||
int yylex(void);
|
||||
int yyparse(void);
|
||||
void yyerror(const char *);
|
||||
#if 0
|
||||
struct veriexec_up *dev_lookup(dev_t);
|
||||
struct veriexec_up *dev_add(dev_t);
|
||||
#endif
|
||||
struct veriexec_up *dev_lookup(char *);
|
||||
struct veriexec_up *dev_add(dev_t, char *);
|
||||
void phase2_load(void);
|
||||
|
||||
#endif /* _VERIEXECCTL_H_ */
|
||||
|
@ -1,5 +1,5 @@
|
||||
%{
|
||||
/* $NetBSD: veriexecctl_parse.y,v 1.13 2005/10/05 13:48:48 elad Exp $ */
|
||||
/* $NetBSD: veriexecctl_parse.y,v 1.14 2006/07/14 18:41:40 elad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright 2005 Elad Efrat <elad@bsd.org.il>
|
||||
@ -71,6 +71,7 @@ statement : /* empty */
|
||||
goto phase_2_end;
|
||||
}
|
||||
|
||||
#if 1
|
||||
if (stat(params.file, &sb) == -1) {
|
||||
warnx("Line %lu: Can't stat `%s'",
|
||||
(unsigned long)line, params.file);
|
||||
@ -83,8 +84,10 @@ statement : /* empty */
|
||||
(unsigned long)line, params.file);
|
||||
goto phase_2_end;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((p = dev_lookup(sb.st_dev)) != NULL) {
|
||||
/* if ((p = dev_lookup(sb.st_dev)) != NULL) { */
|
||||
if ((p = dev_lookup(params.file)) != NULL) {
|
||||
(p->vu_param.hash_size)++;
|
||||
goto phase_2_end;
|
||||
}
|
||||
@ -97,7 +100,7 @@ statement : /* empty */
|
||||
(void)printf( " => Adding device ID %d. (%s)\n",
|
||||
sb.st_dev, sf.f_mntonname);
|
||||
}
|
||||
dev_add(sb.st_dev);
|
||||
dev_add(sb.st_dev, params.file);
|
||||
phase_2_end:
|
||||
(void)memset(¶ms, 0, sizeof(params));
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: options.4,v 1.324 2006/07/11 16:22:23 jschauma Exp $
|
||||
.\" $NetBSD: options.4,v 1.325 2006/07/14 18:41:40 elad Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1996
|
||||
.\" Perry E. Metzger. All rights reserved.
|
||||
@ -30,7 +30,7 @@
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\"
|
||||
.Dd May 19, 2006
|
||||
.Dd July 14, 2006
|
||||
.Os
|
||||
.Dt OPTIONS 4
|
||||
.Sh NAME
|
||||
@ -1460,6 +1460,13 @@ A supplement to XSERVER that adds support for entering
|
||||
.Xr ddb 4
|
||||
while in
|
||||
.Tn X11 .
|
||||
.It Cd options FILEASSOC
|
||||
Support for
|
||||
.Xr fileassoc 9 .
|
||||
.It Cd options FILEASSOC_NHOOKS=integer
|
||||
Number of storage slots per file for
|
||||
.Xr fileassoc 9 .
|
||||
Default is 4.
|
||||
.El
|
||||
.Ss Networking Options
|
||||
.Bl -ohang
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: Makefile,v 1.204 2006/07/08 17:17:31 skrll Exp $
|
||||
# $NetBSD: Makefile,v 1.205 2006/07/14 18:41:41 elad Exp $
|
||||
|
||||
# Makefile for section 9 (kernel function and variable) manual pages.
|
||||
|
||||
@ -15,7 +15,7 @@ MAN= altq.9 arc4random.9 arp.9 audio.9 autoconf.9 \
|
||||
delay.9 disk.9 ddc.9 disklabel.9 dofileread.9 \
|
||||
dopowerhooks.9 do_setresuid.9 doshutdownhooks.9 driver.9 \
|
||||
edid.9 errno.9 ethersubr.9 evcnt.9 extattr.9 extent.9 \
|
||||
fetch.9 file.9 filedesc.9 firmload.9 fork1.9 fsetown.9 \
|
||||
fetch.9 file.9 fileassoc.9 filedesc.9 firmload.9 fork1.9 fsetown.9 \
|
||||
getiobuf.9 \
|
||||
hash.9 hashinit.9 hardclock.9 humanize_number.9 hz.9 \
|
||||
ieee80211.9 ieee80211_crypto.9 ieee80211_input.9 ieee80211_ioctl.9 \
|
||||
|
390
share/man/man9/fileassoc.9
Normal file
390
share/man/man9/fileassoc.9
Normal file
@ -0,0 +1,390 @@
|
||||
.\" $NetBSD: fileassoc.9,v 1.1 2006/07/14 18:41:41 elad 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 July 14, 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
|
||||
.Dq 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 a 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.
|
||||
.Pp
|
||||
.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
|
||||
.Dq 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 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 struct fileassoc_table * Fn fileassoc_table_lookup "struct mount *mp"
|
||||
Return the fileassoc table for
|
||||
.Ar mp
|
||||
or
|
||||
.Dq NULL
|
||||
if not found.
|
||||
.Pp
|
||||
.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 struct fileassoc_hash_entry * Fn fileassoc_file_lookup "struct vnode *vp"
|
||||
Return the fileassoc file entry for
|
||||
.Ar vp
|
||||
or
|
||||
.Dq NULL
|
||||
if not found.
|
||||
.Pp
|
||||
.It Ft void * Fn fileassoc_lookup "struct vnode *vp" "fileassoc_t id"
|
||||
Returns the private data for the file/id combination
|
||||
or
|
||||
.Dq NULL
|
||||
if not found.
|
||||
.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
|
||||
.Dq 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
|
||||
.Dq FILEASSOC_CLEANUP_FILE
|
||||
or
|
||||
.Dq 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 .
|
||||
.El
|
||||
.Ss File-specific Routines
|
||||
.Bl -tag -width "123456"
|
||||
.It Ft struct fileassoc_hash_entry * Fn fileassoc_file_add "struct vnode *vp"
|
||||
Add a
|
||||
.Nm
|
||||
entry for the file.
|
||||
All fileassoc-specific slots for the file are set to
|
||||
.Dq NULL .
|
||||
.Pp
|
||||
.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
|
||||
.Dq 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_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
|
||||
.Dq 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 an file.
|
||||
For example, let's assume we keep a custom ACL with each file:
|
||||
.Bd -literal -offset indent
|
||||
int
|
||||
myhook_acl_add(struct vattr *va, struct myhook_acl *acl)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = fileassoc_add(va->va_fsid, va->va_fileid, 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, normally, when there is no table for the mount.
|
||||
Creating a new table is simple:
|
||||
.Bd -literal -offset indent
|
||||
int error;
|
||||
|
||||
error = fileassoc_table_add(va->va_fsid, nentries);
|
||||
if (error)
|
||||
...handle error...
|
||||
.Ed
|
||||
.Pp
|
||||
The second argument,
|
||||
.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 vattr *va, int access_flags)
|
||||
{
|
||||
struct myhook_acl *acl;
|
||||
|
||||
acl = fileassoc_lookup(va->va_fsid, va->va_fileid, 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(va->va_fsid, va->va_fileid, 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 5.0 .
|
||||
.Sh AUTHOR
|
||||
.An Elad Efrat Aq elad@NetBSD.org
|
||||
designed and implemented the
|
||||
.Nm
|
||||
KPI.
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files,v 1.788 2006/07/13 22:56:02 gdamore Exp $
|
||||
# $NetBSD: files,v 1.789 2006/07/14 18:41:40 elad Exp $
|
||||
|
||||
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
|
||||
|
||||
@ -79,6 +79,9 @@ defflag opt_verified_exec.h VERIFIED_EXEC
|
||||
|
||||
defparam opt_pax.h PAX_MPROTECT
|
||||
|
||||
defflag opt_fileassoc.h FILEASSOC
|
||||
defparam opt_fileassoc.h FILEASSOC_NHOOKS
|
||||
|
||||
# compatibility options
|
||||
#
|
||||
defflag opt_compat_netbsd.h COMPAT_30
|
||||
@ -1133,8 +1136,8 @@ file dev/kttcp.c kttcp needs-flag
|
||||
|
||||
# Verified exec fingerprint loader pseudo-device
|
||||
defpseudo veriexec
|
||||
file kern/kern_verifiedexec.c veriexec needs-flag
|
||||
file dev/verified_exec.c veriexec needs-flag
|
||||
file kern/kern_verifiedexec.c veriexec & fileassoc needs-flag
|
||||
file dev/verified_exec.c veriexec & fileassoc needs-flag
|
||||
|
||||
# isochronous pseudo device for IEEE 1394, i.LINK or FireWire
|
||||
defpseudo fwiso: ieee1394
|
||||
@ -1241,6 +1244,7 @@ file kern/kern_lock.c
|
||||
file kern/kern_lwp.c
|
||||
file kern/kern_malloc.c
|
||||
file kern/kern_malloc_debug.c malloc_debug
|
||||
file kern/kern_fileassoc.c fileassoc needs-flag
|
||||
file kern/kern_ntptime.c
|
||||
file kern/kern_pax.c pax_mprotect
|
||||
file kern/kern_physio.c
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: verified_exec.c,v 1.34 2006/05/25 11:24:00 blymn Exp $ */
|
||||
/* $NetBSD: verified_exec.c,v 1.35 2006/07/14 18:41:40 elad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright 2005 Elad Efrat <elad@bsd.org.il>
|
||||
@ -31,9 +31,9 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(__NetBSD__)
|
||||
__KERNEL_RCSID(0, "$NetBSD: verified_exec.c,v 1.34 2006/05/25 11:24:00 blymn Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: verified_exec.c,v 1.35 2006/07/14 18:41:40 elad Exp $");
|
||||
#else
|
||||
__RCSID("$Id: verified_exec.c,v 1.34 2006/05/25 11:24:00 blymn Exp $\n$NetBSD: verified_exec.c,v 1.34 2006/05/25 11:24:00 blymn Exp $");
|
||||
__RCSID("$Id: verified_exec.c,v 1.35 2006/07/14 18:41:40 elad Exp $\n$NetBSD: verified_exec.c,v 1.35 2006/07/14 18:41:40 elad Exp $");
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
@ -64,8 +64,11 @@ __RCSID("$Id: verified_exec.c,v 1.34 2006/05/25 11:24:00 blymn Exp $\n$NetBSD: v
|
||||
#include <sys/verified_exec.h>
|
||||
#include <sys/kauth.h>
|
||||
|
||||
#include <sys/fileassoc.h>
|
||||
|
||||
/* count of number of times device is open (we really only allow one open) */
|
||||
static unsigned int veriexec_dev_usage;
|
||||
static unsigned int veriexec_tablecount = 0;
|
||||
|
||||
struct veriexec_softc {
|
||||
DEVPORT_DEVICE veriexec_dev;
|
||||
@ -171,7 +174,7 @@ veriexecioctl(dev_t dev __unused, u_long cmd, caddr_t data,
|
||||
switch (cmd) {
|
||||
case VERIEXEC_TABLESIZE:
|
||||
error = veriexec_newtable((struct veriexec_sizing_params *)
|
||||
data);
|
||||
data, l);
|
||||
break;
|
||||
|
||||
case VERIEXEC_LOAD:
|
||||
@ -179,11 +182,11 @@ veriexecioctl(dev_t dev __unused, u_long cmd, caddr_t data,
|
||||
break;
|
||||
|
||||
case VERIEXEC_DELETE:
|
||||
error = veriexec_delete((struct veriexec_delete_params *)data);
|
||||
error = veriexec_delete((struct veriexec_delete_params *)data, l);
|
||||
break;
|
||||
|
||||
case VERIEXEC_QUERY:
|
||||
error = veriexec_query((struct veriexec_query_params *)data);
|
||||
error = veriexec_query((struct veriexec_query_params *)data, l);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -207,44 +210,57 @@ veriexec_drvinit(void *unused __unused)
|
||||
SYSINIT(veriexec, SI_SUB_PSEUDO, SI_ORDER_ANY, veriexec_drvinit, NULL);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Create a new Veriexec table.
|
||||
*/
|
||||
int
|
||||
veriexec_newtable(struct veriexec_sizing_params *params)
|
||||
veriexec_newtable(struct veriexec_sizing_params *params, struct lwp *l)
|
||||
{
|
||||
struct veriexec_hashtbl *tbl;
|
||||
u_char node_name[16];
|
||||
u_long hashmask;
|
||||
struct veriexec_table_entry *vte;
|
||||
struct nameidata nid;
|
||||
u_char buf[16];
|
||||
int error;
|
||||
|
||||
/* Check for existing table for device. */
|
||||
if (veriexec_tblfind(params->dev) != NULL)
|
||||
return (EEXIST);
|
||||
NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, params->file, l);
|
||||
error = namei(&nid);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Allocate and initialize a Veriexec hash table. */
|
||||
tbl = malloc(sizeof(*tbl), M_TEMP, M_WAITOK);
|
||||
tbl->hash_size = params->hash_size;
|
||||
tbl->hash_dev = params->dev;
|
||||
tbl->hash_tbl = hashinit(params->hash_size, HASH_LIST, M_TEMP,
|
||||
M_WAITOK, &hashmask);
|
||||
tbl->hash_count = 0;
|
||||
error = fileassoc_table_add(nid.ni_vp->v_mount, params->hash_size);
|
||||
if (error && (error != EEXIST))
|
||||
goto out;
|
||||
|
||||
LIST_INSERT_HEAD(&veriexec_tables, tbl, hash_list);
|
||||
vte = malloc(sizeof(*vte), M_TEMP, M_WAITOK | M_ZERO);
|
||||
error = fileassoc_tabledata_add(nid.ni_vp->v_mount, veriexec_hook, vte);
|
||||
#ifdef DIAGNOSTIC
|
||||
if (error)
|
||||
panic("Fileassoc: Inconsistency after adding table");
|
||||
#endif /* DIAGNOSTIC */
|
||||
|
||||
snprintf(node_name, sizeof(node_name), "dev_%u",
|
||||
tbl->hash_dev);
|
||||
snprintf(buf, sizeof(buf), "table%ud", veriexec_tablecount++);
|
||||
sysctl_createv(NULL, 0, &veriexec_count_node, &vte->vte_node,
|
||||
0, CTLTYPE_NODE, "table0", NULL, NULL, 0, NULL,
|
||||
0, CTL_CREATE, CTL_EOL);
|
||||
|
||||
sysctl_createv(NULL, 0, &veriexec_count_node, NULL,
|
||||
CTLFLAG_READONLY, CTLTYPE_QUAD, node_name,
|
||||
NULL, NULL, 0, &tbl->hash_count, 0,
|
||||
tbl->hash_dev, CTL_EOL);
|
||||
sysctl_createv(NULL, 0, &vte->vte_node, NULL,
|
||||
CTLFLAG_READONLY, CTLTYPE_STRING, "mntpt",
|
||||
NULL, NULL, 0, nid.ni_vp->v_mount->mnt_stat.f_mntonname, 0, CTL_CREATE, CTL_EOL);
|
||||
sysctl_createv(NULL, 0, &vte->vte_node, NULL,
|
||||
CTLFLAG_READONLY, CTLTYPE_STRING, "fstype",
|
||||
NULL, NULL, 0, nid.ni_vp->v_mount->mnt_stat.f_fstypename, 0, CTL_CREATE, CTL_EOL);
|
||||
sysctl_createv(NULL, 0, &vte->vte_node, NULL,
|
||||
CTLFLAG_READONLY, CTLTYPE_QUAD, "nentries",
|
||||
NULL, NULL, 0, &vte->vte_count, 0, CTL_CREATE, CTL_EOL);
|
||||
|
||||
return (0);
|
||||
out:
|
||||
vrele(nid.ni_vp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
veriexec_load(struct veriexec_params *params, struct lwp *l)
|
||||
{
|
||||
struct veriexec_hashtbl *tbl;
|
||||
struct veriexec_hash_entry *hh;
|
||||
struct veriexec_hash_entry *e;
|
||||
struct veriexec_file_entry *hh, *e;
|
||||
struct nameidata nid;
|
||||
struct vattr va;
|
||||
int error;
|
||||
@ -262,7 +278,7 @@ veriexec_load(struct veriexec_params *params, struct lwp *l)
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Get attributes for device and inode. */
|
||||
/* Get attributes for device and fileid. */
|
||||
error = VOP_GETATTR(nid.ni_vp, &va, l->l_proc->p_cred, l);
|
||||
if (error) {
|
||||
vrele(nid.ni_vp);
|
||||
@ -272,13 +288,7 @@ veriexec_load(struct veriexec_params *params, struct lwp *l)
|
||||
/* Release our reference to the vnode. (namei) */
|
||||
vrele(nid.ni_vp);
|
||||
|
||||
/* Get table for the device. */
|
||||
tbl = veriexec_tblfind(va.va_fsid);
|
||||
if (tbl == NULL) {
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
hh = veriexec_lookup(va.va_fsid, va.va_fileid);
|
||||
hh = veriexec_lookup(nid.ni_vp);
|
||||
if (hh != NULL) {
|
||||
/*
|
||||
* Duplicate entry means something is wrong in
|
||||
@ -302,7 +312,6 @@ veriexec_load(struct veriexec_params *params, struct lwp *l)
|
||||
}
|
||||
|
||||
e = malloc(sizeof(*e), M_TEMP, M_WAITOK);
|
||||
e->inode = va.va_fileid;
|
||||
e->type = params->type;
|
||||
e->status = FINGERPRINT_NOTEVAL;
|
||||
e->page_fp = NULL;
|
||||
@ -313,7 +322,7 @@ veriexec_load(struct veriexec_params *params, struct lwp *l)
|
||||
free(e, M_TEMP);
|
||||
printf("Veriexec: veriexecioctl: Invalid or unknown "
|
||||
"fingerprint type \"%s\" for file \"%s\" "
|
||||
"(dev=%ld, inode=%llu)\n", params->fp_type,
|
||||
"(dev=%ld, fileid=%llu)\n", params->fp_type,
|
||||
params->file, va.va_fsid,
|
||||
(unsigned long long)va.va_fileid);
|
||||
return(EINVAL);
|
||||
@ -330,7 +339,7 @@ veriexec_load(struct veriexec_params *params, struct lwp *l)
|
||||
if (e->ops->hash_len != params->size) {
|
||||
printf("Veriexec: veriexecioctl: Inconsistent "
|
||||
"fingerprint size for type \"%s\" for file "
|
||||
"\"%s\" (dev=%ld, inode=%llu), size was %u "
|
||||
"\"%s\" (dev=%ld, fileid=%llu), size was %u "
|
||||
"was expecting %zu\n", params->fp_type,
|
||||
params->file, va.va_fsid,
|
||||
(unsigned long long)va.va_fileid,
|
||||
@ -347,90 +356,109 @@ veriexec_load(struct veriexec_params *params, struct lwp *l)
|
||||
REPORT_VERBOSE_HIGH, REPORT_NOALARM,
|
||||
REPORT_NOPANIC);
|
||||
|
||||
error = veriexec_hashadd(tbl, e);
|
||||
|
||||
error = veriexec_hashadd(nid.ni_vp, e);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
veriexec_clear(void *data, int file_specific)
|
||||
{
|
||||
if (file_specific) {
|
||||
struct veriexec_file_entry *vfe = data;
|
||||
|
||||
if (vfe->fp != NULL)
|
||||
free(vfe->fp, M_TEMP);
|
||||
if (vfe->page_fp != NULL)
|
||||
free(vfe->page_fp, M_TEMP);
|
||||
free(vfe, M_TEMP);
|
||||
} else {
|
||||
struct veriexec_table_entry *vte = data;
|
||||
|
||||
free(vte, M_TEMP);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
veriexec_delete(struct veriexec_delete_params *params, struct lwp *l)
|
||||
{
|
||||
struct veriexec_table_entry *vte;
|
||||
struct nameidata nid;
|
||||
int error;
|
||||
|
||||
NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, params->file, l);
|
||||
error = namei(&nid);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
vte = veriexec_tblfind(nid.ni_vp);
|
||||
if (vte == NULL) {
|
||||
error = ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* XXX this should either receive the filename to remove OR a mount point! */
|
||||
/* Delete an entire table */
|
||||
if (nid.ni_vp->v_type == VDIR) {
|
||||
sysctl_free(__UNCONST(vte->vte_node));
|
||||
|
||||
veriexec_tablecount--;
|
||||
|
||||
error = fileassoc_table_clear(nid.ni_vp->v_mount, veriexec_hook);
|
||||
if (error)
|
||||
goto out;
|
||||
} else if (nid.ni_vp->v_type == VREG) {
|
||||
error = fileassoc_clear(nid.ni_vp, veriexec_hook);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
vte->vte_count--;
|
||||
}
|
||||
|
||||
out:
|
||||
vrele(nid.ni_vp);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
veriexec_delete(struct veriexec_delete_params *params)
|
||||
veriexec_query(struct veriexec_query_params *params, struct lwp *l)
|
||||
{
|
||||
struct veriexec_hashtbl *tbl;
|
||||
struct veriexec_hash_entry *vhe;
|
||||
|
||||
/* Delete an entire table */
|
||||
if (params->ino == 0) {
|
||||
struct veriexec_hashhead *tbl_list;
|
||||
u_long i;
|
||||
|
||||
tbl = veriexec_tblfind(params->dev);
|
||||
if (tbl == NULL)
|
||||
return (ENOENT);
|
||||
|
||||
/* Remove all entries from the table and lists */
|
||||
tbl_list = tbl->hash_tbl;
|
||||
for (i = 0; i < tbl->hash_size; i++) {
|
||||
while (LIST_FIRST(&tbl_list[i]) != NULL) {
|
||||
vhe = LIST_FIRST(&tbl_list[i]);
|
||||
if (vhe->fp != NULL)
|
||||
free(vhe->fp, M_TEMP);
|
||||
if (vhe->page_fp != NULL)
|
||||
free(vhe->page_fp, M_TEMP);
|
||||
LIST_REMOVE(vhe, entries);
|
||||
free(vhe, M_TEMP);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove hash table and sysctl node */
|
||||
hashdone(tbl->hash_tbl, M_TEMP);
|
||||
LIST_REMOVE(tbl, hash_list);
|
||||
sysctl_destroyv(__UNCONST(veriexec_count_node), params->dev,
|
||||
CTL_EOL);
|
||||
} else {
|
||||
tbl = veriexec_tblfind(params->dev);
|
||||
if (tbl == NULL)
|
||||
return (ENOENT);
|
||||
|
||||
vhe = veriexec_lookup(params->dev, params->ino);
|
||||
if (vhe != NULL) {
|
||||
if (vhe->fp != NULL)
|
||||
free(vhe->fp, M_TEMP);
|
||||
if (vhe->page_fp != NULL)
|
||||
free(vhe->page_fp, M_TEMP);
|
||||
LIST_REMOVE(vhe, entries);
|
||||
free(vhe, M_TEMP);
|
||||
|
||||
tbl->hash_count--;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
veriexec_query(struct veriexec_query_params *params)
|
||||
{
|
||||
struct veriexec_hash_entry *vhe;
|
||||
struct veriexec_file_entry *vfe;
|
||||
struct nameidata nid;
|
||||
int error;
|
||||
|
||||
vhe = veriexec_lookup(params->dev, params->ino);
|
||||
if (vhe == NULL)
|
||||
return (ENOENT);
|
||||
|
||||
params->type = vhe->type;
|
||||
params->status = vhe->status;
|
||||
params->hash_len = vhe->ops->hash_len;
|
||||
strlcpy(params->fp_type, vhe->ops->type, sizeof(params->fp_type));
|
||||
memcpy(params->fp_type, vhe->ops->type, sizeof(params->fp_type));
|
||||
error = copyout(params, params->uaddr, sizeof(*params));
|
||||
NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, params->file, l);
|
||||
error = namei(&nid);
|
||||
if (error)
|
||||
return (error);
|
||||
if (params->fp_bufsize >= vhe->ops->hash_len) {
|
||||
error = copyout(vhe->fp, params->fp, vhe->ops->hash_len);
|
||||
|
||||
vfe = veriexec_lookup(nid.ni_vp);
|
||||
if (vfe == NULL) {
|
||||
error = ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
params->type = vfe->type;
|
||||
params->status = vfe->status;
|
||||
params->hash_len = vfe->ops->hash_len;
|
||||
strlcpy(params->fp_type, vfe->ops->type, sizeof(params->fp_type));
|
||||
memcpy(params->fp_type, vfe->ops->type, sizeof(params->fp_type));
|
||||
error = copyout(params, params->uaddr, sizeof(*params));
|
||||
if (error)
|
||||
goto out;
|
||||
if (params->fp_bufsize >= vfe->ops->hash_len) {
|
||||
error = copyout(vfe->fp, params->fp, vfe->ops->hash_len);
|
||||
if (error)
|
||||
return (error);
|
||||
goto out;
|
||||
} else
|
||||
error = ENOMEM;
|
||||
|
||||
out:
|
||||
vrele(nid.ni_vp);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: init_main.c,v 1.270 2006/07/01 05:41:10 kardel Exp $ */
|
||||
/* $NetBSD: init_main.c,v 1.271 2006/07/14 18:41:40 elad Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 1989, 1991, 1992, 1993
|
||||
@ -71,7 +71,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.270 2006/07/01 05:41:10 kardel Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.271 2006/07/14 18:41:40 elad Exp $");
|
||||
|
||||
#include "opt_ipsec.h"
|
||||
#include "opt_kcont.h"
|
||||
@ -82,6 +82,7 @@ __KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.270 2006/07/01 05:41:10 kardel Exp $
|
||||
#include "opt_syscall_debug.h"
|
||||
#include "opt_sysv.h"
|
||||
#include "opt_verified_exec.h"
|
||||
#include "opt_fileassoc.h"
|
||||
|
||||
#include "rnd.h"
|
||||
|
||||
@ -150,6 +151,10 @@ __KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.270 2006/07/01 05:41:10 kardel Exp $
|
||||
#include <sys/sa.h>
|
||||
#include <sys/syscallargs.h>
|
||||
|
||||
#ifdef FILEASSOC
|
||||
#include <sys/fileassoc.h>
|
||||
#endif /* FILEASSOC */
|
||||
|
||||
#include <ufs/ufs/quota.h>
|
||||
|
||||
#include <miscfs/genfs/genfs.h>
|
||||
@ -330,6 +335,10 @@ main(void)
|
||||
/* Initialize kauth. */
|
||||
kauth_init();
|
||||
|
||||
#ifdef FILEASSOC
|
||||
fileassoc_init();
|
||||
#endif /* FILEASSOC */
|
||||
|
||||
#ifdef VERIFIED_EXEC
|
||||
/*
|
||||
* Initialise the fingerprint operations vectors before
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: kern_exec.c,v 1.218 2006/05/14 21:15:11 elad Exp $ */
|
||||
/* $NetBSD: kern_exec.c,v 1.219 2006/07/14 18:41:40 elad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 1993, 1994, 1996 Christopher G. Demetriou
|
||||
@ -33,7 +33,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.218 2006/05/14 21:15:11 elad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.219 2006/07/14 18:41:40 elad Exp $");
|
||||
|
||||
#include "opt_ktrace.h"
|
||||
#include "opt_syscall_debug.h"
|
||||
@ -286,8 +286,8 @@ check_exec(struct lwp *l, struct exec_package *epp, int flag)
|
||||
|
||||
|
||||
#ifdef VERIFIED_EXEC
|
||||
if ((error = veriexec_verify(l, vp, epp->ep_vap, epp->ep_ndp->ni_dirp,
|
||||
flag, NULL)) != 0)
|
||||
if ((error = veriexec_verify(l, vp, epp->ep_ndp->ni_dirp, flag,
|
||||
NULL)) != 0)
|
||||
goto bad2;
|
||||
#endif
|
||||
|
||||
|
435
sys/kern/kern_fileassoc.c
Normal file
435
sys/kern/kern_fileassoc.c
Normal file
@ -0,0 +1,435 @@
|
||||
/* $NetBSD: kern_fileassoc.c,v 1.1 2006/07/14 18:41:40 elad 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.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/inttypes.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/fileassoc.h>
|
||||
|
||||
struct fileassoc_hook fileassoc_hooks[FILEASSOC_NHOOKS];
|
||||
int fileassoc_nhooks;
|
||||
|
||||
|
||||
/* Global list of hash tables, one per device. */
|
||||
LIST_HEAD(, fileassoc_table) fileassoc_tables;
|
||||
|
||||
/*
|
||||
* Hashing function: Takes a number modulus the mask to give back
|
||||
* an index into the hash table.
|
||||
*/
|
||||
#define FILEASSOC_HASH(tbl, fileid) \
|
||||
(hash32_buf(&(fileid), sizeof((fileid)), HASH32_BUF_INIT) \
|
||||
& ((tbl)->hash_mask))
|
||||
|
||||
/*
|
||||
* Initialize the fileassoc subsystem.
|
||||
*/
|
||||
void
|
||||
fileassoc_init(void)
|
||||
{
|
||||
memset(fileassoc_hooks, 0, sizeof(fileassoc_hooks));
|
||||
fileassoc_nhooks = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a new hook.
|
||||
*/
|
||||
fileassoc_t
|
||||
fileassoc_register(const char *name, fileassoc_cleanup_cb_t cleanup_cb)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (fileassoc_nhooks >= FILEASSOC_NHOOKS)
|
||||
return (-1);
|
||||
|
||||
for (i = 0; i < FILEASSOC_NHOOKS; i++)
|
||||
if (fileassoc_hooks[i].hook_name == NULL)
|
||||
break;
|
||||
|
||||
fileassoc_hooks[i].hook_name = name;
|
||||
fileassoc_hooks[i].hook_cleanup_cb = cleanup_cb;
|
||||
|
||||
fileassoc_nhooks++;
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Deregister a hook.
|
||||
*/
|
||||
int
|
||||
fileassoc_deregister(fileassoc_t id)
|
||||
{
|
||||
if (id < 0 || id >= FILEASSOC_NHOOKS)
|
||||
return (EINVAL);
|
||||
|
||||
fileassoc_hooks[id].hook_name = NULL;
|
||||
fileassoc_hooks[id].hook_cleanup_cb = NULL;
|
||||
|
||||
fileassoc_nhooks--;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the hash table for the specified device.
|
||||
*/
|
||||
struct fileassoc_table *
|
||||
fileassoc_table_lookup(struct mount *mp)
|
||||
{
|
||||
struct fileassoc_table *tbl;
|
||||
|
||||
LIST_FOREACH(tbl, &fileassoc_tables, hash_list) {
|
||||
if (tbl->tbl_mntpt == mp)
|
||||
return (tbl);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a lookup on a hash table.
|
||||
*/
|
||||
struct fileassoc_hash_entry *
|
||||
fileassoc_file_lookup(struct vnode *vp)
|
||||
{
|
||||
struct fileassoc_table *tbl;
|
||||
struct fileassoc_hashhead *tble;
|
||||
struct fileassoc_hash_entry *e;
|
||||
struct vattr va;
|
||||
size_t indx;
|
||||
int error;
|
||||
|
||||
error = VOP_GETATTR(vp, &va, curlwp->l_proc->p_cred, curlwp);
|
||||
if (error)
|
||||
return (NULL);
|
||||
|
||||
tbl = fileassoc_table_lookup(vp->v_mount);
|
||||
if (tbl == NULL)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* XXX: We should NOT rely on fileid here!
|
||||
*/
|
||||
indx = FILEASSOC_HASH(tbl, va.va_fileid);
|
||||
tble = &(tbl->hash_tbl[indx & ((tbl)->hash_mask)]);
|
||||
|
||||
LIST_FOREACH(e, tble, entries) {
|
||||
if ((e != NULL) && (e->fileid == va.va_fileid))
|
||||
return (e);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return hook data associated with a vnode.
|
||||
*/
|
||||
void *
|
||||
fileassoc_lookup(struct vnode *vp, fileassoc_t id)
|
||||
{
|
||||
struct fileassoc_hash_entry *mhe;
|
||||
|
||||
mhe = fileassoc_file_lookup(vp);
|
||||
if (mhe == NULL)
|
||||
return (NULL);
|
||||
|
||||
return (mhe->hooks[id]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new fileassoc table.
|
||||
*/
|
||||
int
|
||||
fileassoc_table_add(struct mount *mp, size_t size)
|
||||
{
|
||||
struct fileassoc_table *tbl;
|
||||
|
||||
/* Check for existing table for device. */
|
||||
if (fileassoc_table_lookup(mp) != NULL)
|
||||
return (EEXIST);
|
||||
|
||||
/* Allocate and initialize a Veriexec hash table. */
|
||||
tbl = malloc(sizeof(*tbl), M_TEMP, M_WAITOK | M_ZERO);
|
||||
tbl->hash_size = size;
|
||||
tbl->tbl_mntpt = mp;
|
||||
tbl->hash_tbl = hashinit(size, HASH_LIST, M_TEMP,
|
||||
M_WAITOK | M_ZERO, &tbl->hash_mask);
|
||||
|
||||
LIST_INSERT_HEAD(&fileassoc_tables, tbl, hash_list);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a table.
|
||||
*/
|
||||
int
|
||||
fileassoc_table_delete(struct mount *mp)
|
||||
{
|
||||
struct fileassoc_table *tbl;
|
||||
struct fileassoc_hashhead *hh;
|
||||
u_long i;
|
||||
int j;
|
||||
|
||||
tbl = fileassoc_table_lookup(mp);
|
||||
if (tbl == NULL)
|
||||
return (EEXIST);
|
||||
|
||||
/* Remove all entries from the table and lists */
|
||||
hh = tbl->hash_tbl;
|
||||
for (i = 0; i < tbl->hash_size; i++) {
|
||||
struct fileassoc_hash_entry *mhe;
|
||||
|
||||
while (LIST_FIRST(&hh[i]) != NULL) {
|
||||
mhe = LIST_FIRST(&hh[i]);
|
||||
LIST_REMOVE(mhe, entries);
|
||||
|
||||
for (j = 0; j < fileassoc_nhooks; j++)
|
||||
if (fileassoc_hooks[j].hook_cleanup_cb != NULL)
|
||||
(fileassoc_hooks[j].hook_cleanup_cb)(mhe->hooks[j], 1);
|
||||
|
||||
free(mhe, M_TEMP);
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < fileassoc_nhooks; j++)
|
||||
if (fileassoc_hooks[j].hook_cleanup_cb != NULL)
|
||||
(fileassoc_hooks[j].hook_cleanup_cb)(tbl->tables[j], 0);
|
||||
|
||||
/* Remove hash table and sysctl node */
|
||||
hashdone(tbl->hash_tbl, M_TEMP);
|
||||
LIST_REMOVE(tbl, hash_list);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear a table for a given hook.
|
||||
*/
|
||||
int
|
||||
fileassoc_table_clear(struct mount *mp, fileassoc_t id)
|
||||
{
|
||||
struct fileassoc_table *tbl;
|
||||
struct fileassoc_hashhead *hh;
|
||||
fileassoc_cleanup_cb_t cleanup_cb;
|
||||
u_long i;
|
||||
|
||||
tbl = fileassoc_table_lookup(mp);
|
||||
if (tbl == NULL)
|
||||
return (EEXIST);
|
||||
|
||||
cleanup_cb = fileassoc_hooks[id].hook_cleanup_cb;
|
||||
|
||||
hh = tbl->hash_tbl;
|
||||
for (i = 0; i < tbl->hash_size; i++) {
|
||||
struct fileassoc_hash_entry *mhe;
|
||||
|
||||
LIST_FOREACH(mhe, &hh[i], entries) {
|
||||
if ((mhe->hooks[id] != NULL) && cleanup_cb != NULL)
|
||||
cleanup_cb(mhe->hooks[id], FILEASSOC_CLEANUP_FILE);
|
||||
|
||||
mhe->hooks[id] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tbl->tables[id] != NULL) && cleanup_cb != NULL)
|
||||
cleanup_cb(tbl->tables[id], FILEASSOC_CLEANUP_TABLE);
|
||||
|
||||
tbl->tables[id] = NULL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add hook-specific data on a fileassoc table.
|
||||
*/
|
||||
int
|
||||
fileassoc_tabledata_add(struct mount *mp, fileassoc_t id, void *data)
|
||||
{
|
||||
struct fileassoc_table *tbl;
|
||||
|
||||
tbl = fileassoc_table_lookup(mp);
|
||||
if (tbl == NULL)
|
||||
return (EFAULT);
|
||||
|
||||
tbl->tables[id] = data;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear hook-specific data on a fileassoc table.
|
||||
*/
|
||||
int
|
||||
fileassoc_tabledata_clear(struct mount *mp, fileassoc_t id)
|
||||
{
|
||||
struct fileassoc_table *tbl;
|
||||
|
||||
tbl = fileassoc_table_lookup(mp);
|
||||
if (tbl == NULL)
|
||||
return (EFAULT);
|
||||
|
||||
tbl->tables[id] = NULL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve hook-specific data from a fileassoc table.
|
||||
*/
|
||||
void *
|
||||
fileassoc_tabledata_lookup(struct mount *mp, fileassoc_t id)
|
||||
{
|
||||
struct fileassoc_table *tbl;
|
||||
|
||||
tbl = fileassoc_table_lookup(mp);
|
||||
if (tbl == NULL)
|
||||
return (NULL);
|
||||
|
||||
return (tbl->tables[id]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a file entry to a table.
|
||||
*/
|
||||
struct fileassoc_hash_entry *
|
||||
fileassoc_file_add(struct vnode *vp)
|
||||
{
|
||||
struct fileassoc_table *tbl;
|
||||
struct fileassoc_hashhead *vhh;
|
||||
struct fileassoc_hash_entry *e;
|
||||
struct vattr va;
|
||||
size_t indx;
|
||||
int error;
|
||||
|
||||
error = VOP_GETATTR(vp, &va, curlwp->l_proc->p_cred, curlwp);
|
||||
if (error)
|
||||
return (NULL);
|
||||
|
||||
e = fileassoc_file_lookup(vp);
|
||||
if (e != NULL)
|
||||
return (e);
|
||||
|
||||
tbl = fileassoc_table_lookup(vp->v_mount);
|
||||
if (tbl == NULL)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* XXX: We should NOT rely on fileid here!
|
||||
*/
|
||||
indx = FILEASSOC_HASH(tbl, va.va_fileid);
|
||||
vhh = &(tbl->hash_tbl[indx & ((tbl)->hash_mask)]);
|
||||
|
||||
e = malloc(sizeof(*e), M_TEMP, M_WAITOK | M_ZERO);
|
||||
e->fileid = va.va_fileid;
|
||||
LIST_INSERT_HEAD(vhh, e, entries);
|
||||
|
||||
return (e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a file entry from a table.
|
||||
*/
|
||||
int
|
||||
fileassoc_file_delete(struct vnode *vp)
|
||||
{
|
||||
struct fileassoc_hash_entry *mhe;
|
||||
int i;
|
||||
|
||||
mhe = fileassoc_file_lookup(vp);
|
||||
if (mhe == NULL)
|
||||
return (ENOENT);
|
||||
|
||||
LIST_REMOVE(mhe, entries);
|
||||
|
||||
for (i = 0; i < fileassoc_nhooks; i++)
|
||||
if (fileassoc_hooks[i].hook_cleanup_cb != NULL)
|
||||
(fileassoc_hooks[i].hook_cleanup_cb)(mhe->hooks[i],
|
||||
FILEASSOC_CLEANUP_FILE);
|
||||
|
||||
free(mhe, M_TEMP);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a hook to a vnode.
|
||||
*/
|
||||
int
|
||||
fileassoc_add(struct vnode *vp, fileassoc_t id, void *data)
|
||||
{
|
||||
struct fileassoc_hash_entry *e;
|
||||
|
||||
e = fileassoc_file_lookup(vp);
|
||||
if (e == NULL) {
|
||||
e = fileassoc_file_add(vp);
|
||||
if (e == NULL)
|
||||
return (ENOTDIR);
|
||||
}
|
||||
|
||||
if (e->hooks[id] != NULL)
|
||||
return (EEXIST);
|
||||
|
||||
e->hooks[id] = data;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear a hook from a vnode.
|
||||
*/
|
||||
int
|
||||
fileassoc_clear(struct vnode *vp, fileassoc_t id)
|
||||
{
|
||||
struct fileassoc_hash_entry *mhe;
|
||||
fileassoc_cleanup_cb_t cleanup_cb;
|
||||
|
||||
mhe = fileassoc_file_lookup(vp);
|
||||
if (mhe == NULL)
|
||||
return (ENOENT);
|
||||
|
||||
cleanup_cb = fileassoc_hooks[id].hook_cleanup_cb;
|
||||
if ((mhe->hooks[id] != NULL) && cleanup_cb != NULL)
|
||||
cleanup_cb(mhe->hooks[id], FILEASSOC_CLEANUP_FILE);
|
||||
|
||||
mhe->hooks[id] = NULL;
|
||||
|
||||
return (0);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: kern_verifiedexec.c,v 1.52 2006/07/09 10:13:53 blymn Exp $ */
|
||||
/* $NetBSD: kern_verifiedexec.c,v 1.53 2006/07/14 18:41:40 elad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright 2005 Elad Efrat <elad@bsd.org.il>
|
||||
@ -30,7 +30,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.52 2006/07/09 10:13:53 blymn Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.53 2006/07/14 18:41:40 elad Exp $");
|
||||
|
||||
#include "opt_verified_exec.h"
|
||||
|
||||
@ -57,6 +57,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.52 2006/07/09 10:13:53 blymn
|
||||
#include <crypto/ripemd160/rmd160.h>
|
||||
#include <sys/md5.h>
|
||||
#include <uvm/uvm_extern.h>
|
||||
#include <sys/fileassoc.h>
|
||||
#include <sys/kauth.h>
|
||||
|
||||
int veriexec_verbose;
|
||||
@ -67,6 +68,8 @@ size_t veriexec_name_max;
|
||||
|
||||
const struct sysctlnode *veriexec_count_node;
|
||||
|
||||
int veriexec_hook;
|
||||
|
||||
/* Veriexecs table of hash types and their associated information. */
|
||||
LIST_HEAD(veriexec_ops_head, veriexec_fp_ops) veriexec_ops_list;
|
||||
|
||||
@ -134,6 +137,13 @@ veriexec_init_fp_ops(void)
|
||||
{
|
||||
struct veriexec_fp_ops *ops;
|
||||
|
||||
/* Register a fileassoc for Veriexec. */
|
||||
veriexec_hook = fileassoc_register("veriexec", veriexec_clear);
|
||||
#ifdef DIAGNOSTIC
|
||||
if (veriexec_hook == FILEASSOC_INVAL)
|
||||
panic("Veriexec: Can't register meta-hook");
|
||||
#endif /* DIAGNOSTIC */
|
||||
|
||||
LIST_INIT(&veriexec_ops_list);
|
||||
veriexec_fp_names = NULL;
|
||||
veriexec_name_max = 0;
|
||||
@ -210,7 +220,7 @@ veriexec_find_ops(u_char *name)
|
||||
*/
|
||||
int
|
||||
veriexec_fp_calc(struct lwp *l, struct vnode *vp,
|
||||
struct veriexec_hash_entry *vhe, uint64_t size, u_char *fp)
|
||||
struct veriexec_file_entry *vfe, uint64_t size, u_char *fp)
|
||||
{
|
||||
void *ctx, *page_ctx;
|
||||
u_char *buf, *page_fp;
|
||||
@ -218,19 +228,18 @@ veriexec_fp_calc(struct lwp *l, struct vnode *vp,
|
||||
size_t resid, npages;
|
||||
int error, do_perpage, pagen;
|
||||
|
||||
if (vhe->ops == NULL) {
|
||||
panic("veriexec: Operations vector is NULL");
|
||||
}
|
||||
if (vfe->ops == NULL)
|
||||
panic("Veriexec: Operations vector is NULL");
|
||||
|
||||
#if 0 /* XXX - for now */
|
||||
if ((vhe->type & VERIEXEC_UNTRUSTED) &&
|
||||
(vhe->page_fp_status == PAGE_FP_NONE))
|
||||
if ((vfe->type & VERIEXEC_UNTRUSTED) &&
|
||||
(vfe->page_fp_status == PAGE_FP_NONE))
|
||||
do_perpage = 1;
|
||||
else
|
||||
#endif
|
||||
do_perpage = 0;
|
||||
|
||||
ctx = (void *) malloc(vhe->ops->context_size, M_TEMP, M_WAITOK);
|
||||
ctx = (void *) malloc(vfe->ops->context_size, M_TEMP, M_WAITOK);
|
||||
buf = (u_char *) malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
|
||||
|
||||
page_ctx = NULL;
|
||||
@ -238,14 +247,14 @@ veriexec_fp_calc(struct lwp *l, struct vnode *vp,
|
||||
npages = 0;
|
||||
if (do_perpage) {
|
||||
npages = (size >> PAGE_SHIFT) + 1;
|
||||
page_fp = (u_char *) malloc(vhe->ops->hash_len * npages,
|
||||
page_fp = (u_char *) malloc(vfe->ops->hash_len * npages,
|
||||
M_TEMP, M_WAITOK|M_ZERO);
|
||||
vhe->page_fp = page_fp;
|
||||
page_ctx = (void *) malloc(vhe->ops->context_size, M_TEMP,
|
||||
vfe->page_fp = page_fp;
|
||||
page_ctx = (void *) malloc(vfe->ops->context_size, M_TEMP,
|
||||
M_WAITOK);
|
||||
}
|
||||
|
||||
(vhe->ops->init)(ctx);
|
||||
(vfe->ops->init)(ctx);
|
||||
|
||||
len = 0;
|
||||
error = 0;
|
||||
@ -265,30 +274,30 @@ veriexec_fp_calc(struct lwp *l, struct vnode *vp,
|
||||
|
||||
if (error) {
|
||||
if (do_perpage) {
|
||||
free(vhe->page_fp, M_TEMP);
|
||||
vhe->page_fp = NULL;
|
||||
free(vfe->page_fp, M_TEMP);
|
||||
vfe->page_fp = NULL;
|
||||
}
|
||||
|
||||
goto bad;
|
||||
}
|
||||
|
||||
(vhe->ops->update)(ctx, buf, (unsigned int) len);
|
||||
(vfe->ops->update)(ctx, buf, (unsigned int) len);
|
||||
|
||||
if (do_perpage) {
|
||||
(vhe->ops->init)(page_ctx);
|
||||
(vhe->ops->update)(page_ctx, buf, (unsigned int)len);
|
||||
(vhe->ops->final)(page_fp, page_ctx);
|
||||
(vfe->ops->init)(page_ctx);
|
||||
(vfe->ops->update)(page_ctx, buf, (unsigned int)len);
|
||||
(vfe->ops->final)(page_fp, page_ctx);
|
||||
|
||||
if (veriexec_verbose >= 2) {
|
||||
int i;
|
||||
|
||||
printf("hash for page %d: ", pagen);
|
||||
for (i = 0; i < vhe->ops->hash_len; i++)
|
||||
for (i = 0; i < vfe->ops->hash_len; i++)
|
||||
printf("%02x", page_fp[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
page_fp += vhe->ops->hash_len;
|
||||
page_fp += vfe->ops->hash_len;
|
||||
pagen++;
|
||||
}
|
||||
|
||||
@ -296,12 +305,12 @@ veriexec_fp_calc(struct lwp *l, struct vnode *vp,
|
||||
break;
|
||||
}
|
||||
|
||||
(vhe->ops->final)(fp, ctx);
|
||||
(vfe->ops->final)(fp, ctx);
|
||||
|
||||
if (do_perpage) {
|
||||
vhe->last_page_size = len;
|
||||
vhe->page_fp_status = PAGE_FP_READY;
|
||||
vhe->npages = npages;
|
||||
vfe->last_page_size = len;
|
||||
vfe->page_fp_status = PAGE_FP_READY;
|
||||
vfe->npages = npages;
|
||||
}
|
||||
|
||||
bad:
|
||||
@ -335,41 +344,16 @@ veriexec_fp_cmp(struct veriexec_fp_ops *ops, u_char *fp1, u_char *fp2)
|
||||
return (memcmp(fp1, fp2, ops->hash_len));
|
||||
}
|
||||
|
||||
/* Get the hash table for the specified device. */
|
||||
struct veriexec_hashtbl *
|
||||
veriexec_tblfind(dev_t device) {
|
||||
struct veriexec_hashtbl *tbl;
|
||||
|
||||
LIST_FOREACH(tbl, &veriexec_tables, hash_list) {
|
||||
if (tbl->hash_dev == device)
|
||||
return (tbl);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
struct veriexec_table_entry *
|
||||
veriexec_tblfind(struct vnode *vp)
|
||||
{
|
||||
return (fileassoc_tabledata_lookup(vp->v_mount, veriexec_hook));
|
||||
}
|
||||
|
||||
/* Perform a lookup on a hash table. */
|
||||
struct veriexec_hash_entry *
|
||||
veriexec_lookup(dev_t device, ino_t inode)
|
||||
struct veriexec_file_entry *
|
||||
veriexec_lookup(struct vnode *vp)
|
||||
{
|
||||
struct veriexec_hashtbl *tbl;
|
||||
struct veriexec_hashhead *tble;
|
||||
struct veriexec_hash_entry *e;
|
||||
size_t indx;
|
||||
|
||||
tbl = veriexec_tblfind(device);
|
||||
if (tbl == NULL)
|
||||
return (NULL);
|
||||
|
||||
indx = VERIEXEC_HASH(tbl, inode);
|
||||
tble = &(tbl->hash_tbl[indx & VERIEXEC_HASH_MASK(tbl)]);
|
||||
|
||||
LIST_FOREACH(e, tble, entries) {
|
||||
if ((e != NULL) && (e->inode == inode))
|
||||
return (e);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
return (fileassoc_lookup(vp, veriexec_hook));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -377,23 +361,22 @@ veriexec_lookup(dev_t device, ino_t inode)
|
||||
* The passed entry is allocated in kernel memory.
|
||||
*/
|
||||
int
|
||||
veriexec_hashadd(struct veriexec_hashtbl *tbl, struct veriexec_hash_entry *e)
|
||||
veriexec_hashadd(struct vnode *vp, struct veriexec_file_entry *vfe)
|
||||
{
|
||||
struct veriexec_hashhead *vhh;
|
||||
size_t indx;
|
||||
struct veriexec_table_entry *vte;
|
||||
int error;
|
||||
|
||||
if (tbl == NULL)
|
||||
return (EFAULT);
|
||||
error = fileassoc_add(vp, veriexec_hook, vfe);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
indx = VERIEXEC_HASH(tbl, e->inode);
|
||||
vhh = &(tbl->hash_tbl[indx]);
|
||||
vte = veriexec_tblfind(vp);
|
||||
#ifdef DIAGNOSTIC
|
||||
if (vte == NULL)
|
||||
panic("Fileassoc: Inconsistency with table data");
|
||||
#endif /* DIAGNOSTIC */
|
||||
|
||||
if (vhh == NULL)
|
||||
panic("veriexec: veriexec_hashadd: vhh is NULL.");
|
||||
|
||||
LIST_INSERT_HEAD(vhh, e, entries);
|
||||
|
||||
tbl->hash_count++;
|
||||
vte->vte_count++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -405,52 +388,57 @@ veriexec_hashadd(struct veriexec_hashtbl *tbl, struct veriexec_hash_entry *e)
|
||||
* vn_open(), 'flag' will be VERIEXEC_FILE.
|
||||
*/
|
||||
int
|
||||
veriexec_verify(struct lwp *l, struct vnode *vp, struct vattr *va,
|
||||
const u_char *name, int flag, struct veriexec_hash_entry **ret)
|
||||
veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag,
|
||||
struct veriexec_file_entry **ret)
|
||||
{
|
||||
struct veriexec_hash_entry *vhe;
|
||||
struct veriexec_file_entry *vfe;
|
||||
struct vattr va;
|
||||
u_char *digest;
|
||||
int error;
|
||||
|
||||
if (vp->v_type != VREG)
|
||||
return (0);
|
||||
|
||||
error = VOP_GETATTR(vp, &va, l->l_proc->p_cred, l);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Lookup veriexec table entry, save pointer if requested. */
|
||||
vhe = veriexec_lookup((dev_t)va->va_fsid, (ino_t)va->va_fileid);
|
||||
vfe = veriexec_lookup(vp);
|
||||
if (ret != NULL)
|
||||
*ret = vhe;
|
||||
if (vhe == NULL)
|
||||
*ret = vfe;
|
||||
if (vfe == NULL)
|
||||
goto out;
|
||||
|
||||
/* Evaluate fingerprint if needed. */
|
||||
error = 0;
|
||||
digest = NULL;
|
||||
if ((vhe->status == FINGERPRINT_NOTEVAL) ||
|
||||
(vhe->type & VERIEXEC_UNTRUSTED)) {
|
||||
if ((vfe->status == FINGERPRINT_NOTEVAL) ||
|
||||
(vfe->type & VERIEXEC_UNTRUSTED)) {
|
||||
/* Calculate fingerprint for on-disk file. */
|
||||
digest = (u_char *) malloc(vhe->ops->hash_len, M_TEMP,
|
||||
digest = (u_char *) malloc(vfe->ops->hash_len, M_TEMP,
|
||||
M_WAITOK);
|
||||
error = veriexec_fp_calc(l, vp, vhe, va->va_size, digest);
|
||||
error = veriexec_fp_calc(l, vp, vfe, va.va_size, digest);
|
||||
if (error) {
|
||||
veriexec_report("Fingerprint calculation error.",
|
||||
name, va, NULL, REPORT_NOVERBOSE,
|
||||
name, &va, NULL, REPORT_NOVERBOSE,
|
||||
REPORT_NOALARM, REPORT_NOPANIC);
|
||||
free(digest, M_TEMP);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Compare fingerprint with loaded data. */
|
||||
if (veriexec_fp_cmp(vhe->ops, vhe->fp, digest) == 0) {
|
||||
vhe->status = FINGERPRINT_VALID;
|
||||
if (veriexec_fp_cmp(vfe->ops, vfe->fp, digest) == 0) {
|
||||
vfe->status = FINGERPRINT_VALID;
|
||||
} else {
|
||||
vhe->status = FINGERPRINT_NOMATCH;
|
||||
vfe->status = FINGERPRINT_NOMATCH;
|
||||
}
|
||||
|
||||
free(digest, M_TEMP);
|
||||
}
|
||||
|
||||
if (!(vhe->type & flag)) {
|
||||
veriexec_report("Incorrect access type.", name, va, l,
|
||||
if (!(vfe->type & flag)) {
|
||||
veriexec_report("Incorrect access type.", name, &va, l,
|
||||
REPORT_NOVERBOSE, REPORT_ALARM,
|
||||
REPORT_NOPANIC);
|
||||
|
||||
@ -459,10 +447,10 @@ veriexec_verify(struct lwp *l, struct vnode *vp, struct vattr *va,
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
out:
|
||||
out:
|
||||
/* No entry in the veriexec tables. */
|
||||
if (vhe == NULL) {
|
||||
veriexec_report("veriexec_verify: No entry.", name, va,
|
||||
if (vfe == NULL) {
|
||||
veriexec_report("veriexec_verify: No entry.", name, &va,
|
||||
l, REPORT_VERBOSE, REPORT_NOALARM, REPORT_NOPANIC);
|
||||
|
||||
/* Lockdown mode: Deny access to non-monitored files if
|
||||
@ -477,23 +465,23 @@ out:
|
||||
return (0);
|
||||
}
|
||||
|
||||
switch (vhe->status) {
|
||||
switch (vfe->status) {
|
||||
case FINGERPRINT_NOTEVAL:
|
||||
/* Should not happen. */
|
||||
veriexec_report("veriexec_verify: Not-evaluated status "
|
||||
"post evaluation; inconsistency detected.", name, va,
|
||||
"post evaluation; inconsistency detected.", name, &va,
|
||||
NULL, REPORT_NOVERBOSE, REPORT_NOALARM, REPORT_PANIC);
|
||||
|
||||
case FINGERPRINT_VALID:
|
||||
/* Valid fingerprint. */
|
||||
veriexec_report("veriexec_verify: Match.", name, va, NULL,
|
||||
veriexec_report("veriexec_verify: Match.", name, &va, NULL,
|
||||
REPORT_VERBOSE, REPORT_NOALARM, REPORT_NOPANIC);
|
||||
|
||||
break;
|
||||
|
||||
case FINGERPRINT_NOMATCH:
|
||||
/* Fingerprint mismatch. */
|
||||
veriexec_report("veriexec_verify: Mismatch.", name, va,
|
||||
veriexec_report("veriexec_verify: Mismatch.", name, &va,
|
||||
NULL, REPORT_NOVERBOSE, REPORT_ALARM, REPORT_NOPANIC);
|
||||
|
||||
/* IDS mode: Deny access on fingerprint mismatch. */
|
||||
@ -503,12 +491,9 @@ out:
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* Should never happen.
|
||||
* XXX: Print vnode/process?
|
||||
*/
|
||||
/* Should never happen. */
|
||||
veriexec_report("veriexec_verify: Invalid status "
|
||||
"post evaluation.", name, va, NULL, REPORT_NOVERBOSE,
|
||||
"post evaluation.", name, &va, NULL, REPORT_NOVERBOSE,
|
||||
REPORT_NOALARM, REPORT_PANIC);
|
||||
}
|
||||
|
||||
@ -519,7 +504,7 @@ out:
|
||||
* Evaluate per-page fingerprints.
|
||||
*/
|
||||
int
|
||||
veriexec_page_verify(struct veriexec_hash_entry *vhe, struct vattr *va,
|
||||
veriexec_page_verify(struct veriexec_file_entry *vfe, struct vattr *va,
|
||||
struct vm_page *pg, size_t idx, struct lwp *l)
|
||||
{
|
||||
void *ctx;
|
||||
@ -528,31 +513,31 @@ veriexec_page_verify(struct veriexec_hash_entry *vhe, struct vattr *va,
|
||||
int error;
|
||||
vaddr_t kva;
|
||||
|
||||
if (vhe->page_fp_status == PAGE_FP_NONE)
|
||||
if (vfe->page_fp_status == PAGE_FP_NONE)
|
||||
return (0);
|
||||
|
||||
if (vhe->page_fp_status == PAGE_FP_FAIL)
|
||||
if (vfe->page_fp_status == PAGE_FP_FAIL)
|
||||
return (EPERM);
|
||||
|
||||
if (idx >= vhe->npages)
|
||||
if (idx >= vfe->npages)
|
||||
return (0);
|
||||
|
||||
ctx = malloc(vhe->ops->context_size, M_TEMP, M_WAITOK);
|
||||
fp = malloc(vhe->ops->hash_len, M_TEMP, M_WAITOK);
|
||||
ctx = malloc(vfe->ops->context_size, M_TEMP, M_WAITOK);
|
||||
fp = malloc(vfe->ops->hash_len, M_TEMP, M_WAITOK);
|
||||
kva = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA);
|
||||
pmap_kenter_pa(kva, VM_PAGE_TO_PHYS(pg), VM_PROT_READ);
|
||||
|
||||
page_fp = (u_char *) vhe->page_fp + (vhe->ops->hash_len * idx);
|
||||
(vhe->ops->init)(ctx);
|
||||
(vhe->ops->update)(ctx, (void *) kva,
|
||||
((vhe->npages - 1) == idx) ? vhe->last_page_size
|
||||
page_fp = (u_char *) vfe->page_fp + (vfe->ops->hash_len * idx);
|
||||
(vfe->ops->init)(ctx);
|
||||
(vfe->ops->update)(ctx, (void *) kva,
|
||||
((vfe->npages - 1) == idx) ? vfe->last_page_size
|
||||
: PAGE_SIZE);
|
||||
(vhe->ops->final)(fp, ctx);
|
||||
(vfe->ops->final)(fp, ctx);
|
||||
|
||||
pmap_kremove(kva, PAGE_SIZE);
|
||||
uvm_km_free(kernel_map, kva, PAGE_SIZE, UVM_KMF_VAONLY);
|
||||
|
||||
error = veriexec_fp_cmp(vhe->ops, page_fp, fp);
|
||||
error = veriexec_fp_cmp(vfe->ops, page_fp, fp);
|
||||
if (error) {
|
||||
const char *msg;
|
||||
|
||||
@ -591,8 +576,8 @@ veriexec_page_verify(struct veriexec_hash_entry *vhe, struct vattr *va,
|
||||
int
|
||||
veriexec_removechk(struct lwp *l, struct vnode *vp, const char *pathbuf)
|
||||
{
|
||||
struct veriexec_hashtbl *tbl;
|
||||
struct veriexec_hash_entry *vhe;
|
||||
struct veriexec_file_entry *vfe;
|
||||
struct veriexec_table_entry *vte;
|
||||
struct vattr va;
|
||||
int error;
|
||||
|
||||
@ -600,8 +585,8 @@ veriexec_removechk(struct lwp *l, struct vnode *vp, const char *pathbuf)
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
vhe = veriexec_lookup(va.va_fsid, va.va_fileid);
|
||||
if (vhe == NULL) {
|
||||
vfe = veriexec_lookup(vp);
|
||||
if (vfe == NULL) {
|
||||
/* Lockdown mode: Deny access to non-monitored files. */
|
||||
if (veriexec_strict >= 3)
|
||||
return (EPERM);
|
||||
@ -616,21 +601,15 @@ veriexec_removechk(struct lwp *l, struct vnode *vp, const char *pathbuf)
|
||||
if (veriexec_strict >= 2)
|
||||
return (EPERM);
|
||||
|
||||
tbl = veriexec_tblfind(va.va_fsid);
|
||||
if (tbl == NULL) {
|
||||
veriexec_report("veriexec_removechk: Inconsistency "
|
||||
"detected: Could not get table for file in lists.",
|
||||
pathbuf, &va, NULL, REPORT_NOVERBOSE, REPORT_NOALARM,
|
||||
REPORT_PANIC);
|
||||
}
|
||||
fileassoc_clear(vp, veriexec_hook);
|
||||
|
||||
LIST_REMOVE(vhe, entries);
|
||||
if (vhe->fp != NULL)
|
||||
free(vhe->fp, M_TEMP);
|
||||
if (vhe->page_fp != NULL)
|
||||
free(vhe->page_fp, M_TEMP);
|
||||
free(vhe, M_TEMP);
|
||||
tbl->hash_count--;
|
||||
vte = veriexec_tblfind(vp);
|
||||
#ifdef DIAGNOSTIC
|
||||
if (vte == NULL)
|
||||
panic("Fileassoc: Inconsistency during entry removel");
|
||||
#endif /* DIAGNOSTIC */
|
||||
|
||||
vte->vte_count--;
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -642,7 +621,7 @@ int
|
||||
veriexec_renamechk(struct vnode *vp, const char *from, const char *to,
|
||||
struct lwp *l)
|
||||
{
|
||||
struct veriexec_hash_entry *vhe;
|
||||
struct veriexec_file_entry *vfe;
|
||||
struct vattr va;
|
||||
int error;
|
||||
|
||||
@ -651,24 +630,22 @@ veriexec_renamechk(struct vnode *vp, const char *from, const char *to,
|
||||
return (error);
|
||||
|
||||
if (veriexec_strict >= 3) {
|
||||
printf("Veriexec: veriexec_renamechk: Preventing rename "
|
||||
"of \"%s\" [%ld:%llu] to \"%s\", uid=%u, pid=%u: "
|
||||
"Lockdown mode.\n", from, va.va_fsid,
|
||||
(unsigned long long)va.va_fileid,
|
||||
printf("Veriexec: Preventing rename of \"%s\" [%ld:%llu] to "
|
||||
"\"%s\", uid=%u, pid=%u: Lockdown mode.\n", from,
|
||||
va.va_fsid, (unsigned long long)va.va_fileid,
|
||||
to, kauth_cred_geteuid(l->l_proc->p_cred),
|
||||
l->l_proc->p_pid);
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
vhe = veriexec_lookup(va.va_fsid, va.va_fileid);
|
||||
if (vhe != NULL) {
|
||||
vfe = veriexec_lookup(vp);
|
||||
if (vfe != NULL) {
|
||||
if (veriexec_strict >= 2) {
|
||||
printf("Veriexec: veriexec_renamechk: Preventing "
|
||||
"rename of \"%s\" [%ld:%llu] to \"%s\", "
|
||||
"uid=%u, pid=%u: IPS mode, file "
|
||||
"monitored.\n", from, va.va_fsid,
|
||||
(unsigned long long)va.va_fileid,
|
||||
to, kauth_cred_geteuid(l->l_proc->p_cred),
|
||||
printf("Veriexec: Preventing rename of \"%s\" "
|
||||
"[%ld:%llu] to \"%s\", uid=%u, pid=%u: "
|
||||
"IPS mode, file monitored.\n", from, va.va_fsid,
|
||||
(unsigned long long)va.va_fileid, to,
|
||||
kauth_cred_geteuid(l->l_proc->p_cred),
|
||||
l->l_proc->p_pid);
|
||||
return (EPERM);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: vfs_syscalls.c,v 1.250 2006/07/14 18:30:35 yamt Exp $ */
|
||||
/* $NetBSD: vfs_syscalls.c,v 1.251 2006/07/14 18:41:40 elad Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
@ -37,13 +37,14 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.250 2006/07/14 18:30:35 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.251 2006/07/14 18:41:40 elad Exp $");
|
||||
|
||||
#include "opt_compat_netbsd.h"
|
||||
#include "opt_compat_43.h"
|
||||
#include "opt_ktrace.h"
|
||||
#include "opt_verified_exec.h"
|
||||
#include "fss.h"
|
||||
#include "opt_fileassoc.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -65,6 +66,9 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.250 2006/07/14 18:30:35 yamt Exp
|
||||
#ifdef KTRACE
|
||||
#include <sys/ktrace.h>
|
||||
#endif
|
||||
#ifdef FILEASSOC
|
||||
#include <sys/fileassoc.h>
|
||||
#endif /* FILEASSOC */
|
||||
#ifdef VERIFIED_EXEC
|
||||
#include <sys/verified_exec.h>
|
||||
#endif /* VERIFIED_EXEC */
|
||||
@ -546,6 +550,35 @@ dounmount(struct mount *mp, int flags, struct lwp *l)
|
||||
int async;
|
||||
int used_syncer;
|
||||
|
||||
#ifdef VERIFIED_EXEC
|
||||
if (!doing_shutdown) {
|
||||
if (veriexec_strict >= 3) {
|
||||
printf("Veriexec: Lockdown mode, preventing unmount of"
|
||||
" \"%s\". (uid=%u)\n", mp->mnt_stat.f_mntonname,
|
||||
kauth_cred_getuid(l->l_proc->p_cred));
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
if (veriexec_strict == 2) {
|
||||
struct veriexec_table_entry *vte;
|
||||
|
||||
/* Check if we have fingerprints on mount. */
|
||||
vte = fileassoc_tabledata_lookup(mp, veriexec_hook);
|
||||
if ((vte != NULL) && (vte->vte_count > 0)) {
|
||||
printf("Veriexec: IPS mode, preventing unmount"
|
||||
" of \"%s\" with monitored files. "
|
||||
"(uid=%u)\n", mp->mnt_stat.f_mntonname,
|
||||
kauth_cred_getuid(l->l_proc->p_cred));
|
||||
return (EPERM);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* VERIFIED_EXEC */
|
||||
|
||||
#ifdef FILEASSOC
|
||||
(void)fileassoc_table_delete(mp);
|
||||
#endif /* FILEASSOC */
|
||||
|
||||
simple_lock(&mountlist_slock);
|
||||
vfs_unbusy(mp);
|
||||
used_syncer = (mp->mnt_syncer != NULL);
|
||||
@ -2019,6 +2052,10 @@ restart:
|
||||
VOP_LEASE(vp, l, p->p_cred, LEASE_WRITE);
|
||||
error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
|
||||
vn_finished_write(mp, 0);
|
||||
#ifdef FILEASSOC
|
||||
if (!error)
|
||||
(void)fileassoc_file_delete(nd.ni_vp);
|
||||
#endif /* FILEASSOC */
|
||||
out:
|
||||
return (error);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: vfs_vnops.c,v 1.112 2006/05/27 23:46:49 simonb Exp $ */
|
||||
/* $NetBSD: vfs_vnops.c,v 1.113 2006/07/14 18:41:40 elad Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 1989, 1993
|
||||
@ -37,7 +37,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.112 2006/05/27 23:46:49 simonb Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.113 2006/07/14 18:41:40 elad Exp $");
|
||||
|
||||
#include "opt_verified_exec.h"
|
||||
|
||||
@ -105,7 +105,7 @@ vn_open(struct nameidata *ndp, int fmode, int cmode)
|
||||
struct vattr va;
|
||||
int error;
|
||||
#ifdef VERIFIED_EXEC
|
||||
struct veriexec_hash_entry *vhe = NULL;
|
||||
struct veriexec_file_entry *vfe = NULL;
|
||||
char pathbuf[MAXPATHLEN];
|
||||
size_t pathlen;
|
||||
int (*copyfun)(const void *, void *, size_t, size_t *) =
|
||||
@ -208,8 +208,8 @@ restart:
|
||||
|
||||
if ((fmode & O_CREAT) == 0) {
|
||||
#ifdef VERIFIED_EXEC
|
||||
if ((error = veriexec_verify(l, vp, &va, pathbuf,
|
||||
VERIEXEC_FILE, &vhe)) != 0)
|
||||
if ((error = veriexec_verify(l, vp, pathbuf,
|
||||
VERIEXEC_FILE, &vfe)) != 0)
|
||||
goto bad;
|
||||
#endif
|
||||
|
||||
@ -227,7 +227,7 @@ restart:
|
||||
(error = VOP_ACCESS(vp, VWRITE, cred, l)) != 0)
|
||||
goto bad;
|
||||
#ifdef VERIFIED_EXEC
|
||||
if (vhe != NULL) {
|
||||
if (vfe != NULL) {
|
||||
veriexec_report("Write access request.",
|
||||
pathbuf, &va, l,
|
||||
REPORT_NOVERBOSE,
|
||||
@ -239,7 +239,7 @@ restart:
|
||||
error = EPERM;
|
||||
goto bad;
|
||||
} else {
|
||||
vhe->status = FINGERPRINT_NOTEVAL;
|
||||
vfe->status = FINGERPRINT_NOTEVAL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
99
sys/sys/fileassoc.h
Normal file
99
sys/sys/fileassoc.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* $NetBSD: fileassoc.h,v 1.1 2006/07/14 18:41:40 elad 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_FILEASSOC_H_
|
||||
#define _SYS_FILEASSOC_H_
|
||||
|
||||
#include "opt_fileassoc.h"
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/hash.h>
|
||||
|
||||
/* Max. number of hooks. */
|
||||
#ifndef FILEASSOC_NHOOKS
|
||||
#define FILEASSOC_NHOOKS 4
|
||||
#endif /* !FILEASSOC_NHOOKS */
|
||||
|
||||
#define FILEASSOC_INVAL -1
|
||||
|
||||
typedef int fileassoc_t;
|
||||
typedef void (*fileassoc_cleanup_cb_t)(void *, int);
|
||||
|
||||
/*
|
||||
* Hook entry.
|
||||
* Includes the hook name for identification and private hook clear callback.
|
||||
*/
|
||||
struct fileassoc_hook {
|
||||
const char *hook_name; /* Hook name. */
|
||||
fileassoc_cleanup_cb_t hook_cleanup_cb; /* Hook clear callback. */
|
||||
};
|
||||
|
||||
/* An entry in the per-device hash table. */
|
||||
struct fileassoc_hash_entry {
|
||||
ino_t fileid; /* File id. */
|
||||
void *hooks[FILEASSOC_NHOOKS]; /* Hooks. */
|
||||
LIST_ENTRY(fileassoc_hash_entry) entries; /* List pointer. */
|
||||
};
|
||||
|
||||
LIST_HEAD(fileassoc_hashhead, fileassoc_hash_entry);
|
||||
|
||||
struct fileassoc_table {
|
||||
struct fileassoc_hashhead *hash_tbl;
|
||||
size_t hash_size; /* Number of slots. */
|
||||
struct mount *tbl_mntpt;
|
||||
u_long hash_mask;
|
||||
void *tables[FILEASSOC_NHOOKS];
|
||||
LIST_ENTRY(fileassoc_table) hash_list; /* List pointer. */
|
||||
};
|
||||
|
||||
#define FILEASSOC_CLEANUP_TABLE 0
|
||||
#define FILEASSOC_CLEANUP_FILE 1
|
||||
|
||||
void fileassoc_init(void);
|
||||
fileassoc_t fileassoc_register(const char *, fileassoc_cleanup_cb_t);
|
||||
int fileassoc_deregister(fileassoc_t);
|
||||
struct fileassoc_table *fileassoc_table_lookup(struct mount *);
|
||||
void *fileassoc_tabledata_lookup(struct mount *, fileassoc_t);
|
||||
struct fileassoc_hash_entry *fileassoc_file_lookup(struct vnode *);
|
||||
void *fileassoc_lookup(struct vnode *, fileassoc_t);
|
||||
int fileassoc_table_add(struct mount *, size_t);
|
||||
int fileassoc_table_delete(struct mount *);
|
||||
int fileassoc_table_clear(struct mount *, fileassoc_t);
|
||||
int fileassoc_tabledata_add(struct mount *, fileassoc_t, void *);
|
||||
int fileassoc_tabledata_clear(struct mount *, fileassoc_t);
|
||||
struct fileassoc_hash_entry *fileassoc_file_add(struct vnode *);
|
||||
int fileassoc_file_delete(struct vnode *);
|
||||
int fileassoc_add(struct vnode *, fileassoc_t, void *);
|
||||
int fileassoc_clear(struct vnode *, fileassoc_t);
|
||||
|
||||
#endif /* !_SYS_FILEASSOC_H_ */
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: verified_exec.h,v 1.28 2005/12/12 21:47:58 elad Exp $ */
|
||||
/* $NetBSD: verified_exec.h,v 1.29 2006/07/14 18:41:40 elad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright 2005 Elad Efrat <elad@bsd.org.il>
|
||||
@ -51,19 +51,17 @@ struct veriexec_params {
|
||||
};
|
||||
|
||||
struct veriexec_sizing_params {
|
||||
dev_t dev;
|
||||
size_t hash_size;
|
||||
u_char file[MAXPATHLEN];
|
||||
};
|
||||
|
||||
struct veriexec_delete_params {
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
u_char file[MAXPATHLEN];
|
||||
};
|
||||
|
||||
struct veriexec_query_params {
|
||||
u_char file[MAXPATHLEN];
|
||||
unsigned char fp_type[VERIEXEC_TYPE_MAXLEN];
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
unsigned char type;
|
||||
unsigned char status;
|
||||
unsigned char *fp;
|
||||
@ -114,6 +112,7 @@ extern int veriexec_strict;
|
||||
#ifdef VERIEXEC_NEED_NODE
|
||||
extern const struct sysctlnode *veriexec_count_node;
|
||||
#endif /* VERIEXEC_NEED_NODE */
|
||||
extern int veriexec_hook;
|
||||
|
||||
/*
|
||||
* Operations vector for verified exec, this defines the characteristics
|
||||
@ -134,37 +133,24 @@ struct veriexec_fp_ops {
|
||||
LIST_ENTRY(veriexec_fp_ops) entries;
|
||||
};
|
||||
|
||||
/* An entry in the per-device hash table. */
|
||||
struct veriexec_hash_entry {
|
||||
ino_t inode; /* Inode number. */
|
||||
unsigned char type; /* Entry type. */
|
||||
unsigned char status; /* Evaluation status. */
|
||||
unsigned char page_fp_status; /* Per-page FP status. */
|
||||
unsigned char *fp; /* Fingerprint. */
|
||||
void *page_fp; /* Per-page fingerprints */
|
||||
size_t npages; /* Number of pages. */
|
||||
size_t last_page_size; /* To support < PAGE_SIZE */
|
||||
struct veriexec_fp_ops *ops; /* Fingerprint ops vector*/
|
||||
LIST_ENTRY(veriexec_hash_entry) entries; /* List pointer. */
|
||||
/* Veriexec per-file entry data. */
|
||||
struct veriexec_file_entry {
|
||||
u_char type; /* Entry type. */
|
||||
u_char status; /* Evaluation status. */
|
||||
u_char page_fp_status; /* Per-page FP status. */
|
||||
u_char *fp; /* Fingerprint. */
|
||||
void *page_fp; /* Per-page fingerprints */
|
||||
size_t npages; /* Number of pages. */
|
||||
size_t last_page_size; /* To support < PAGE_SIZE */
|
||||
struct veriexec_fp_ops *ops; /* Fingerprint ops vector*/
|
||||
};
|
||||
|
||||
LIST_HEAD(veriexec_hashhead, veriexec_hash_entry);
|
||||
|
||||
/* Veriexec hash table information. */
|
||||
struct veriexec_hashtbl {
|
||||
struct veriexec_hashhead *hash_tbl;
|
||||
size_t hash_size; /* Number of slots in the table. */
|
||||
dev_t hash_dev; /* Device ID the hash table refers to. */
|
||||
uint64_t hash_count; /* # of fingerprinted files in table. */
|
||||
LIST_ENTRY(veriexec_hashtbl) hash_list;
|
||||
/* Veriexec per-table data. */
|
||||
struct veriexec_table_entry {
|
||||
uint64_t vte_count; /* Number of Veriexec entries. */
|
||||
const struct sysctlnode *vte_node;
|
||||
};
|
||||
|
||||
/* Global list of hash tables, one per device. */
|
||||
LIST_HEAD(, veriexec_hashtbl) veriexec_tables;
|
||||
|
||||
/* Mask to ensure bounded access to elements in the hash table. */
|
||||
#define VERIEXEC_HASH_MASK(tbl) ((tbl)->hash_size - 1)
|
||||
|
||||
/* Readable values for veriexec_report(). */
|
||||
#define REPORT_NOVERBOSE 0 /* Always print */
|
||||
#define REPORT_VERBOSE 1 /* Print when verbose >= 1 */
|
||||
@ -174,14 +160,6 @@ LIST_HEAD(, veriexec_hashtbl) veriexec_tables;
|
||||
#define REPORT_NOALARM 0 /* Normal report */
|
||||
#define REPORT_ALARM 1 /* Alarm - also print pid/uid/.. */
|
||||
|
||||
/*
|
||||
* Hashing function: Takes an inode number modulus the mask to give back
|
||||
* an index into the hash table.
|
||||
*/
|
||||
#define VERIEXEC_HASH(tbl, inode) \
|
||||
(hash32_buf(&(inode), sizeof((inode)), HASH32_BUF_INIT) \
|
||||
& VERIEXEC_HASH_MASK(tbl))
|
||||
|
||||
/* Initialize a fingerprint ops struct. */
|
||||
#define VERIEXEC_OPINIT(ops, fp_type, hashlen, ctx_size, init_fn, \
|
||||
update_fn, final_fn) \
|
||||
@ -198,14 +176,14 @@ int veriexec_add_fp_ops(struct veriexec_fp_ops *);
|
||||
void veriexec_init_fp_ops(void);
|
||||
struct veriexec_fp_ops *veriexec_find_ops(u_char *name);
|
||||
int veriexec_fp_calc(struct lwp *, struct vnode *,
|
||||
struct veriexec_hash_entry *, uint64_t, u_char *);
|
||||
struct veriexec_file_entry *, uint64_t, u_char *);
|
||||
int veriexec_fp_cmp(struct veriexec_fp_ops *, u_char *, u_char *);
|
||||
struct veriexec_hashtbl *veriexec_tblfind(dev_t);
|
||||
struct veriexec_hash_entry *veriexec_lookup(dev_t, ino_t);
|
||||
int veriexec_hashadd(struct veriexec_hashtbl *, struct veriexec_hash_entry *);
|
||||
int veriexec_verify(struct lwp *, struct vnode *, struct vattr *,
|
||||
const u_char *, int, struct veriexec_hash_entry **);
|
||||
int veriexec_page_verify(struct veriexec_hash_entry *, struct vattr *,
|
||||
struct veriexec_table_entry *veriexec_tblfind(struct vnode *);
|
||||
struct veriexec_file_entry *veriexec_lookup(struct vnode *);
|
||||
int veriexec_hashadd(struct vnode *, struct veriexec_file_entry *);
|
||||
int veriexec_verify(struct lwp *, struct vnode *,
|
||||
const u_char *, int, struct veriexec_file_entry **);
|
||||
int veriexec_page_verify(struct veriexec_file_entry *, struct vattr *,
|
||||
struct vm_page *, size_t, struct lwp *);
|
||||
int veriexec_removechk(struct lwp *, struct vnode *, const char *);
|
||||
int veriexec_renamechk(struct vnode *, const char *, const char *,
|
||||
@ -213,10 +191,11 @@ int veriexec_renamechk(struct vnode *, const char *, const char *,
|
||||
void veriexec_init_fp_ops(void);
|
||||
void veriexec_report(const u_char *, const u_char *, struct vattr *,
|
||||
struct lwp *, int, int, int);
|
||||
int veriexec_newtable(struct veriexec_sizing_params *);
|
||||
int veriexec_newtable(struct veriexec_sizing_params *, struct lwp *);
|
||||
int veriexec_load(struct veriexec_params *, struct lwp *);
|
||||
int veriexec_delete(struct veriexec_delete_params *);
|
||||
int veriexec_query(struct veriexec_query_params *);
|
||||
int veriexec_delete(struct veriexec_delete_params *, struct lwp *);
|
||||
int veriexec_query(struct veriexec_query_params *, struct lwp *);
|
||||
void veriexec_clear(void *, int);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user