Page MenuHomeFreeBSD

D56166.diff
No OneTemporary

D56166.diff

diff --git a/lib/libugidfw/ugidfw.c b/lib/libugidfw/ugidfw.c
--- a/lib/libugidfw/ugidfw.c
+++ b/lib/libugidfw/ugidfw.c
@@ -342,6 +342,21 @@
left -= len;
cur += len;
}
+ if (!notdone && (rule->mbr_object.mbo_neg & MBO_GLOB_DEFINED)) {
+ len = snprintf(cur, left, "! ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_object.mbo_flags & MBO_GLOB_DEFINED) {
+ len = snprintf(cur, left, "glob '%s' ",
+ rule->mbr_object.mbo_glob);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
if (!notdone && (rule->mbr_object.mbo_neg & MBO_SUID)) {
len = snprintf(cur, left, "! ");
if (len < 0 || len > left)
@@ -797,6 +812,14 @@
return (0);
}
+static int
+bsde_parse_glob(char *spec, char *glob, size_t buflen, char *errstr)
+{
+ strncpy(glob, spec, buflen);
+
+ return (0);
+}
+
static int
bsde_parse_object(int argc, char *argv[],
struct mac_bsdextended_object *object, size_t buflen, char *errstr)
@@ -807,6 +830,7 @@
uid_t uid_min, uid_max;
gid_t gid_min, gid_max;
struct fsid fsid;
+ char glob[MBO_GLOB_MAX];
current = 0;
flags = 0;
@@ -875,6 +899,20 @@
nextnot = 0;
}
current += 2;
+ } else if (strcmp(argv[current], "glob") == 0) {
+ if (current + 2 > argc) {
+ snprintf(errstr, buflen, "glob short");
+ return (-1);
+ }
+ if (bsde_parse_glob(argv[current+1], glob,
+ MBO_GLOB_MAX, errstr) < 0)
+ return (-1);
+ flags |= MBO_GLOB_DEFINED;
+ if (nextnot) {
+ neg ^= MBO_GLOB_DEFINED;
+ nextnot = 0;
+ }
+ current += 2;
} else if (strcmp(argv[current], "suid") == 0) {
flags |= MBO_SUID;
if (nextnot) {
@@ -951,6 +989,8 @@
}
if (flags & MBO_FSID_DEFINED)
object->mbo_fsid = fsid;
+ if (flags & MBO_GLOB_DEFINED)
+ strncpy(object->mbo_glob, glob, MBO_GLOB_MAX);
if (flags & MBO_TYPE_DEFINED)
object->mbo_type = type;
diff --git a/sys/fs/tarfs/tarfs_vfsops.c b/sys/fs/tarfs/tarfs_vfsops.c
--- a/sys/fs/tarfs/tarfs_vfsops.c
+++ b/sys/fs/tarfs/tarfs_vfsops.c
@@ -991,7 +991,7 @@
/* vp is now held and locked */
/* Open the source tarball */
- error = vn_open_vnode(vp, flags, td->td_ucred, td, NULL);
+ error = vn_open_vnode(vp, flags, td->td_ucred, td, NULL, NULL);
if (error != 0) {
TARFS_DPF(FS, "%s: failed to open %s: %d\n", __func__,
from, error);
diff --git a/sys/fs/unionfs/union.h b/sys/fs/unionfs/union.h
--- a/sys/fs/unionfs/union.h
+++ b/sys/fs/unionfs/union.h
@@ -139,7 +139,8 @@
struct unionfs_node_status **);
void unionfs_tryrem_node_status(struct unionfs_node *,
struct unionfs_node_status *);
-int unionfs_check_rmdir(struct vnode *, struct ucred *, struct thread *);
+int unionfs_check_rmdir(struct vnode *, struct thread *,
+ struct componentname *cnp);
int unionfs_copyfile(struct vnode *, int, struct ucred *, struct thread *);
int unionfs_copylink(struct vnode *, struct ucred *, struct thread *);
void unionfs_create_uppervattr_core(struct unionfs_mount *, struct vattr *,
diff --git a/sys/fs/unionfs/union_subr.c b/sys/fs/unionfs/union_subr.c
--- a/sys/fs/unionfs/union_subr.c
+++ b/sys/fs/unionfs/union_subr.c
@@ -1701,7 +1701,8 @@
* locked.
*/
int
-unionfs_check_rmdir(struct vnode *vp, struct ucred *cred, struct thread *td)
+unionfs_check_rmdir(struct vnode *vp, struct thread *td,
+ struct componentname *cnp)
{
struct vnode *uvp;
struct vnode *lvp;
@@ -1745,20 +1746,21 @@
ASSERT_VOP_LOCKED(lvp, __func__);
ASSERT_VOP_ELOCKED(uvp, __func__);
- if ((error = VOP_GETATTR(uvp, &va, cred)) != 0)
+ if ((error = VOP_GETATTR(uvp, &va, cnp->cn_cred)) != 0)
return (error);
if (va.va_flags & OPAQUE)
return (0);
#ifdef MAC
- if ((error = mac_vnode_check_open(cred, lvp, VEXEC | VREAD)) != 0)
+ if ((error = mac_vnode_check_open(cnp->cn_cred, lvp, VEXEC | VREAD,
+ cnp)) != 0)
return (error);
#endif
- if ((error = VOP_ACCESS(lvp, VEXEC | VREAD, cred, td)) != 0)
+ if ((error = VOP_ACCESS(lvp, VEXEC | VREAD, cnp->cn_cred, td)) != 0)
return (error);
- if ((error = VOP_OPEN(lvp, FREAD, cred, td, NULL)) != 0)
+ if ((error = VOP_OPEN(lvp, FREAD, cnp->cn_cred, td, NULL)) != 0)
return (error);
- if ((error = VOP_GETATTR(lvp, &va, cred)) != 0)
+ if ((error = VOP_GETATTR(lvp, &va, cnp->cn_cred)) != 0)
return (error);
dirbuflen = max(DEV_BSIZE, GENERIC_MAXDIRSIZ);
@@ -1812,7 +1814,7 @@
cn.cn_nameiop = LOOKUP;
cn.cn_flags = LOCKPARENT | LOCKLEAF | RDONLY | ISLASTCN;
cn.cn_lkflags = LK_EXCLUSIVE;
- cn.cn_cred = cred;
+ cn.cn_cred = cnp->cn_cred;
error = VOP_LOOKUP(uvp, &tvp, &cn);
if (tvp != NULL)
@@ -1826,7 +1828,7 @@
error = 0;
}
- VOP_CLOSE(lvp, FREAD, cred, td);
+ VOP_CLOSE(lvp, FREAD, cnp->cn_cred, td);
free(dirbuf, M_TEMP);
return (error);
}
diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c
--- a/sys/fs/unionfs/union_vnops.c
+++ b/sys/fs/unionfs/union_vnops.c
@@ -1754,7 +1754,7 @@
vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
return (ERELOOKUP);
}
- error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td);
+ error = unionfs_check_rmdir(ap->a_vp, td, cnp);
/*
* It's possible for a direct operation on the lower FS
* to make the lower directory non-empty after we drop
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -2919,7 +2919,7 @@
goto bad;
}
#ifdef MAC
- error = mac_vnode_check_open(td->td_ucred, vp, VWRITE | VREAD);
+ error = mac_vnode_check_open(td->td_ucred, vp, VWRITE | VREAD, NULL);
if (error)
goto bad;
#endif
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -98,13 +98,13 @@
static int setutimes(struct thread *td, struct vnode *,
const struct timespec *, int, int);
static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
- struct thread *td);
+ struct thread *td, struct componentname *cnp);
static int kern_fhlinkat(struct thread *td, int fd, const char *path,
enum uio_seg pathseg, fhandle_t *fhp);
static int kern_readlink_vp(struct vnode *vp, char *buf, enum uio_seg bufseg,
size_t count, struct thread *td);
static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd,
- const char *path, enum uio_seg segflag);
+ const char *path, enum uio_seg segflag, const char *spath);
uint64_t
at2cnpflags(u_int at_flags, u_int mask)
@@ -1715,18 +1715,23 @@
return (error);
}
}
- error = kern_linkat_vp(td, nd.ni_vp, fd2, path2, segflag);
+ error = kern_linkat_vp(td, nd.ni_vp, fd2, path2, segflag,
+ path1);
} while (error == EAGAIN || error == ERELOOKUP);
return (error);
}
static int
kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, const char *path,
- enum uio_seg segflag)
+ enum uio_seg segflag, const char *spath)
{
struct nameidata nd;
struct mount *mp;
int error;
+#ifdef MAC
+ struct componentname cnp;
+ char kspath[PATH_MAX];
+#endif
if (vp->v_type == VDIR) {
vrele(vp);
@@ -1762,9 +1767,16 @@
} else if (vn_lock(vp, LK_EXCLUSIVE) == 0) {
error = can_hardlink(vp, td->td_ucred);
#ifdef MAC
- if (error == 0)
- error = mac_vnode_check_link(td->td_ucred,
- nd.ni_dvp, vp, &nd.ni_cnd);
+ if (error == 0 && spath != NULL) {
+ error = copyinstr(spath, kspath, PATH_MAX, NULL);
+ if (error == 0) {
+ cnp.cn_pnbuf = kspath;
+ cnp.cn_nameptr = cnp.cn_pnbuf;
+ cnp.cn_namelen = strlen(cnp.cn_pnbuf);
+ error = mac_vnode_check_link(td->td_ucred,
+ nd.ni_dvp, vp, &nd.ni_cnd, &cnp);
+ }
+ }
#endif
if (error != 0) {
vput(vp);
@@ -2174,7 +2186,7 @@
*/
static int
vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
- struct thread *td)
+ struct thread *td, struct componentname *cnp)
{
accmode_t accmode;
int error;
@@ -2191,7 +2203,7 @@
if (user_flags & X_OK)
accmode |= VEXEC;
#ifdef MAC
- error = mac_vnode_check_access(cred, vp, accmode);
+ error = mac_vnode_check_access(cred, vp, accmode, cnp);
if (error != 0)
return (error);
#endif
@@ -2270,7 +2282,7 @@
goto out;
vp = nd.ni_vp;
- error = vn_access(vp, amode, usecred, td);
+ error = vn_access(vp, amode, usecred, td, &nd.ni_cnd);
NDFREE_PNBUF(&nd);
vput(vp);
out:
@@ -4677,7 +4689,7 @@
if (error != 0)
return (error);
VOP_UNLOCK(vp);
- error = kern_linkat_vp(td, vp, fd, path, pathseg);
+ error = kern_linkat_vp(td, vp, fd, path, pathseg, NULL);
} while (error == EAGAIN || error == ERELOOKUP);
return (error);
}
@@ -4792,7 +4804,7 @@
#ifdef INVARIANTS
td->td_dupfd = -1;
#endif
- error = vn_open_vnode(vp, flags, td->td_ucred, td, fp);
+ error = vn_open_vnode(vp, flags, td->td_ucred, td, fp, NULL);
if (error != 0) {
KASSERT(fp->f_ops == &badfileops,
("VOP_OPEN in fhopen() set f_ops"));
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -375,7 +375,7 @@
goto bad;
}
}
- error = vn_open_vnode(vp, fmode, cred, curthread, fp);
+ error = vn_open_vnode(vp, fmode, cred, curthread, fp, ndp);
if (first_open) {
VI_LOCK(vp);
vp->v_iflag &= ~VI_FOPENING;
@@ -433,7 +433,7 @@
*/
int
vn_open_vnode(struct vnode *vp, int fmode, struct ucred *cred,
- struct thread *td, struct file *fp)
+ struct thread *td, struct file *fp, struct nameidata *nd)
{
accmode_t accmode;
int error;
@@ -471,7 +471,8 @@
#ifdef MAC
if ((fmode & O_VERIFY) != 0)
accmode |= VVERIFY;
- error = mac_vnode_check_open(cred, vp, accmode);
+ error = mac_vnode_check_open(cred, vp, accmode,
+ nd ? &nd->ni_cnd : NULL);
if (error != 0)
return (error);
diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h
--- a/sys/security/mac/mac_framework.h
+++ b/sys/security/mac/mac_framework.h
@@ -515,17 +515,17 @@
int mac_vnode_associate_extattr(struct mount *mp, struct vnode *vp);
void mac_vnode_associate_singlelabel(struct mount *mp, struct vnode *vp);
int mac_vnode_check_access_impl(struct ucred *cred, struct vnode *dvp,
- accmode_t accmode);
+ accmode_t accmode, struct componentname *cnp);
extern bool mac_vnode_check_access_fp_flag;
#define mac_vnode_check_access_enabled() __predict_false(mac_vnode_check_access_fp_flag)
static inline int
mac_vnode_check_access(struct ucred *cred, struct vnode *dvp,
- accmode_t accmode)
+ accmode_t accmode, struct componentname *cnp)
{
mac_vnode_assert_locked(dvp, "mac_vnode_check_access");
if (mac_vnode_check_access_enabled())
- return (mac_vnode_check_access_impl(cred, dvp, accmode));
+ return (mac_vnode_check_access_impl(cred, dvp, accmode, cnp));
return (0);
}
int mac_vnode_check_chdir(struct ucred *cred, struct vnode *dvp);
@@ -543,7 +543,8 @@
int mac_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
int attrnamespace, const char *name);
int mac_vnode_check_link(struct ucred *cred, struct vnode *dvp,
- struct vnode *vp, struct componentname *cnp);
+ struct vnode *vp, struct componentname *cnp,
+ struct componentname *scnp);
int mac_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
int attrnamespace);
@@ -586,7 +587,7 @@
}
int mac_vnode_check_open_impl(struct ucred *cred, struct vnode *vp,
- accmode_t accmode);
+ accmode_t accmode, struct componentname *cnp);
#ifdef MAC
extern bool mac_vnode_check_open_fp_flag;
#else
@@ -595,12 +596,12 @@
#define mac_vnode_check_open_enabled() __predict_false(mac_vnode_check_open_fp_flag)
static inline int
mac_vnode_check_open(struct ucred *cred, struct vnode *vp,
- accmode_t accmode)
+ accmode_t accmode, struct componentname *cnp)
{
mac_vnode_assert_locked(vp, "mac_vnode_check_open");
if (mac_vnode_check_open_enabled())
- return (mac_vnode_check_open_impl(cred, vp, accmode));
+ return (mac_vnode_check_open_impl(cred, vp, accmode, cnp));
return (0);
}
diff --git a/sys/security/mac/mac_policy.h b/sys/security/mac/mac_policy.h
--- a/sys/security/mac/mac_policy.h
+++ b/sys/security/mac/mac_policy.h
@@ -609,7 +609,7 @@
struct label *vplabel);
typedef int (*mpo_vnode_check_access_t)(struct ucred *cred,
struct vnode *vp, struct label *vplabel,
- accmode_t accmode);
+ accmode_t accmode, struct componentname *cnp);
typedef int (*mpo_vnode_check_chdir_t)(struct ucred *cred,
struct vnode *dvp, struct label *dvplabel);
typedef int (*mpo_vnode_check_chroot_t)(struct ucred *cred,
@@ -635,7 +635,7 @@
typedef int (*mpo_vnode_check_link_t)(struct ucred *cred,
struct vnode *dvp, struct label *dvplabel,
struct vnode *vp, struct label *vplabel,
- struct componentname *cnp);
+ struct componentname *cnp, struct componentname *scnp);
typedef int (*mpo_vnode_check_listextattr_t)(struct ucred *cred,
struct vnode *vp, struct label *vplabel,
int attrnamespace);
@@ -651,7 +651,7 @@
struct vnode *vp, struct label *vplabel, int prot);
typedef int (*mpo_vnode_check_open_t)(struct ucred *cred,
struct vnode *vp, struct label *vplabel,
- accmode_t accmode);
+ accmode_t accmode, struct componentname *cnp);
typedef int (*mpo_vnode_check_poll_t)(struct ucred *active_cred,
struct ucred *file_cred, struct vnode *vp,
struct label *vplabel);
diff --git a/sys/security/mac/mac_vfs.c b/sys/security/mac/mac_vfs.c
--- a/sys/security/mac/mac_vfs.c
+++ b/sys/security/mac/mac_vfs.c
@@ -366,18 +366,19 @@
return (result);
}
-MAC_CHECK_PROBE_DEFINE3(vnode_check_access, "struct ucred *",
- "struct vnode *", "accmode_t");
+MAC_CHECK_PROBE_DEFINE4(vnode_check_access, "struct ucred *",
+ "struct vnode *", "accmode_t", "struct componentname *");
int
-mac_vnode_check_access_impl(struct ucred *cred, struct vnode *vp, accmode_t accmode)
+mac_vnode_check_access_impl(struct ucred *cred, struct vnode *vp,
+ accmode_t accmode, struct componentname *cnp)
{
int error;
ASSERT_VOP_LOCKED(vp, "mac_vnode_check_access");
- MAC_POLICY_CHECK(vnode_check_access, cred, vp, vp->v_label, accmode);
- MAC_CHECK_PROBE3(vnode_check_access, error, cred, vp, accmode);
+ MAC_POLICY_CHECK(vnode_check_access, cred, vp, vp->v_label, accmode, cnp);
+ MAC_CHECK_PROBE4(vnode_check_access, error, cred, vp, accmode, cnp);
return (error);
}
@@ -521,12 +522,12 @@
return (error);
}
-MAC_CHECK_PROBE_DEFINE4(vnode_check_link, "struct ucred *", "struct vnode *",
- "struct vnode *", "struct componentname *");
+MAC_CHECK_PROBE_DEFINE5(vnode_check_link, "struct ucred *", "struct vnode *",
+ "struct vnode *", "struct componentname *", "struct componentname *");
int
mac_vnode_check_link(struct ucred *cred, struct vnode *dvp,
- struct vnode *vp, struct componentname *cnp)
+ struct vnode *vp, struct componentname *cnp, struct componentname *scnp)
{
int error;
@@ -534,8 +535,8 @@
ASSERT_VOP_LOCKED(vp, "mac_vnode_check_link");
MAC_POLICY_CHECK(vnode_check_link, cred, dvp, dvp->v_label, vp,
- vp->v_label, cnp);
- MAC_CHECK_PROBE4(vnode_check_link, error, cred, dvp, vp, cnp);
+ vp->v_label, cnp, scnp);
+ MAC_CHECK_PROBE5(vnode_check_link, error, cred, dvp, vp, cnp, scnp);
return (error);
}
@@ -625,18 +626,19 @@
return (error);
}
-MAC_CHECK_PROBE_DEFINE3(vnode_check_open, "struct ucred *", "struct vnode *",
- "accmode_t");
+MAC_CHECK_PROBE_DEFINE4(vnode_check_open, "struct ucred *", "struct vnode *",
+ "accmode_t", "struct componentname *");
int
-mac_vnode_check_open_impl(struct ucred *cred, struct vnode *vp, accmode_t accmode)
+mac_vnode_check_open_impl(struct ucred *cred, struct vnode *vp,
+ accmode_t accmode, struct componentname *cnp)
{
int error;
ASSERT_VOP_LOCKED(vp, "mac_vnode_check_open");
- MAC_POLICY_CHECK(vnode_check_open, cred, vp, vp->v_label, accmode);
- MAC_CHECK_PROBE3(vnode_check_open, error, cred, vp, accmode);
+ MAC_POLICY_CHECK(vnode_check_open, cred, vp, vp->v_label, accmode, cnp);
+ MAC_CHECK_PROBE4(vnode_check_open, error, cred, vp, accmode, cnp);
return (error);
}
diff --git a/sys/security/mac_biba/mac_biba.c b/sys/security/mac_biba/mac_biba.c
--- a/sys/security/mac_biba/mac_biba.c
+++ b/sys/security/mac_biba/mac_biba.c
@@ -62,6 +62,7 @@
#include <sys/systm.h>
#include <sys/vnode.h>
#include <sys/file.h>
+#include <sys/namei.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/pipe.h>
@@ -3031,7 +3032,7 @@
static int
biba_vnode_check_link(struct ucred *cred, struct vnode *dvp,
struct label *dvplabel, struct vnode *vp, struct label *vplabel,
- struct componentname *cnp)
+ struct componentname *cnp, struct componentname *scnp)
{
struct mac_biba *subj, *obj;
@@ -3118,7 +3119,7 @@
static int
biba_vnode_check_open(struct ucred *cred, struct vnode *vp,
- struct label *vplabel, accmode_t accmode)
+ struct label *vplabel, accmode_t accmode, struct componentname *cnp)
{
struct mac_biba *subj, *obj;
diff --git a/sys/security/mac_bsdextended/mac_bsdextended.h b/sys/security/mac_bsdextended/mac_bsdextended.h
--- a/sys/security/mac_bsdextended/mac_bsdextended.h
+++ b/sys/security/mac_bsdextended/mac_bsdextended.h
@@ -51,6 +51,7 @@
#define MBI_APPEND 040000
#define MBI_ALLPERM (MBI_EXEC | MBI_WRITE | MBI_READ | MBI_ADMIN | \
MBI_STAT | MBI_APPEND)
+#define MBI_LINK 0100000
#define MBS_UID_DEFINED 0x00000001 /* uid field should be matched */
#define MBS_GID_DEFINED 0x00000002 /* gid field should be matched */
@@ -68,18 +69,19 @@
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_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_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_GLOB_DEFINED 0x00000100 /* glob field 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)
+ MBO_TYPE_DEFINED | MBO_GLOB_DEFINED)
#define MBO_TYPE_REG 0x00000001
#define MBO_TYPE_DIR 0x00000002
@@ -92,6 +94,8 @@
#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)
+#define MBO_GLOB_MAX 256
+
struct mac_bsdextended_object {
int mbo_flags;
int mbo_neg;
@@ -100,6 +104,7 @@
gid_t mbo_gid_min;
gid_t mbo_gid_max;
fsid_t mbo_fsid;
+ char mbo_glob[MBO_GLOB_MAX];
int mbo_type;
};
diff --git a/sys/security/mac_bsdextended/mac_bsdextended.c b/sys/security/mac_bsdextended/mac_bsdextended.c
--- a/sys/security/mac_bsdextended/mac_bsdextended.c
+++ b/sys/security/mac_bsdextended/mac_bsdextended.c
@@ -61,6 +61,7 @@
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/stat.h>
+#include <sys/namei.h>
#include <security/mac/mac_policy.h>
#include <security/mac_bsdextended/mac_bsdextended.h>
@@ -221,9 +222,29 @@
mtx_destroy(&ugidfw_mtx);
}
+static int
+ugidfw_globmatch(struct componentname *cnp, char *glob, int neg)
+{
+ int match;
+ char *matchthis;
+
+ if (cnp == NULL)
+ return (0);
+ matchthis = strrchr(cnp->cn_nameptr, '/');
+ if (matchthis == NULL)
+ matchthis = cnp->cn_nameptr;
+ else
+ matchthis++;
+ match = fnmatch(glob, matchthis, 0) != FNM_NOMATCH;
+ if (neg & MBO_GLOB_DEFINED)
+ match = !match;
+ return (match);
+}
+
static int
ugidfw_rulecheck(struct mac_bsdextended_rule *rule,
- struct ucred *cred, struct vnode *vp, struct vattr *vap, int acc_mode)
+ struct ucred *cred, struct vnode *vp, struct vattr *vap, int acc_mode,
+ struct componentname *cnp)
{
int mac_granted, match, priv_granted;
int i;
@@ -308,6 +329,18 @@
return (0);
}
+ if (rule->mbr_object.mbo_flags & MBO_GLOB_DEFINED) {
+ if (cnp != NULL) {
+ match = ugidfw_globmatch(cnp,
+ rule->mbr_object.mbo_glob,
+ rule->mbr_object.mbo_neg);
+ if (!match)
+ return (0);
+ } else {
+ return (0);
+ }
+ }
+
if (rule->mbr_object.mbo_flags & MBO_SUID) {
match = (vap->va_mode & S_ISUID);
if (rule->mbr_object.mbo_neg & MBO_SUID)
@@ -421,9 +454,9 @@
int
ugidfw_check(struct ucred *cred, struct vnode *vp, struct vattr *vap,
- int acc_mode)
+ int acc_mode, struct componentname *cnp)
{
- int error, i;
+ int error, i, match;
/*
* Since we do not separately handle append, map append to write.
@@ -436,8 +469,27 @@
for (i = 0; i < rule_slots; i++) {
if (rules[i] == NULL)
continue;
+ if (acc_mode & MBI_LINK && cnp != NULL &&
+ rules[i]->mbr_object.mbo_flags & MBO_GLOB_DEFINED) {
+ /*
+ * Forbid hardlinks when glob restriction is in
+ * effect for the source file.
+ */
+ match = ugidfw_globmatch(cnp,
+ rules[i]->mbr_object.mbo_glob,
+ rules[i]->mbr_object.mbo_neg);
+ if (match) {
+ if (ugidfw_logging)
+ log(LOG_AUTHPRIV,
+ "mac_bsdextended: hardlink "
+ "prevented");
+ if (!ugidfw_firstmatch_enabled)
+ mtx_unlock(&ugidfw_mtx);
+ return (EACCES);
+ }
+ }
error = ugidfw_rulecheck(rules[i], cred,
- vp, vap, acc_mode);
+ vp, vap, acc_mode, cnp);
if (error == EJUSTRETURN)
break;
if (error) {
@@ -450,7 +502,8 @@
}
int
-ugidfw_check_vp(struct ucred *cred, struct vnode *vp, int acc_mode)
+ugidfw_check_vp(struct ucred *cred, struct vnode *vp, int acc_mode,
+ struct componentname *cnp)
{
int error;
struct vattr vap;
@@ -460,7 +513,7 @@
error = VOP_GETATTR(vp, &vap, cred);
if (error)
return (error);
- return (ugidfw_check(cred, vp, &vap, acc_mode));
+ return (ugidfw_check(cred, vp, &vap, acc_mode, cnp));
}
int
diff --git a/sys/security/mac_bsdextended/ugidfw_internal.h b/sys/security/mac_bsdextended/ugidfw_internal.h
--- a/sys/security/mac_bsdextended/ugidfw_internal.h
+++ b/sys/security/mac_bsdextended/ugidfw_internal.h
@@ -34,8 +34,9 @@
*/
int ugidfw_accmode2mbi(accmode_t accmode);
int ugidfw_check(struct ucred *cred, struct vnode *vp, struct vattr *vap,
- int acc_mode);
-int ugidfw_check_vp(struct ucred *cred, struct vnode *vp, int acc_mode);
+ int acc_mode, struct componentname *cnp);
+int ugidfw_check_vp(struct ucred *cred, struct vnode *vp, int acc_mode,
+ struct componentname *cnp);
/*
* System access control checks.
@@ -51,7 +52,8 @@
* Vnode access control checks.
*/
int ugidfw_vnode_check_access(struct ucred *cred, struct vnode *vp,
- struct label *vplabel, accmode_t accmode);
+ struct label *vplabel, accmode_t accmode,
+ struct componentname *cnp);
int ugidfw_vnode_check_chdir(struct ucred *cred, struct vnode *dvp,
struct label *dvplabel);
int ugidfw_vnode_check_chroot(struct ucred *cred, struct vnode *dvp,
@@ -73,13 +75,14 @@
struct label *vplabel, int attrnamespace, const char *name);
int ugidfw_vnode_check_link(struct ucred *cred, struct vnode *dvp,
struct label *dvplabel, struct vnode *vp, struct label *label,
- struct componentname *cnp);
+ struct componentname *cnp, struct componentname *scnp);
int ugidfw_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
struct label *vplabel, int attrnamespace);
int ugidfw_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
struct label *dvplabel, struct componentname *cnp);
int ugidfw_vnode_check_open(struct ucred *cred, struct vnode *vp,
- struct label *vplabel, accmode_t accmode);
+ struct label *vplabel, accmode_t accmode,
+ struct componentname *cnp);
int ugidfw_vnode_check_readdir(struct ucred *cred, struct vnode *dvp,
struct label *dvplabel);
int ugidfw_vnode_check_readdlink(struct ucred *cred, struct vnode *vp,
diff --git a/sys/security/mac_bsdextended/ugidfw_system.c b/sys/security/mac_bsdextended/ugidfw_system.c
--- a/sys/security/mac_bsdextended/ugidfw_system.c
+++ b/sys/security/mac_bsdextended/ugidfw_system.c
@@ -64,7 +64,7 @@
{
if (vp != NULL)
- return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE, NULL));
else
return (0);
}
@@ -75,7 +75,7 @@
{
if (vp != NULL)
- return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE, NULL));
else
return (0);
}
@@ -85,5 +85,5 @@
struct label *vplabel)
{
- return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE, NULL));
}
diff --git a/sys/security/mac_bsdextended/ugidfw_vnode.c b/sys/security/mac_bsdextended/ugidfw_vnode.c
--- a/sys/security/mac_bsdextended/ugidfw_vnode.c
+++ b/sys/security/mac_bsdextended/ugidfw_vnode.c
@@ -60,10 +60,10 @@
int
ugidfw_vnode_check_access(struct ucred *cred, struct vnode *vp,
- struct label *vplabel, accmode_t accmode)
+ struct label *vplabel, accmode_t accmode, struct componentname *cnp)
{
- return (ugidfw_check_vp(cred, vp, ugidfw_accmode2mbi(accmode)));
+ return (ugidfw_check_vp(cred, vp, ugidfw_accmode2mbi(accmode), cnp));
}
int
@@ -71,7 +71,7 @@
struct label *dvplabel)
{
- return (ugidfw_check_vp(cred, dvp, MBI_EXEC));
+ return (ugidfw_check_vp(cred, dvp, MBI_EXEC, NULL));
}
int
@@ -79,7 +79,7 @@
struct label *dvplabel)
{
- return (ugidfw_check_vp(cred, dvp, MBI_EXEC));
+ return (ugidfw_check_vp(cred, dvp, MBI_EXEC, NULL));
}
int
@@ -87,7 +87,7 @@
struct label *dvplabel, struct componentname *cnp, struct vattr *vap)
{
- return (ugidfw_check_vp(cred, dvp, MBI_WRITE));
+ return (ugidfw_check_vp(cred, dvp, MBI_WRITE, cnp));
}
int
@@ -95,7 +95,7 @@
struct label *vplabel, acl_type_t type)
{
- return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN, NULL));
}
int
@@ -103,7 +103,7 @@
struct label *vplabel, int attrnamespace, const char *name)
{
- return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE, NULL));
}
int
@@ -112,7 +112,7 @@
struct label *execlabel)
{
- return (ugidfw_check_vp(cred, vp, MBI_READ|MBI_EXEC));
+ return (ugidfw_check_vp(cred, vp, MBI_READ|MBI_EXEC, NULL));
}
int
@@ -120,7 +120,7 @@
struct label *vplabel, acl_type_t type)
{
- return (ugidfw_check_vp(cred, vp, MBI_STAT));
+ return (ugidfw_check_vp(cred, vp, MBI_STAT, NULL));
}
int
@@ -128,20 +128,28 @@
struct label *vplabel, int attrnamespace, const char *name)
{
- return (ugidfw_check_vp(cred, vp, MBI_READ));
+ return (ugidfw_check_vp(cred, vp, MBI_READ, NULL));
}
int
ugidfw_vnode_check_link(struct ucred *cred, struct vnode *dvp,
struct label *dvplabel, struct vnode *vp, struct label *label,
- struct componentname *cnp)
+ struct componentname *cnp, struct componentname *scnp)
{
int error;
- error = ugidfw_check_vp(cred, dvp, MBI_WRITE);
+ /*
+ * This is to allow ugidfw_check_vp to prevent hardlinks
+ * when filename globbing is in effect.
+ */
+ error = ugidfw_check_vp(cred, dvp, MBI_LINK, scnp);
if (error)
return (error);
- error = ugidfw_check_vp(cred, vp, MBI_WRITE);
+
+ error = ugidfw_check_vp(cred, dvp, MBI_WRITE, cnp);
+ if (error)
+ return (error);
+ error = ugidfw_check_vp(cred, vp, MBI_WRITE, cnp);
if (error)
return (error);
return (0);
@@ -152,7 +160,7 @@
struct label *vplabel, int attrnamespace)
{
- return (ugidfw_check_vp(cred, vp, MBI_READ));
+ return (ugidfw_check_vp(cred, vp, MBI_READ, NULL));
}
int
@@ -160,23 +168,23 @@
struct label *dvplabel, struct componentname *cnp)
{
- return (ugidfw_check_vp(cred, dvp, MBI_EXEC));
+ return (ugidfw_check_vp(cred, dvp, MBI_EXEC, cnp));
}
int
ugidfw_vnode_check_open(struct ucred *cred, struct vnode *vp,
- struct label *vplabel, accmode_t accmode)
+ struct label *vplabel, accmode_t accmode, struct componentname *cnp)
{
- return (ugidfw_check_vp(cred, vp, ugidfw_accmode2mbi(accmode)));
+ return (ugidfw_check_vp(cred, vp, ugidfw_accmode2mbi(accmode), cnp));
}
int
ugidfw_vnode_check_readdir(struct ucred *cred, struct vnode *dvp,
struct label *dvplabel)
{
-
- return (ugidfw_check_vp(cred, dvp, MBI_READ));
+
+ return (ugidfw_check_vp(cred, dvp, MBI_READ, NULL));
}
int
@@ -184,7 +192,7 @@
struct label *vplabel)
{
- return (ugidfw_check_vp(cred, vp, MBI_READ));
+ return (ugidfw_check_vp(cred, vp, MBI_READ, NULL));
}
int
@@ -194,10 +202,10 @@
{
int error;
- error = ugidfw_check_vp(cred, dvp, MBI_WRITE);
+ error = ugidfw_check_vp(cred, dvp, MBI_WRITE, cnp);
if (error)
return (error);
- return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE, cnp));
}
int
@@ -207,11 +215,11 @@
{
int error;
- error = ugidfw_check_vp(cred, dvp, MBI_WRITE);
+ error = ugidfw_check_vp(cred, dvp, MBI_WRITE, cnp);
if (error)
return (error);
if (vp != NULL)
- error = ugidfw_check_vp(cred, vp, MBI_WRITE);
+ error = ugidfw_check_vp(cred, vp, MBI_WRITE, cnp);
return (error);
}
@@ -220,7 +228,7 @@
struct label *vplabel)
{
- return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN, NULL));
}
int
@@ -228,7 +236,7 @@
struct label *vplabel, acl_type_t type, struct acl *acl)
{
- return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN, NULL));
}
int
@@ -236,7 +244,7 @@
struct label *vplabel, int attrnamespace, const char *name)
{
- return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE, NULL));
}
int
@@ -244,7 +252,7 @@
struct label *vplabel, u_long flags)
{
- return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN, NULL));
}
int
@@ -252,7 +260,7 @@
struct label *vplabel, mode_t mode)
{
- return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN, NULL));
}
int
@@ -260,7 +268,7 @@
struct label *vplabel, uid_t uid, gid_t gid)
{
- return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN, NULL));
}
int
@@ -268,15 +276,16 @@
struct label *vplabel, struct timespec atime, struct timespec utime)
{
- return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN, NULL));
}
int
ugidfw_vnode_check_stat(struct ucred *active_cred,
- struct ucred *file_cred, struct vnode *vp, struct label *vplabel)
+ struct ucred *file_cred, struct vnode *vp, struct label *vplabel /*,
+ struct componentname *cnp */)
{
- return (ugidfw_check_vp(active_cred, vp, MBI_STAT));
+ return (ugidfw_check_vp(active_cred, vp, MBI_STAT, NULL));
}
int
@@ -286,8 +295,8 @@
{
int error;
- error = ugidfw_check_vp(cred, dvp, MBI_WRITE);
+ error = ugidfw_check_vp(cred, dvp, MBI_WRITE, cnp);
if (error)
return (error);
- return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE, cnp));
}
diff --git a/sys/security/mac_lomac/mac_lomac.c b/sys/security/mac_lomac/mac_lomac.c
--- a/sys/security/mac_lomac/mac_lomac.c
+++ b/sys/security/mac_lomac/mac_lomac.c
@@ -2374,7 +2374,7 @@
static int
lomac_vnode_check_link(struct ucred *cred, struct vnode *dvp,
struct label *dvplabel, struct vnode *vp, struct label *vplabel,
- struct componentname *cnp)
+ struct componentname *cnp, struct componentname *scnp)
{
struct mac_lomac *subj, *obj;
@@ -2445,7 +2445,7 @@
static int
lomac_vnode_check_open(struct ucred *cred, struct vnode *vp,
- struct label *vplabel, accmode_t accmode)
+ struct label *vplabel, accmode_t accmode, struct componentname *cnp)
{
struct mac_lomac *subj, *obj;
diff --git a/sys/security/mac_mls/mac_mls.c b/sys/security/mac_mls/mac_mls.c
--- a/sys/security/mac_mls/mac_mls.c
+++ b/sys/security/mac_mls/mac_mls.c
@@ -2660,7 +2660,7 @@
static int
mls_vnode_check_link(struct ucred *cred, struct vnode *dvp,
struct label *dvplabel, struct vnode *vp, struct label *vplabel,
- struct componentname *cnp)
+ struct componentname *cnp, struct componentname *scnp)
{
struct mac_mls *subj, *obj;
@@ -2747,7 +2747,7 @@
static int
mls_vnode_check_open(struct ucred *cred, struct vnode *vp,
- struct label *vplabel, accmode_t accmode)
+ struct label *vplabel, accmode_t accmode, struct componentname *cnp)
{
struct mac_mls *subj, *obj;
diff --git a/sys/security/mac_stub/mac_stub.c b/sys/security/mac_stub/mac_stub.c
--- a/sys/security/mac_stub/mac_stub.c
+++ b/sys/security/mac_stub/mac_stub.c
@@ -1453,7 +1453,7 @@
static int
stub_vnode_check_access(struct ucred *cred, struct vnode *vp,
- struct label *vplabel, accmode_t accmode)
+ struct label *vplabel, accmode_t accmode, struct componentname *cnp)
{
return (0);
@@ -1527,7 +1527,7 @@
static int
stub_vnode_check_link(struct ucred *cred, struct vnode *dvp,
struct label *dvplabel, struct vnode *vp, struct label *vplabel,
- struct componentname *cnp)
+ struct componentname *cnp, struct componentname *scnp)
{
return (0);
@@ -1574,7 +1574,7 @@
static int
stub_vnode_check_open(struct ucred *cred, struct vnode *vp,
- struct label *vplabel, accmode_t accmode)
+ struct label *vplabel, accmode_t accmode, struct componentname *cnp)
{
return (0);
diff --git a/sys/security/mac_test/mac_test.c b/sys/security/mac_test/mac_test.c
--- a/sys/security/mac_test/mac_test.c
+++ b/sys/security/mac_test/mac_test.c
@@ -2668,7 +2668,7 @@
COUNTER_DECL(vnode_check_access);
static int
test_vnode_check_access(struct ucred *cred, struct vnode *vp,
- struct label *vplabel, accmode_t accmode)
+ struct label *vplabel, accmode_t accmode, struct componentname *cnp)
{
LABEL_CHECK(cred->cr_label, MAGIC_CRED);
@@ -2788,7 +2788,7 @@
static int
test_vnode_check_link(struct ucred *cred, struct vnode *dvp,
struct label *dvplabel, struct vnode *vp, struct label *vplabel,
- struct componentname *cnp)
+ struct componentname *cnp, struct componentname *scnp)
{
LABEL_CHECK(cred->cr_label, MAGIC_CRED);
@@ -2841,7 +2841,7 @@
COUNTER_DECL(vnode_check_open);
static int
test_vnode_check_open(struct ucred *cred, struct vnode *vp,
- struct label *vplabel, accmode_t accmode)
+ struct label *vplabel, accmode_t accmode, struct componentname *cnp)
{
LABEL_CHECK(cred->cr_label, MAGIC_CRED);
diff --git a/sys/sys/param.h b/sys/sys/param.h
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -74,7 +74,7 @@
* cannot include sys/param.h and should only be updated here.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1600014
+#define __FreeBSD_version 1600015
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -791,7 +791,7 @@
int vn_open_cred(struct nameidata *ndp, int *flagp, int cmode,
u_int vn_open_flags, struct ucred *cred, struct file *fp);
int vn_open_vnode(struct vnode *vp, int fmode, struct ucred *cred,
- struct thread *td, struct file *fp);
+ struct thread *td, struct file *fp, struct nameidata *nd);
void vn_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end);
void vn_pages_remove_valid(struct vnode *vp, vm_pindex_t start,
vm_pindex_t end);
diff --git a/tests/sys/mac/bsdextended/matches_test.sh b/tests/sys/mac/bsdextended/matches_test.sh
--- a/tests/sys/mac/bsdextended/matches_test.sh
+++ b/tests/sys/mac/bsdextended/matches_test.sh
@@ -379,6 +379,38 @@
cleanup
}
+atf_test_case object_glob cleanup
+object_glob_head()
+{
+ atf_set "require.user" "root"
+}
+object_glob_body()
+{
+ setup
+
+ # access still working when glob not matched
+ atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object glob 'nomatch' mode arx
+ atf_check -s exit:0 su -fm $uidinrange -c "$command1"
+
+ # permission denied when glob matches
+ atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object glob 'test-*' mode arx
+ atf_check -s not-exit:0 -e match:"Permission denied" \
+ su -fm $uidinrange -c "$command1"
+
+ # does hardlink prevention work?
+ atf_check -s not-exit:0 -e match:"Permission denied" \
+ su -fm $uidinrange -c "ln $file1 mnt/meh"
+ # and do other handlinks still work?
+ atf_check -s exit:0 \
+ su -fm $uidinrange -c "touch mnt/file2a"
+ atf_check -s exit:0 \
+ su -fm $uidinrange -c "ln mnt/file2a mnt/file2b"
+}
+object_glob_cleanup()
+{
+ cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case no_rules
@@ -393,4 +425,5 @@
atf_add_test_case object_uid_matches_subject
atf_add_test_case object_gid_matches_subject
atf_add_test_case object_type
+ atf_add_test_case object_glob
}
diff --git a/usr.sbin/ugidfw/ugidfw.8 b/usr.sbin/ugidfw/ugidfw.8
--- a/usr.sbin/ugidfw/ugidfw.8
+++ b/usr.sbin/ugidfw/ugidfw.8
@@ -67,6 +67,10 @@
.Oc
.Oo
.Op Cm \&!
+.Cm glob Ad pattern
+.Oc
+.Oo
+.Op Cm \&!
.Cm suid
.Oc
.Oo
@@ -122,6 +126,10 @@
.Oc
.Oo
.Op Cm \&!
+.Cm glob Ad pattern
+.Oc
+.Oo
+.Op Cm \&!
.Cm suid
.Oc
.Oo
@@ -241,6 +249,10 @@
.Oc
.Oo
.Op Cm \&!
+.Cm glob Ad pattern
+.Oc
+.Oo
+.Op Cm \&!
.Cm suid
.Oc
.Oo
@@ -279,6 +291,14 @@
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 match a filename glob pattern using
+.Cm glob .
+.Cm Pattern
+is evaluated against the last pathname component.
+When
+.Cm glob
+is in effect the system also prevents hardlinking to files matching the
+.Cm pattern .
The object can be required to have the
.Cm suid
or

File Metadata

Mime Type
text/plain
Expires
Thu, Jun 18, 5:28 PM (3 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34054586
Default Alt Text
D56166.diff (37 KB)

Event Timeline