Add some new options to mac_bsdestended. We can now match on:

subject: ranges of uid, ranges of gid, jail id
	objects: ranges of uid, ranges of gid, filesystem,
		object is suid, object is sgid, object matches subject uid/gid
		object type

We can also negate individual conditions. The ruleset language is
a superset of the previous language, so old rules should continue
to work.

These changes require a change to the API between libugidfw and the
mac_bsdextended module. Add a version number, so we can tell if
we're running mismatched versions.

Update man pages to reflect changes, add extra test cases to
test_ugidfw.c and add a shell script that checks that the the
module seems to do what we expect.

Suggestions from: rwatson, trhodes
Reviewed by: trhodes
MFC after: 2 months
This commit is contained in:
David Malone 2006-04-23 17:06:18 +00:00
parent 19af5f6b17
commit 89ddbd45e5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=157986
9 changed files with 1362 additions and 277 deletions

View file

@ -59,14 +59,6 @@ Converts the internal representation of a rule
into its text representation;
see
.Xr bsde_rule_to_string 3 .
.It Fn bsde_parse_identity
Parses the identity of a subject or object;
see
.Xr bsde_parse_identity 3 .
.It Fn bsde_parse_mode
Parses the access mode for a ugidfw rule;
see
.Xr bsde_parse_mode 3 .
.It Fn bsde_parse_rule
Parses an entire rule
(in argument array form);
@ -108,8 +100,6 @@ rule number; see
.Xr bsde_get_rule 3 ,
.Xr bsde_get_rule_count 3 ,
.Xr bsde_get_rule_slots 3 ,
.Xr bsde_parse_identity 3 ,
.Xr bsde_parse_mode 3 ,
.Xr bsde_parse_rule 3 ,
.Xr bsde_parse_rule_string 3 ,
.Xr bsde_rule_to_string 3 ,

File diff suppressed because it is too large Load diff

View file

@ -37,9 +37,6 @@
__BEGIN_DECLS
int bsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf,
size_t buflen);
int bsde_parse_identity(int argc, char *argv[],
struct mac_bsdextended_identity *identity, size_t buflen,
char *errstr);
int bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
char *errstr);
int bsde_parse_rule(int argc, char *argv[],

View file

@ -47,6 +47,7 @@
#include <sys/acl.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/jail.h>
#include <sys/lock.h>
#include <sys/mac.h>
#include <sys/malloc.h>
@ -62,6 +63,7 @@
#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/ucred.h>
#include <net/bpfdesc.h>
#include <net/if.h>
@ -92,11 +94,14 @@ MALLOC_DEFINE(M_MACBSDEXTENDED, "mac_bsdextended", "BSD Extended MAC rule");
static struct mac_bsdextended_rule *rules[MAC_BSDEXTENDED_MAXRULES];
static int rule_count = 0;
static int rule_slots = 0;
static int rule_version = MB_VERSION;
SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_count, CTLFLAG_RD,
&rule_count, 0, "Number of defined rules\n");
SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_slots, CTLFLAG_RD,
&rule_slots, 0, "Number of used rule slots\n");
SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_version, CTLFLAG_RD,
&rule_version, 0, "Version number for API\n");
/*
* This is just used for logging purposes, eventually we would like
@ -121,10 +126,20 @@ static int
mac_bsdextended_rule_valid(struct mac_bsdextended_rule *rule)
{
if ((rule->mbr_subject.mbi_flags | MBI_BITS) != MBI_BITS)
if ((rule->mbr_subject.mbs_flags | MBS_ALL_FLAGS) != MBS_ALL_FLAGS)
return (EINVAL);
if ((rule->mbr_object.mbi_flags | MBI_BITS) != MBI_BITS)
if ((rule->mbr_subject.mbs_neg | MBS_ALL_FLAGS) != MBS_ALL_FLAGS)
return (EINVAL);
if ((rule->mbr_object.mbo_flags | MBO_ALL_FLAGS) != MBO_ALL_FLAGS)
return (EINVAL);
if ((rule->mbr_object.mbo_neg | MBO_ALL_FLAGS) != MBO_ALL_FLAGS)
return (EINVAL);
if ((rule->mbr_object.mbo_neg | MBO_TYPE_DEFINED) &&
(rule->mbr_object.mbo_type | MBO_ALL_TYPE) != MBO_ALL_TYPE)
return (EINVAL);
if ((rule->mbr_mode | MBI_ALLPERM) != MBI_ALLPERM)
@ -240,32 +255,59 @@ mac_bsdextended_destroy(struct mac_policy_conf *mpc)
static int
mac_bsdextended_rulecheck(struct mac_bsdextended_rule *rule,
struct ucred *cred, uid_t object_uid, gid_t object_gid, int acc_mode)
struct ucred *cred, struct vnode *vp, struct vattr *vap, int acc_mode)
{
int match;
int i;
/*
* Is there a subject match?
*/
mtx_assert(&mac_bsdextended_mtx, MA_OWNED);
if (rule->mbr_subject.mbi_flags & MBI_UID_DEFINED) {
match = (rule->mbr_subject.mbi_uid == cred->cr_uid ||
rule->mbr_subject.mbi_uid == cred->cr_ruid ||
rule->mbr_subject.mbi_uid == cred->cr_svuid);
if (rule->mbr_subject.mbs_flags & MBS_UID_DEFINED) {
match = ((cred->cr_uid <= rule->mbr_subject.mbs_uid_max &&
cred->cr_uid >= rule->mbr_subject.mbs_uid_min) ||
(cred->cr_ruid <= rule->mbr_subject.mbs_uid_max &&
cred->cr_ruid >= rule->mbr_subject.mbs_uid_min) ||
(cred->cr_svuid <= rule->mbr_subject.mbs_uid_max &&
cred->cr_svuid >= rule->mbr_subject.mbs_uid_min));
if (rule->mbr_subject.mbi_flags & MBI_NEGATED)
if (rule->mbr_subject.mbs_neg & MBS_UID_DEFINED)
match = !match;
if (!match)
return (0);
}
if (rule->mbr_subject.mbi_flags & MBI_GID_DEFINED) {
match = (groupmember(rule->mbr_subject.mbi_gid, cred) ||
rule->mbr_subject.mbi_gid == cred->cr_rgid ||
rule->mbr_subject.mbi_gid == cred->cr_svgid);
if (rule->mbr_subject.mbs_flags & MBS_GID_DEFINED) {
match = ((cred->cr_rgid <= rule->mbr_subject.mbs_gid_max &&
cred->cr_rgid >= rule->mbr_subject.mbs_gid_min) ||
(cred->cr_svgid <= rule->mbr_subject.mbs_gid_max &&
cred->cr_svgid >= rule->mbr_subject.mbs_gid_min));
if (rule->mbr_subject.mbi_flags & MBI_NEGATED)
if (!match) {
for (i = 0; i < cred->cr_ngroups; i++)
if (cred->cr_groups[i]
<= rule->mbr_subject.mbs_gid_max &&
cred->cr_groups[i]
>= rule->mbr_subject.mbs_gid_min) {
match = 1;
break;
}
}
if (rule->mbr_subject.mbs_neg & MBS_GID_DEFINED)
match = !match;
if (!match)
return (0);
}
if (rule->mbr_subject.mbs_flags & MBS_PRISON_DEFINED) {
match = (cred->cr_prison != NULL &&
cred->cr_prison->pr_id == rule->mbr_subject.mbs_prison);
if (rule->mbr_subject.mbs_neg & MBS_PRISON_DEFINED)
match = !match;
if (!match)
@ -275,26 +317,118 @@ mac_bsdextended_rulecheck(struct mac_bsdextended_rule *rule,
/*
* Is there an object match?
*/
if (rule->mbr_object.mbi_flags & MBI_UID_DEFINED) {
match = (rule->mbr_object.mbi_uid == object_uid);
if (rule->mbr_object.mbo_flags & MBO_UID_DEFINED) {
match = (vap->va_uid <= rule->mbr_object.mbo_uid_max &&
vap->va_uid >= rule->mbr_object.mbo_uid_min);
if (rule->mbr_object.mbi_flags & MBI_NEGATED)
if (rule->mbr_object.mbo_neg & MBO_UID_DEFINED)
match = !match;
if (!match)
return (0);
}
if (rule->mbr_object.mbi_flags & MBI_GID_DEFINED) {
match = (rule->mbr_object.mbi_gid == object_gid);
if (rule->mbr_object.mbo_flags & MBO_GID_DEFINED) {
match = (vap->va_gid <= rule->mbr_object.mbo_gid_max &&
vap->va_gid >= rule->mbr_object.mbo_gid_min);
if (rule->mbr_object.mbi_flags & MBI_NEGATED)
if (rule->mbr_object.mbo_neg & MBO_GID_DEFINED)
match = !match;
if (!match)
return (0);
}
if (rule->mbr_object.mbo_flags & MBO_FSID_DEFINED) {
match = (bcmp(&(vp->v_mount->mnt_stat.f_fsid),
&(rule->mbr_object.mbo_fsid),
sizeof(rule->mbr_object.mbo_fsid)) == 0);
if (rule->mbr_object.mbo_neg & MBO_FSID_DEFINED)
match = !match;
if (!match)
return 0;
}
if (rule->mbr_object.mbo_flags & MBO_SUID) {
match = (vap->va_mode & VSUID);
if (rule->mbr_object.mbo_neg & MBO_SUID)
match = !match;
if (!match)
return 0;
}
if (rule->mbr_object.mbo_flags & MBO_SGID) {
match = (vap->va_mode & VSGID);
if (rule->mbr_object.mbo_neg & MBO_SGID)
match = !match;
if (!match)
return 0;
}
if (rule->mbr_object.mbo_flags & MBO_UID_SUBJECT) {
match = (vap->va_uid == cred->cr_uid ||
vap->va_uid == cred->cr_ruid ||
vap->va_uid == cred->cr_svuid);
if (rule->mbr_object.mbo_neg & MBO_UID_SUBJECT)
match = !match;
if (!match)
return 0;
}
if (rule->mbr_object.mbo_flags & MBO_GID_SUBJECT) {
match = (groupmember(vap->va_gid, cred) ||
vap->va_gid == cred->cr_rgid ||
vap->va_gid == cred->cr_svgid);
if (rule->mbr_object.mbo_neg & MBO_GID_SUBJECT)
match = !match;
if (!match)
return 0;
}
if (rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) {
switch (vap->va_type) {
case VREG:
match = (rule->mbr_object.mbo_type & MBO_TYPE_REG);
break;
case VDIR:
match = (rule->mbr_object.mbo_type & MBO_TYPE_DIR);
break;
case VBLK:
match = (rule->mbr_object.mbo_type & MBO_TYPE_BLK);
break;
case VCHR:
match = (rule->mbr_object.mbo_type & MBO_TYPE_CHR);
break;
case VLNK:
match = (rule->mbr_object.mbo_type & MBO_TYPE_LNK);
break;
case VSOCK:
match = (rule->mbr_object.mbo_type & MBO_TYPE_SOCK);
break;
case VFIFO:
match = (rule->mbr_object.mbo_type & MBO_TYPE_FIFO);
break;
default:
match = 0;
}
if (rule->mbr_object.mbo_neg & MBO_TYPE_DEFINED)
match = !match;
if (!match)
return 0;
}
/*
* Is the access permitted?
*/
@ -302,7 +436,7 @@ mac_bsdextended_rulecheck(struct mac_bsdextended_rule *rule,
if (mac_bsdextended_logging)
log(LOG_AUTHPRIV, "mac_bsdextended: %d:%d request %d"
" on %d:%d failed. \n", cred->cr_ruid,
cred->cr_rgid, acc_mode, object_uid, object_gid);
cred->cr_rgid, acc_mode, vap->va_uid, vap->va_gid);
return (EACCES); /* Matching rule denies access */
}
@ -317,7 +451,7 @@ mac_bsdextended_rulecheck(struct mac_bsdextended_rule *rule,
}
static int
mac_bsdextended_check(struct ucred *cred, uid_t object_uid, gid_t object_gid,
mac_bsdextended_check(struct ucred *cred, struct vnode *vp, struct vattr *vap,
int acc_mode)
{
int error, i;
@ -339,8 +473,8 @@ mac_bsdextended_check(struct ucred *cred, uid_t object_uid, gid_t object_gid,
acc_mode |= MBI_WRITE;
}
error = mac_bsdextended_rulecheck(rules[i], cred, object_uid,
object_gid, acc_mode);
error = mac_bsdextended_rulecheck(rules[i], cred,
vp, vap, acc_mode);
if (error == EJUSTRETURN)
break;
if (error) {
@ -365,8 +499,7 @@ mac_bsdextended_check_vp(struct ucred *cred, struct vnode *vp, int acc_mode)
if (error)
return (error);
return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
acc_mode));
return (mac_bsdextended_check(cred, vp, &vap, acc_mode));
}
static int

View file

@ -37,10 +37,7 @@
#ifndef _SYS_SECURITY_MAC_BSDEXTENDED_H
#define _SYS_SECURITY_MAC_BSDEXTENDED_H
#define MBI_UID_DEFINED 0x00000001 /* uid field should be used */
#define MBI_GID_DEFINED 0x00000002 /* gid field should be used */
#define MBI_NEGATED 0x00000004 /* negate uid/gid matches */
#define MBI_BITS (MBI_UID_DEFINED | MBI_GID_DEFINED | MBI_NEGATED)
#define MB_VERSION 2 /* Used to check library and kernel are the same. */
/*
* Rights that can be represented in mbr_mode. These have the same values
@ -57,15 +54,60 @@
#define MBI_ALLPERM (MBI_EXEC | MBI_WRITE | MBI_READ | MBI_ADMIN | \
MBI_STAT | MBI_APPEND)
struct mac_bsdextended_identity {
int mbi_flags;
uid_t mbi_uid;
gid_t mbi_gid;
#define MBS_UID_DEFINED 0x00000001 /* uid field should be matched */
#define MBS_GID_DEFINED 0x00000002 /* gid field should be matched */
#define MBS_PRISON_DEFINED 0x00000004 /* prison field should be matched */
#define MBS_ALL_FLAGS (MBS_UID_DEFINED | MBS_GID_DEFINED | MBS_PRISON_DEFINED)
struct mac_bsdextended_subject {
int mbs_flags;
int mbs_neg;
uid_t mbs_uid_min;
uid_t mbs_uid_max;
gid_t mbs_gid_min;
gid_t mbs_gid_max;
int mbs_prison;
};
#define MBO_UID_DEFINED 0x00000001 /* uid field should be matched */
#define MBO_GID_DEFINED 0x00000002 /* gid field should be matched */
#define MBO_FSID_DEFINED 0x00000004 /* fsid field should be matched */
#define MBO_SUID 0x00000008 /* object must be suid */
#define MBO_SGID 0x00000010 /* object must be sgid */
#define MBO_UID_SUBJECT 0x00000020 /* uid must match subject */
#define MBO_GID_SUBJECT 0x00000040 /* gid must match subject */
#define MBO_TYPE_DEFINED 0x00000080 /* object type should be matched */
#define MBO_ALL_FLAGS (MBO_UID_DEFINED | MBO_GID_DEFINED | MBO_FSID_DEFINED | \
MBO_SUID | MBO_SGID | MBO_UID_SUBJECT | MBO_GID_SUBJECT | \
MBO_TYPE_DEFINED)
#define MBO_TYPE_REG 0x00000001
#define MBO_TYPE_DIR 0x00000002
#define MBO_TYPE_BLK 0x00000004
#define MBO_TYPE_CHR 0x00000008
#define MBO_TYPE_LNK 0x00000010
#define MBO_TYPE_SOCK 0x00000020
#define MBO_TYPE_FIFO 0x00000040
#define MBO_ALL_TYPE (MBO_TYPE_REG | MBO_TYPE_DIR | MBO_TYPE_BLK | \
MBO_TYPE_CHR | MBO_TYPE_LNK | MBO_TYPE_SOCK | MBO_TYPE_FIFO)
struct mac_bsdextended_object {
int mbo_flags;
int mbo_neg;
uid_t mbo_uid_min;
uid_t mbo_uid_max;
gid_t mbo_gid_min;
gid_t mbo_gid_max;
struct fsid mbo_fsid;
int mbo_type;
};
struct mac_bsdextended_rule {
struct mac_bsdextended_identity mbr_subject;
struct mac_bsdextended_identity mbr_object;
struct mac_bsdextended_subject mbr_subject;
struct mac_bsdextended_object mbr_object;
mode_t mbr_mode; /* maximum access */
};

View file

@ -0,0 +1,167 @@
#!/bin/sh
#
# $FreeBSD$
#
uidrange="60000:100000"
gidrange="60000:100000"
uidinrange="nobody"
uidoutrange="daemon"
gidinrange="nobody" # We expect $uidinrange in this group
gidoutrange="daemon" # We expect $uidinrange in this group
playground="/stuff/nobody/" # Must not be on root fs
#
# Setup
#
rm -f $playground/test*
ugidfw remove 1
file1=$playground/test-$uidinrange
file2=$playground/test-$uidoutrange
cat <<EOF> $playground/test-script.pl
if (open(F, ">" . shift)) { exit 0; } else { exit 1; }
EOF
command1="perl $playground/test-script.pl $file1"
command2="perl $playground/test-script.pl $file2"
echo -n "$uidinrange file: "
su -m $uidinrange -c "$command1 && echo good"
chown "$uidinrange":"$gidinrange" $file1
chmod a+w $file1
echo -n "$uidoutrange file: "
$command2 && echo good
chown "$uidoutrange":"$gidoutrange" $file2
chmod a+w $file2
#
# No rules
#
echo -n "no rules $uidinrange: "
su -fm $uidinrange -c "$command1 && echo good"
echo -n "no rules $uidoutrange: "
su -fm $uidoutrange -c "$command1 && echo good"
#
# Subject Match on uid
#
ugidfw set 1 subject uid $uidrange object mode rasx
echo -n "subject uid in range: "
su -fm $uidinrange -c "$command1 || echo good"
echo -n "subject uid out range: "
su -fm $uidoutrange -c "$command1 && echo good"
#
# Subject Match on gid
#
ugidfw set 1 subject gid $gidrange object mode rasx
echo -n "subject gid in range: "
su -fm $uidinrange -c "$command1 || echo good"
echo -n "subject gid out range: "
su -fm $uidoutrange -c "$command1 && echo good"
#
# Subject Match on jail
#
echo -n "subject matching jailid: "
rm -f $playground/test-jail
jailid=`jail -i / localhost 127.0.0.1 /usr/sbin/daemon -f /bin/sh -c "(sleep 3; touch $playground/test-jail) &"`
ugidfw set 1 subject jailid $jailid object mode rasx
sleep 6
if [ ! -f $playground/test-jail ] ; then echo good ; fi
echo -n "subject nonmatching jailid: "
rm -f $playground/test-jail
jailid=`jail -i / localhost 127.0.0.1 /usr/sbin/daemon -f /bin/sh -c "(sleep 3; touch $playground/test-jail) &"`
sleep 6
if [ -f $playground/test-jail ] ; then echo good ; fi
#
# Object uid
#
ugidfw set 1 subject object uid $uidrange mode rasx
echo -n "object uid in range: "
su -fm $uidinrange -c "$command1 || echo good"
echo -n "object uid out range: "
su -fm $uidinrange -c "$command2 && echo good"
ugidfw set 1 subject object uid $uidrange mode rasx
echo -n "object uid in range (differennt subject): "
su -fm $uidoutrange -c "$command1 || echo good"
echo -n "object uid out range (differennt subject): "
su -fm $uidoutrange -c "$command2 && echo good"
#
# Object gid
#
ugidfw set 1 subject object gid $uidrange mode rasx
echo -n "object gid in range: "
su -fm $uidinrange -c "$command1 || echo good"
echo -n "object gid out range: "
su -fm $uidinrange -c "$command2 && echo good"
echo -n "object gid in range (differennt subject): "
su -fm $uidoutrange -c "$command1 || echo good"
echo -n "object gid out range (differennt subject): "
su -fm $uidoutrange -c "$command2 && echo good"
#
# Object filesys
#
ugidfw set 1 subject uid $uidrange object filesys / mode rasx
echo -n "object out of filesys: "
su -fm $uidinrange -c "$command1 && echo good"
ugidfw set 1 subject uid $uidrange object filesys $playground mode rasx
echo -n "object in filesys: "
su -fm $uidinrange -c "$command1 || echo good"
#
# Object suid
#
ugidfw set 1 subject uid $uidrange object suid mode rasx
echo -n "object notsuid: "
su -fm $uidinrange -c "$command1 && echo good"
chmod u+s $file1
echo -n "object suid: "
su -fm $uidinrange -c "$command1 || echo good"
chmod u-s $file1
#
# Object sgid
#
ugidfw set 1 subject uid $uidrange object sgid mode rasx
echo -n "object notsgid: "
su -fm $uidinrange -c "$command1 && echo good"
chmod g+s $file1
echo -n "object sgid: "
su -fm $uidinrange -c "$command1 || echo good"
chmod g-s $file1
#
# Object uid matches subject
#
ugidfw set 1 subject uid $uidrange object uid_of_subject mode rasx
echo -n "object uid notmatches subject: "
su -fm $uidinrange -c "$command2 && echo good"
echo -n "object uid matches subject: "
su -fm $uidinrange -c "$command1 || echo good"
#
# Object gid matches subject
#
ugidfw set 1 subject uid $uidrange object gid_of_subject mode rasx
echo -n "object gid notmatches subject: "
su -fm $uidinrange -c "$command2 && echo good"
echo -n "object gid matches subject: "
su -fm $uidinrange -c "$command1 || echo good"
#
# Object type
#
ugidfw set 1 subject uid $uidrange object type dbclsp mode rasx
echo -n "object not type: "
su -fm $uidinrange -c "$command1 && echo good"
ugidfw set 1 subject uid $uidrange object type r mode rasx
echo -n "object type: "
su -fm $uidinrange -c "$command1 || echo good"

View file

@ -26,8 +26,9 @@
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/mac.h>
#include <sys/mount.h>
#include <security/mac_bsdextended/mac_bsdextended.h>
@ -104,6 +105,47 @@ static const char *test_strings[] = {
"subject not uid operator object uid bin mode n",
"subject uid bin object not uid operator mode n",
"subject not uid daemon object not uid operator mode n",
/* Ranges */
"subject uid root:operator object gid wheel:bin mode n",
/* Jail ID */
"subject jailid 1 object uid root mode n",
/* Filesys */
"subject uid root object filesys / mode n",
"subject uid root object filesys /dev mode n",
/* S/UGID */
"subject not uid root object sgid mode n",
"subject not uid root object sgid mode n",
/* Matching uid/gid */
"subject not uid root:operator object not uid_of_subject mode n",
"subject not gid wheel:bin object not gid_of_subject mode n",
/* Object types */
"subject uid root object type a mode a",
"subject uid root object type r mode a",
"subject uid root object type d mode a",
"subject uid root object type b mode a",
"subject uid root object type c mode a",
"subject uid root object type l mode a",
"subject uid root object type s mode a",
"subject uid root object type rbc mode a",
"subject uid root object type dls mode a",
/* Empty rules always match */
"subject object mode a",
/* Partial negations */
"subject ! uid root object mode n",
"subject ! gid wheel object mode n",
"subject ! jailid 2 object mode n",
"subject object ! uid root mode n",
"subject object ! gid wheel mode n",
"subject object ! filesys / mode n",
"subject object ! suid mode n",
"subject object ! sgid mode n",
"subject object ! uid_of_subject mode n",
"subject object ! gid_of_subject mode n",
"subject object ! type d mode n",
/* All out nonsense */
"subject uid root ! gid wheel:bin ! jailid 1 "
"object ! uid root:daemon gid daemon filesys / suid sgid uid_of_subject gid_of_subject ! type r "
"mode rsx",
};
static const int test_strings_len = sizeof(test_strings) / sizeof(char *);
@ -111,8 +153,8 @@ static void
test_libugidfw_strings(void)
{
struct mac_bsdextended_rule rule;
char errorstr[128];
char rulestr[128];
char errorstr[256];
char rulestr[256];
int i, error;
for (i = 0; i < test_users_len; i++) {
@ -129,11 +171,11 @@ test_libugidfw_strings(void)
for (i = 0; i < test_strings_len; i++) {
error = bsde_parse_rule_string(test_strings[i], &rule,
128, errorstr);
sizeof(errorstr), errorstr);
if (error == -1)
errx(-1, "bsde_parse_rule_string: '%s' (%d): %s",
test_strings[i], i, errorstr);
error = bsde_rule_to_string(&rule, rulestr, 128);
error = bsde_rule_to_string(&rule, rulestr, sizeof(rulestr));
if (error < 0)
errx(-1, "bsde_rule_to_string: rule for '%s' "
"returned %d", test_strings[i], error);
@ -147,7 +189,7 @@ test_libugidfw_strings(void)
int
main(int argc, char *argv[])
{
char errorstr[128];
char errorstr[256];
int count, slots;
if (argc != 1)
@ -182,13 +224,13 @@ main(int argc, char *argv[])
* starting, but "slots" is a property of prior runs and so we ignore
* the return value.
*/
count = bsde_get_rule_count(128, errorstr);
count = bsde_get_rule_count(sizeof(errorstr), errorstr);
if (count == -1)
errx(-1, "bsde_get_rule_count: %s", errorstr);
if (count != 0)
errx(-1, "bsde_get_rule_count: %d rules", count);
slots = bsde_get_rule_slots(128, errorstr);
slots = bsde_get_rule_slots(sizeof(errorstr), errorstr);
if (slots == -1)
errx(-1, "bsde_get_rule_slots: %s", errorstr);

View file

@ -41,12 +41,52 @@
.Cm add
.Cm subject
.Op Cm not
.Op Cm uid Ar uid
.Op Cm gid Ar gid
.Oo
.Op Cm \&!
.Cm uid Ar uid | minuid:maxuid
.Oc
.Oo
.Op Cm \&!
.Cm gid Ar gid | mingid:maxgid
.Oc
.Oo
.Op Cm \&!
.Cm jailid Ad jailid
.Oc
.Cm object
.Op Cm not
.Op Cm uid Ar uid
.Op Cm gid Ar gid
.Oo
.Op Cm \&!
.Cm uid Ar uid | minuid:maxuid
.Oc
.Oo
.Op Cm \&!
.Cm gid Ar gid | mingid:maxgid
.Oc
.Oo
.Op Cm \&!
.Cm filesys Ad path
.Oc
.Oo
.Op Cm \&!
.Cm suid
.Oc
.Oo
.Op Cm \&!
.Cm sgid
.Oc
.Oo
.Op Cm \&!
.Cm uid_of_subject
.Oc
.Oo
.Op Cm \&!
.Cm gid_of_subject
.Oc
.Oo
.Op Cm \&!
.Cm type Ar ardbclsp
.Oc
.Cm mode
.Ar arswxn
.Nm
@ -56,12 +96,52 @@
.Ar rulenum
.Cm subject
.Op Cm not
.Op Cm uid Ar uid
.Op Cm gid Ar gid
.Oo
.Op Cm \&!
.Cm uid Ar uid | minuid:maxuid
.Oc
.Oo
.Op Cm \&!
.Cm gid Ar gid | mingid:maxgid
.Oc
.Oo
.Op Cm \&!
.Cm jailid Ad jailid
.Oc
.Cm object
.Op Cm not
.Op Cm uid Ar uid
.Op Cm gid Ar gid
.Oo
.Op Cm \&!
.Cm uid Ar uid | minuid:maxuid
.Oc
.Oo
.Op Cm \&!
.Cm gid Ar gid | mingid:maxgid
.Oc
.Oo
.Op Cm \&!
.Cm filesys Ad path
.Oc
.Oo
.Op Cm \&!
.Cm suid
.Oc
.Oo
.Op Cm \&!
.Cm sgid
.Oc
.Oo
.Op Cm \&!
.Cm uid_of_subject
.Oc
.Oo
.Op Cm \&!
.Cm gid_of_subject
.Oc
.Oo
.Op Cm \&!
.Cm type Ar ardbclsp
.Oc
.Cm mode
.Ar arswxn
.Nm
@ -80,20 +160,12 @@ policy.
.Pp
The arguments are as follows:
.Bl -tag -width indent -offset indent
.It Cm add
Add a new
.Nm
rule.
.It Xo
.Cm add
.Cm subject
.Op Cm not
.Op Cm uid Ar uid
.Op Cm gid Ar gid
.Ar ...
.Cm object
.Op Cm not
.Op Cm uid Ar uid
.Op Cm gid Ar gid
.Ar ...
.Cm mode
.Ar arswxn
.Xc
@ -108,13 +180,9 @@ rules in the system.
.It Xo
.Cm set Ar rulenum
.Cm subject
.Op Cm not
.Op Cm uid Ar uid
.Op Cm gid Ar gid
.Ar ...
.Cm object
.Op Cm not
.Op Cm uid Ar uid
.Op Cm gid Ar gid
.Ar ...
.Cm mode
.Ar arswxn
.Xc
@ -131,37 +199,120 @@ will yield a slight performance increase.
.It Xo
.Cm subject
.Op Cm not
.Op Cm uid Ar uid
.Op Cm gid Ar gid
.Oo
.Op Cm \&!
.Cm uid Ar uid | minuid:maxuid
.Oc
.Oo
.Op Cm \&!
.Cm gid Ar gid | mingid:maxgid
.Oc
.Oo
.Op Cm \&!
.Cm jailid Ad jailid
.Oc
.Xc
Subjects performing an operation must match
(or, if
Subjects performing an operation must match all the conditions given.
A leading
.Cm not
is specified, must
.Em not
match)
the user and group specified by
means that the subject should not match the remainder of the specification.
A condition may be prefixed by
.Cm \&!
to indicate that particular condition must not match the subject.
The subject can be required to have a particular
.Ar uid
and/or
.Ar gid
for the rule to be applied.
.Ar gid .
A range of uids/gids can be specified,
seperated by a colon.
The subject can be required to be in a particular jail with the
.Ar jailid .
.It Xo
.Cm object
.Op Cm not
.Op Cm uid Ar uid
.Op Cm gid Ar gid
.Oo
.Op Cm \&!
.Cm uid Ar uid | minuid:maxuid
.Oc
.Oo
.Op Cm \&!
.Cm gid Ar gid | mingid:maxgid
.Oc
.Oo
.Op Cm \&!
.Cm filesys Ad path
.Oc
.Oo
.Op Cm \&!
.Cm suid
.Oc
.Oo
.Op Cm \&!
.Cm sgid
.Oc
.Oo
.Op Cm \&!
.Cm uid_of_subject
.Oc
.Oo
.Op Cm \&!
.Cm gid_of_subject
.Oc
.Oo
.Op Cm \&!
.Cm type Ar ardbclsp
.Oc
.Xc
Objects must be owned by
(or, if
The rule will apply only to objects matching all the specified conditions.
A leading
.Cm not
is specified, must
.Em not
be owned by)
the user and/or group specified by
means that the object should not match all the remaining conditions.
A condition may be prefixed by
.Cm \&!
to indicate that particular condition must not match the object.
Objects can be required to be owned by the user and/or group specified by
.Ar uid
and/or
.Ar gid
for the rule to be applied.
.Ar gid .
A range of uids/gids can be specified, seperated by a colon.
The object can be required to be in a particular filesystem by
specifing the filesystem using
.Cm filesys .
Note,
if the filesystem is unmounted and remounted,
then the rule may need to be reapplied to ensure the correct filesystem
id is used.
The object can be required to have the
.Cm suid
or
.Cm sgid
bits set.
The owner of the object can be required to match the
.Cm uid_of_subject
or the
.Cm gid_of_subject
attempting the operation.
The type of the object can be restricted to a subset of
the following types.
.Pp
.Bl -tag -width ".Cm w" -compact -offset indent
.It Cm a
any file type
.It Cm r
a regular file
.It Cm d
a directory
.It Cm b
a block special device
.It Cm c
a character special device
.It Cm l
a symbolic link
.It Cm s
a unix domain socket
.It Cm p
a named pipe (FIFO)
.El
.It Cm mode Ar arswxn
Similar to
.Xr chmod 1 ,

View file

@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/mount.h>
#include <sys/time.h>
#include <sys/sysctl.h>