From owner-p4-projects Tue Oct 15 15: 3:34 2002 Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id BB89B37B401; Tue, 15 Oct 2002 15:03:18 -0700 (PDT) Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 4D99537B404 for ; Tue, 15 Oct 2002 15:03:18 -0700 (PDT) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 938CA43E65 for ; Tue, 15 Oct 2002 15:03:16 -0700 (PDT) (envelope-from green@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.12.6/8.12.6) with ESMTP id g9FM3GMt012890 for ; Tue, 15 Oct 2002 15:03:16 -0700 (PDT) (envelope-from green@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.12.6/8.12.3/Submit) id g9FM3Fu1012887 for perforce@freebsd.org; Tue, 15 Oct 2002 15:03:15 -0700 (PDT) Date: Tue, 15 Oct 2002 15:03:15 -0700 (PDT) Message-Id: <200210152203.g9FM3Fu1012887@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to green@freebsd.org using -f From: Brian Feldman Subject: PERFORCE change 19355 for review To: Perforce Change Reviews Sender: owner-p4-projects@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG http://perforce.freebsd.org/chv.cgi?CH=19355 Change 19355 by green@green_laptop_2 on 2002/10/15 15:02:50 Submit basic framework changes necessary to be able to transition correctly on a shell script. Affected files ... .. //depot/projects/trustedbsd/mac/sys/kern/kern_exec.c#36 edit .. //depot/projects/trustedbsd/mac/sys/kern/kern_mac.c#310 edit .. //depot/projects/trustedbsd/mac/sys/security/mac_biba/mac_biba.c#132 edit .. //depot/projects/trustedbsd/mac/sys/security/mac_lomac/kernel_plm.c#3 edit .. //depot/projects/trustedbsd/mac/sys/security/mac_lomac/kernel_plm.h#3 edit .. //depot/projects/trustedbsd/mac/sys/security/mac_lomac/mac_lomac.c#7 edit .. //depot/projects/trustedbsd/mac/sys/security/mac_lomac/mac_lomac.h#3 edit .. //depot/projects/trustedbsd/mac/sys/security/mac_lomac/policy_plm.h#3 edit .. //depot/projects/trustedbsd/mac/sys/security/mac_mls/mac_mls.c#112 edit .. //depot/projects/trustedbsd/mac/sys/security/mac_none/mac_none.c#83 edit .. //depot/projects/trustedbsd/mac/sys/security/mac_te/mac_te.c#85 edit .. //depot/projects/trustedbsd/mac/sys/security/mac_test/mac_test.c#56 edit .. //depot/projects/trustedbsd/mac/sys/security/sebsd/sebsd.c#40 edit .. //depot/projects/trustedbsd/mac/sys/sys/imgact.h#10 edit .. //depot/projects/trustedbsd/mac/sys/sys/mac.h#178 edit .. //depot/projects/trustedbsd/mac/sys/sys/mac_policy.h#139 edit Differences ... ==== //depot/projects/trustedbsd/mac/sys/kern/kern_exec.c#36 (text+ko) ==== @@ -216,6 +216,7 @@ imgp->interpreter_name[0] = '\0'; imgp->auxargs = NULL; imgp->vp = NULL; + imgp->interpvp = NULL; imgp->object = NULL; imgp->firstpage = NULL; imgp->ps_strings = 0; @@ -330,13 +331,14 @@ imgp->vp->v_vflag &= ~VV_TEXT; /* free name buffer and old vnode */ NDFREE(ndp, NDF_ONLY_PNBUF); - vput(ndp->ni_vp); + VOP_UNLOCK(ndp->ni_vp, 0, td); vm_object_deallocate(imgp->object); imgp->object = NULL; vrele(ndp->ni_dvp); /* set new name to that of the interpreter */ NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME | SAVESTART, UIO_SYSSPACE, imgp->interpreter_name, td); + imgp->interpvp = imgp->vp; goto interpret; } @@ -451,7 +453,12 @@ attr.va_gid; #ifdef MAC - will_transition = mac_execve_will_transition(oldcred, imgp->vp); + if (imgp->interpvp != NULL) /* XXX Could this ever deadlock? */ + vn_lock(imgp->interpvp, LK_EXCLUSIVE | LK_RETRY, td); + will_transition = mac_execve_will_transition(oldcred, imgp->vp, + imgp->interpvp); + if (imgp->interpvp != NULL) + VOP_UNLOCK(imgp->interpvp, 0, td); credential_changing |= will_transition; #endif @@ -498,7 +505,13 @@ change_egid(newcred, attr.va_gid); #ifdef MAC if (will_transition) { - mac_execve_transition(oldcred, newcred, imgp->vp); + if (imgp->interpvp != NULL) + vn_lock(imgp->interpvp, LK_EXCLUSIVE | + LK_RETRY, td); + mac_execve_transition(oldcred, newcred, imgp->vp, + imgp->interpvp); + if (imgp->interpvp != NULL) + VOP_UNLOCK(imgp->interpvp, 0, td); } #endif /* @@ -630,6 +643,8 @@ vput(imgp->vp); vrele(ndp->ni_dvp); } + if (imgp->interpvp != NULL) + vrele(imgp->interpvp); if (imgp->object) vm_object_deallocate(imgp->object); ==== //depot/projects/trustedbsd/mac/sys/kern/kern_mac.c#310 (text+ko) ==== @@ -2057,7 +2057,8 @@ } void -mac_execve_transition(struct ucred *old, struct ucred *new, struct vnode *vp) +mac_execve_transition(struct ucred *old, struct ucred *new, struct vnode *vp, + struct vnode *shellvp) { int error; @@ -2069,21 +2070,31 @@ error); printf("mac_execve_transition: using old vnode label\n"); } + if (shellvp != NULL) + (void)vn_refreshlabel(shellvp, old); - MAC_PERFORM(execve_transition, old, new, vp, &vp->v_label); + MAC_PERFORM(execve_transition, old, new, vp, &vp->v_label, shellvp, + shellvp != NULL ? &shellvp->v_label : NULL); } int -mac_execve_will_transition(struct ucred *old, struct vnode *vp) +mac_execve_will_transition(struct ucred *old, struct vnode *vp, + struct vnode *shellvp) { int error, result; error = vn_refreshlabel(vp, old); if (error) return (error); + if (shellvp != NULL) { + error = vn_refreshlabel(shellvp, old); + if (error) + return (error); + } result = 0; - MAC_BOOLEAN(execve_will_transition, ||, old, vp, &vp->v_label); + MAC_BOOLEAN(execve_will_transition, ||, old, vp, &vp->v_label, + shellvp, shellvp != NULL ? &shellvp->v_label : NULL); return (result); } ==== //depot/projects/trustedbsd/mac/sys/security/mac_biba/mac_biba.c#132 (text+ko) ==== @@ -1236,7 +1236,8 @@ static void mac_biba_execve_transition(struct ucred *old, struct ucred *new, - struct vnode *vp, struct mac *vnodelabel) + struct vnode *vp, struct mac *vnodelabel, struct vnode *shellvp, + struct mac *shellvnodelabel) { struct mac_biba *source, *dest; @@ -1249,7 +1250,8 @@ static int mac_biba_execve_will_transition(struct ucred *old, struct vnode *vp, - struct mac *vnodelabel) + struct mac *vnodelabel, struct vnode *shellvp, + struct vnode *shellvnodelabel) { return (0); ==== //depot/projects/trustedbsd/mac/sys/security/mac_lomac/kernel_plm.c#3 (text+ko) ==== @@ -43,11 +43,11 @@ #include #include #include +#include -#include "kernel_interface.h" -#include "kernel_plm.h" -#include "lomacfs.h" -#include "policy_plm.h" +#include +#include +#include MALLOC_DEFINE(M_LOMACPLM, "LOMAC_PLM", "LOMAC PLM nodes and strings"); char *strsep(register char **stringp, register const char *delim); @@ -227,7 +227,7 @@ return (sl->string); } -static int +int lomac_plm_initialize(void) { struct lomac_node_entry *plne, *lne; plm_rule_t *pr; ==== //depot/projects/trustedbsd/mac/sys/security/mac_lomac/kernel_plm.h#3 (text+ko) ==== @@ -72,7 +72,8 @@ struct lomac_node_entry *ln_entry; }; -void lomac_plm_init_lomacfs_vnode(struct vnode *dvp, struct vnode *vp, - struct componentname *cnp, lattr_t *subjlattr); +void lomac_plm_init_lomacfs_vnode(struct vnode *dvp, struct lomac_node *dln, + struct vnode *vp, struct lomac_node *ln, struct componentname *cnp); +int lomac_plm_initialize(void); #endif /* KERNEL_PLM_H */ ==== //depot/projects/trustedbsd/mac/sys/security/mac_lomac/mac_lomac.c#7 (text+ko) ==== @@ -75,6 +75,7 @@ #include #include +#include SYSCTL_DECL(_security_mac); @@ -111,6 +112,8 @@ #define SLOT(l) ((struct mac_biba *)LABEL_TO_SLOT((l), mac_lomac_slot).l_ptr) #define PSLOT(l) ((struct mac_biba_proc *) \ LABEL_TO_SLOT((l), mac_lomac_slot).l_ptr) +#define VSLOT(l) ((struct lomac_node *) LABEL_TO_SLOT((l), \ + mac_lomac_slot).l_ptr) struct mac_biba_proc { struct mac_biba mac_biba; @@ -212,9 +215,9 @@ mac_biba_single_in_range(struct mac_biba *single, struct mac_biba *range) { - KASSERT((single->mb_flag & MAC_BIBA_FLAG_SINGLE) != 0, + KASSERT((single->mb_flags & MAC_BIBA_FLAG_SINGLE) != 0, ("mac_biba_single_in_range: a not single")); - KASSERT((range->mb_flag & MAC_BIBA_FLAG_RANGE) != 0, + KASSERT((range->mb_flags & MAC_BIBA_FLAG_RANGE) != 0, ("mac_biba_single_in_range: b not range")); return (mac_biba_dominate_element(&range->mb_rangehigh, @@ -301,8 +304,8 @@ mac_biba_subject_equal_ok(struct mac_biba *mac_biba) { - KASSERT((mac_biba->mb_flags & MAC_BIBA_FLAGS_BOTH == - MAC_BIBA_FLAGS_BOTH), + KASSERT((mac_biba->mb_flags & MAC_BIBA_FLAGS_BOTH) == + MAC_BIBA_FLAGS_BOTH, ("mac_biba_subject_equal_ok: subject doesn't have both labels")); /* If the single is EQUAL, it's ok */ @@ -401,7 +404,7 @@ mac_biba->mb_flags |= MAC_BIBA_FLAG_RANGE; } -static void +void mac_biba_set_single(struct mac_biba *mac_biba, u_short type, u_short grade) { @@ -445,7 +448,7 @@ labelto->mb_flags |= MAC_BIBA_FLAG_RANGE; } -static void +void mac_biba_copy(struct mac_biba *source, struct mac_biba *dest) { @@ -468,6 +471,11 @@ mac_biba_init(struct mac_policy_conf *conf) { + /* + * XXX This can fail, resulting in all files in the system + * being high integrity. + */ + (void)lomac_plm_initialize(); } static void @@ -489,6 +497,11 @@ mac_biba_copy_single(objlabel, &subj->mac_biba); mac_biba_copy_single_to_range(objlabel, &subj->mac_biba); subj->mac_biba.mb_flags |= MAC_BIBA_FLAG_UPDATESUBJ; + mtx_lock_spin(&sched_lock); + curthread->td_kse->ke_flags |= KEF_ASTPENDING; + curthread->td_proc->p_sflag |= PS_MACPEND; + mtx_unlock_spin(&sched_lock); + mac_set_ast_pending(); out: mtx_unlock(&subj->mtx); } @@ -588,7 +601,8 @@ mac_biba_init_vnode(struct vnode *vp, struct label *label) { - SLOT(label) = biba_alloc(M_WAITOK); + VSLOT(label) = malloc(sizeof(struct lomac_node), M_MACLOMAC, + M_ZERO | M_WAITOK); } static void @@ -775,15 +789,13 @@ } static void -mac_biba_create_vnode(struct ucred *cred, struct vnode *parent, - struct label *parentlabel, struct vnode *child, struct label *childlabel) +mac_lomac_create_vnode(struct ucred *cred, struct vnode *parent, + struct label *parentlabel, struct vnode *child, struct label *childlabel, + struct componentname *cnp) { - struct mac_biba *source, *dest; - source = SLOT(&cred->cr_label); - dest = SLOT(childlabel); - - mac_biba_copy_single(source, dest); + lomac_plm_init_lomacfs_vnode(parent, VSLOT(parentlabel), child, + VSLOT(childlabel), cnp); } static void @@ -2385,8 +2397,10 @@ (macop_t)mac_biba_create_devfs_directory }, { MAC_CREATE_DEVFS_VNODE, (macop_t)mac_biba_create_devfs_vnode }, - { MAC_CREATE_VNODE, - (macop_t)mac_biba_create_vnode }, + { MAC_CREATE_NEW_VNODE, + (macop_t)mac_lomac_create_vnode }, + { MAC_CREATE_OLD_VNODE, + (macop_t)mac_lomac_create_vnode }, { MAC_CREATE_MOUNT, (macop_t)mac_biba_create_mount }, { MAC_CREATE_ROOT_MOUNT, ==== //depot/projects/trustedbsd/mac/sys/security/mac_lomac/mac_lomac.h#3 (text+ko) ==== @@ -34,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/security/mac_biba/mac_biba.h,v 1.1 2002/07/31 18:07:43 rwatson Exp $ + * $FreeBSD: src/sys/security/mac_lomac/mac_lomac.h,v 1.1 2002/07/31 18:07:43 rwatson Exp $ */ /* * Definitions for the TrustedBSD Lomac floating-label integrity policy module. @@ -43,20 +43,46 @@ #define _SYS_SECURITY_MAC_LOMAC_H #define MAC_LOMAC_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM -#define MAC_LOMAC_EXTATTR_NAME "mac_biba" +#define MAC_LOMAC_EXTATTR_NAME "mac_lomac" + +struct mac_lomac_element { + u_short mle_type; + u_short mle_grade; +}; + +struct mac_lomac { + int ml_flags; + struct mac_lomac_element ml_single; + struct mac_lomac_element ml_rangelow, ml_rangehigh; +}; + +/* + * This represents both the on-disk representation of a LOMAC label + * and the internal representation. + */ + +struct mac_lomac_label { + struct mac_lomac mll_self; /* integrity of this object */ + struct mac_lomac mll_children; /* default for this object's children */ +}; -#define MAC_BIBA_FLAG_SINGLE 0x00000001 /* mb_single initialized */ -#define MAC_BIBA_FLAG_RANGE 0x00000002 /* mb_range* initialized */ -#define MAC_BIBA_FLAGS_BOTH (MAC_BIBA_FLAG_SINGLE | MAC_BIBA_FLAG_RANGE) -#define MAC_BIBA_FLAG_UPDATESUBJ 0x00000003 /* update subject label from proc */ +#define MAC_LOMAC_FLAG_SINGLE 0x00000001 /* ml_single initialized */ +#define MAC_LOMAC_FLAG_RANGE 0x00000002 /* ml_range* initialized */ +#define MAC_LOMAC_FLAGS_BOTH (MAC_LOMAC_FLAG_SINGLE | MAC_LOMAC_FLAG_RANGE) +#define MAC_LOMAC_FLAG_UPDATESUBJ 0x00000003 /* update subject label from proc */ -#define MAC_BIBA_TYPE_UNDEF 0 /* Undefined */ -#define MAC_BIBA_TYPE_GRADE 1 /* Hierarchal grade with mb_grade. */ -#define MAC_BIBA_TYPE_LOW 2 /* Dominated by any - * MAC_BIBA_TYPE_LABEL. */ -#define MAC_BIBA_TYPE_HIGH 3 /* Dominates any - * MAC_BIBA_TYPE_LABEL. */ -#define MAC_BIBA_TYPE_EQUAL 4 /* Equivilent to any - * MAC_BIBA_TYPE_LABEL. */ +#define MAC_LOMAC_TYPE_UNDEF 0 /* Undefined */ +#define MAC_LOMAC_TYPE_GRADE 1 /* Hierarchal grade with ml_grade. */ +#define MAC_LOMAC_TYPE_LOW 2 /* Dominated by any + * MAC_LOMAC_TYPE_LABEL. */ +#define MAC_LOMAC_TYPE_HIGH 3 /* Dominates any + * MAC_LOMAC_TYPE_LABEL. */ +#define MAC_LOMAC_TYPE_EQUAL 4 /* Equivilent to any + * MAC_LOMAC_TYPE_LABEL. */ +#ifdef _KERNEL +void mac_lomac_copy(struct mac_lomac *source, struct mac_lomac *dest); +void mac_lomac_set_single(struct mac_lomac *mac_lomac, u_short type, + u_short grade); +#endif /* _KERNEL */ #endif /* !_SYS_SECURITY_MAC_LOMAC_H */ ==== //depot/projects/trustedbsd/mac/sys/security/mac_lomac/policy_plm.h#3 (text+ko) ==== @@ -45,10 +45,10 @@ PLM_NOFLAGS, /* rule applies to this node and its children */ PLM_CHILDOF /* rule applies to node's children, not the node */ }; -#define LOWWRITE LN_ATTR_LOWWRITE -#define LOWNOOPEN LN_ATTR_LOWNOOPEN -#define NONETDEMOTE LN_ATTR_NONETDEMOTE -#define NODEMOTE LN_ATTR_NODEMOTE +#define LOWWRITE 0x01 +#define LOWNOOPEN 0x02 +#define NONETDEMOTE 0x04 +#define NODEMOTE 0x08 typedef struct plm_rule { /* struct mac_biba_element ... */ ==== //depot/projects/trustedbsd/mac/sys/security/mac_mls/mac_mls.c#112 (text+ko) ==== @@ -1278,7 +1278,8 @@ static void mac_mls_execve_transition(struct ucred *old, struct ucred *new, - struct vnode *vp, struct mac *vnodelabel) + struct vnode *vp, struct mac *vnodelabel, struct vnode *shellvp, + struct vnode *shellvnodelabel) { struct mac_mls *source, *dest; @@ -1291,7 +1292,8 @@ static int mac_mls_execve_will_transition(struct ucred *old, struct vnode *vp, - struct mac *vnodelabel) + struct mac *vnodelabel, struct vnode *shellvp, + struct vnode *shellvnodelabel) { return (0); ==== //depot/projects/trustedbsd/mac/sys/security/mac_none/mac_none.c#83 (text+ko) ==== @@ -415,14 +415,16 @@ static void mac_none_execve_transition(struct ucred *old, struct ucred *new, - struct vnode *vp, struct label *vnodelabel) + struct vnode *vp, struct label *vnodelabel, struct vnode *shellvp, + struct vnode *shellvnodelabel) { } static int mac_none_execve_will_transition(struct ucred *old, struct vnode *vp, - struct label *vnodelabel) + struct label *vnodelabel, struct vnode *shellvp, + struct vnode *shellvnodelabel) { return (0); ==== //depot/projects/trustedbsd/mac/sys/security/mac_te/mac_te.c#85 (text+ko) ==== @@ -1534,7 +1534,8 @@ static void mac_te_execve_transition(struct ucred *old, struct ucred *new, - struct vnode *vp, struct label *filelabel) + struct vnode *vp, struct label *filelabel, struct vp *shellvp, + struct label *shellfilelabel) { int rule; @@ -1566,7 +1567,8 @@ static int mac_te_execve_will_transition(struct ucred *old, struct vnode *vp, - struct label *filelabel) + struct label *filelabel, struct vnode *shellvp, + struct label *shellfilelabel) { int rule; ==== //depot/projects/trustedbsd/mac/sys/security/mac_test/mac_test.c#56 (text+ko) ==== @@ -794,14 +794,16 @@ static void mac_test_execve_transition(struct ucred *old, struct ucred *new, - struct vnode *vp, struct label *filelabel) + struct vnode *vp, struct label *filelabel, + struct vnode *shellvp, struct vnode *shellfilelabel) { } static int mac_test_execve_will_transition(struct ucred *old, struct vnode *vp, - struct label *filelabel) + struct label *filelabel, struct vnode *shellvp, + struct vnode *shellfilelabel) { return (0); ==== //depot/projects/trustedbsd/mac/sys/security/sebsd/sebsd.c#40 (text+ko) ==== @@ -297,7 +297,8 @@ static void sebsd_execve_transition(struct ucred *old, struct ucred *new, - struct vnode *vp, struct mac *vnodelabel) + struct vnode *vp, struct mac *vnodelabel, + struct vnode *shellvp, struct mac *shellvnodelabel) { struct task_security_struct *otask, *ntask; struct vnode_security_struct *file; @@ -305,7 +306,10 @@ otask = SLOT(&old->cr_label); ntask = SLOT(&new->cr_label); - file = SLOT(&vp->v_label); + if (shellvp != NULL) + file = SLOT(&shellvp->v_label); + else + file = SLOT(&vp->v_label); /* * Should have already checked all the permissions @@ -331,7 +335,8 @@ static int sebsd_execve_will_transition(struct ucred *old, struct vnode *vp, - struct mac *vnodelabel) + struct mac *vnodelabel, struct vnode *shellvp, + struct mac *shellvnodelabel) { struct task_security_struct *task; struct vnode_security_struct *file; @@ -339,7 +344,10 @@ int rc; task = SLOT(&old->cr_label); - file = SLOT(&vp->v_label); + if (shellvp != NULL) + file = SLOT(&shellvp->v_label); + else + file = SLOT(&vp->v_label); /* * Should have already checked all the permissions, so just see if ==== //depot/projects/trustedbsd/mac/sys/sys/imgact.h#10 (text+ko) ==== @@ -46,6 +46,7 @@ struct proc *proc; /* our process struct */ struct execve_args *uap; /* syscall arguments */ struct vnode *vp; /* pointer to vnode of file to exec */ + struct vnode *interpvp; /* vnode of the shell script, if interpreted */ struct vm_object *object; /* The vm object for this vp */ struct vattr *attr; /* attributes of file */ const char *image_header; /* head of file to exec */ ==== //depot/projects/trustedbsd/mac/sys/sys/mac.h#178 (text+ko) ==== @@ -307,8 +307,9 @@ */ void mac_create_cred(struct ucred *cred_parent, struct ucred *cred_child); void mac_execve_transition(struct ucred *old, struct ucred *new, - struct vnode *vp); -int mac_execve_will_transition(struct ucred *old, struct vnode *vp); + struct vnode *vp, struct vnode *shellvp); +int mac_execve_will_transition(struct ucred *old, struct vnode *vp, + struct vnode *shellvp); void mac_create_proc0(struct ucred *cred); void mac_create_proc1(struct ucred *cred); void mac_thread_userret(struct thread *td); ==== //depot/projects/trustedbsd/mac/sys/sys/mac_policy.h#139 (text+ko) ==== @@ -251,9 +251,11 @@ void (*mpo_create_cred)(struct ucred *parent_cred, struct ucred *child_cred); void (*mpo_execve_transition)(struct ucred *old, struct ucred *new, - struct vnode *vp, struct label *vnodelabel); + struct vnode *vp, struct label *vnodelabel, + struct vnode *shellvp, struct label *shellvnodelabel); int (*mpo_execve_will_transition)(struct ucred *old, - struct vnode *vp, struct label *vnodelabel); + struct vnode *vp, struct label *vnodelabel, + struct vnode *shellvp, struct label *shellvnodelabel); void (*mpo_create_proc0)(struct ucred *cred); void (*mpo_create_proc1)(struct ucred *cred); void (*mpo_relabel_cred)(struct ucred *cred, To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe p4-projects" in the body of the message