Record denied OPEN events in Changelogs, in the same format as
successful OPEN events.
Recording denied OPEN events is useful for security audit,
in order to find out who tried to get access to some data.
An NOPEN changlog entry is in the form:
4 24NOPEN 15:45:44.
947406626 2017.08.31 0x2 t=[0x200000402:0x1:0x0]
ef=0xf u=500:500 nid=10.128.11.158@tcp m=-w-
By default, disable recording of NOPEN events in Changelogs.
NOPEN entries in Changelogs are rate limited: no more than one
entry per user per file per minute, configurable via
/proc/fs/lustre/mdd/<fsname>-MDTXXX/changelog_deniednext
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: Ib33651dda63735e21fffeed34cb1adc803ff7eca
Reviewed-on: https://review.whamcloud.com/28812
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: Matthew S <matthew.sanderson@anu.edu.au>
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
/** default \a changelog_rec_type mask. Allow all of them, except
* CL_ATIME since it can really be time consuming, and not necessary
* under normal use.
- * Remove also CL_OPEN and CL_GETXATTR from default list as it can be costly and
- * only necessary for audit purpose.
+ * Remove also CL_OPEN, CL_GETXATTR and CL_DN_OPEN from default list as it can
+ * be costly and only necessary for audit purpose.
*/
#define CHANGELOG_DEFMASK (CHANGELOG_ALLMASK & \
- ~(1 << CL_ATIME | 1 << CL_OPEN | 1 << CL_GETXATTR))
+ ~(1 << CL_ATIME | 1 << CL_OPEN | 1 << CL_GETXATTR | \
+ 1 << CL_DN_OPEN))
/* changelog llog name, needed by client replicators */
#define CHANGELOG_CATALOG "changelog_catalog"
CL_FLRW = 21, /* FLR: file was firstly written */
CL_RESYNC = 22, /* FLR: file was resync-ed */
CL_GETXATTR = 23,
+ CL_DN_OPEN = 24, /* denied open */
CL_LAST
};
"MARK", "CREAT", "MKDIR", "HLINK", "SLINK", "MKNOD", "UNLNK",
"RMDIR", "RENME", "RNMTO", "OPEN", "CLOSE", "LYOUT", "TRUNC",
"SATTR", "XATTR", "HSM", "MTIME", "CTIME", "ATIME", "MIGRT",
- "FLRW", "RESYNC","GXATR",
+ "FLRW", "RESYNC","GXATR", "NOPEN",
};
if (type >= 0 && type < CL_LAST)
/* LU-8040 Set defaults here, before values configs */
mdd->mdd_cl.mc_flags = 0; /* off by default */
mdd->mdd_cl.mc_mask = CHANGELOG_DEFMASK;
+ mdd->mdd_cl.mc_deniednext = 60; /* 60 secs by default */
dev = lustre_cfg_string(lcfg, 0);
if (dev == NULL)
int mc_lastuser;
struct task_struct *mc_gc_task;
time64_t mc_gc_time;
+ unsigned int mc_deniednext; /* interval for recording denied
+ * accesses
+ */
};
static inline __u64 cl_time(void)
}
LPROC_SEQ_FOPS(mdd_changelog_min_free_cat_entries);
+static int mdd_changelog_deniednext_seq_show(struct seq_file *m, void *data)
+{
+ struct mdd_device *mdd = m->private;
+
+ seq_printf(m, "%u\n", mdd->mdd_cl.mc_deniednext);
+ return 0;
+}
+
+static ssize_t
+mdd_changelog_deniednext_seq_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *off)
+{
+ struct seq_file *m = file->private_data;
+ struct mdd_device *mdd = m->private;
+ char kernbuf[11];
+ unsigned int time = 0;
+ int rc;
+
+ if (count > (sizeof(kernbuf) - 1))
+ return -EINVAL;
+
+ if (copy_from_user(kernbuf, buffer, count))
+ return -EFAULT;
+
+ kernbuf[count] = '\0';
+
+ rc = kstrtoul(kernbuf, 0, (unsigned long int *)&time);
+ if (rc)
+ return rc;
+
+ mdd->mdd_cl.mc_deniednext = time;
+ return count;
+}
+LPROC_SEQ_FOPS(mdd_changelog_deniednext);
+
static int mdd_sync_perm_seq_show(struct seq_file *m, void *data)
{
struct mdd_device *mdd = m->private;
.fops = &mdd_changelog_min_gc_interval_fops },
{ .name = "changelog_min_free_cat_entries",
.fops = &mdd_changelog_min_free_cat_entries_fops },
+ { .name = "changelog_deniednext",
+ .fops = &mdd_changelog_deniednext_fops },
{ .name = "sync_permission",
.fops = &mdd_sync_perm_fops },
{ .name = "lfsck_speed_limit",
int mou_flags; /**< open mode by client */
__u64 mou_uidgid; /**< uid_gid on client */
int mou_opencount; /**< # opened */
+ ktime_t mou_deniednext; /**< time of next access denied
+ * notfication
+ */
};
static int mdd_xattr_get(const struct lu_env *env,
mou->mou_flags = flags;
mou->mou_uidgid = ((__u64)uid << 32) | gid;
mou->mou_opencount = 0;
+ mou->mou_deniednext = ktime_set(0, 0);
RETURN(mou);
}
* \retval -ve failure
*/
static int mdd_obj_user_add(struct mdd_object *mdd_obj,
- struct mdd_object_user *mou)
+ struct mdd_object_user *mou,
+ bool denied)
{
+ struct mdd_device *mdd = mdd_obj2mdd_dev(mdd_obj);
struct mdd_object_user *tmp;
__u32 uid = mou->mou_uidgid >> 32;
__u32 gid = mou->mou_uidgid & ((1UL << 32) - 1);
list_add_tail(&mou->mou_list, &mdd_obj->mod_users);
- mou->mou_opencount++;
+ if (denied)
+ /* next 'access denied' notification cannot happen before
+ * mou_deniednext
+ */
+ mou->mou_deniednext =
+ ktime_add(ktime_get(),
+ ktime_set(mdd->mdd_cl.mc_deniednext, 0));
+ else
+ mou->mou_opencount++;
RETURN(0);
}
xflags |= CLFE_UIDGID;
xflags |= CLFE_NID;
}
- if (type == CL_OPEN)
+ if (type == CL_OPEN || type == CL_DN_OPEN)
xflags |= CLFE_OPEN;
if (type == CL_SETXATTR || type == CL_GETXATTR)
xflags |= CLFE_XATTR;
struct mdd_object_user *mou = NULL;
const struct lu_ucred *uc = lu_ucred(env);
struct mdd_device *mdd = mdo2mdd(obj);
+ int type = CL_OPEN;
int rc = 0;
mdd_write_lock(env, mdd_obj, MOR_TGT_CHILD);
GOTO(out, rc);
rc = mdd_open_sanity_check(env, mdd_obj, attr, flags);
- if (rc != 0)
+ if ((rc == -EACCES) && (mdd->mdd_cl.mc_mask & (1 << CL_DN_OPEN)))
+ type = CL_DN_OPEN;
+ else if (rc != 0)
GOTO(out, rc);
-
- mdd_obj->mod_count++;
+ else
+ mdd_obj->mod_count++;
/* Not recording */
if (!(mdd->mdd_cl.mc_flags & CLM_ON))
GOTO(out, rc);
- if (!(mdd->mdd_cl.mc_mask & (1 << CL_OPEN)))
+ if (!(mdd->mdd_cl.mc_mask & (1 << type)))
GOTO(out, rc);
find:
mou = mdd_obj_user_find(mdd_obj, uc->uc_uid, uc->uc_gid, flags);
if (!mou) {
+ int rc2;
+
/* add user to list */
mou = mdd_obj_user_alloc(flags, uc->uc_uid, uc->uc_gid);
- if (IS_ERR(mou))
- GOTO(out, rc = PTR_ERR(mou));
- rc = mdd_obj_user_add(mdd_obj, mou);
- if (rc != 0) {
+ if (IS_ERR(mou)) {
+ if (rc == 0)
+ rc = PTR_ERR(mou);
+ GOTO(out, rc);
+ }
+ rc2 = mdd_obj_user_add(mdd_obj, mou, type == CL_DN_OPEN);
+ if (rc2 != 0) {
mdd_obj_user_free(mou);
- if (rc == -EEXIST)
- GOTO(find, rc);
+ if (rc2 == -EEXIST)
+ GOTO(find, rc2);
}
} else {
- mou->mou_opencount++;
- /* same user opening file again with same flags: don't record */
- GOTO(out, rc);
+ if (type == CL_DN_OPEN) {
+ if (ktime_before(ktime_get(), mou->mou_deniednext))
+ /* same user denied again same access within
+ * time interval: do not record
+ */
+ GOTO(out, rc);
+
+ /* this user already denied, but some time ago:
+ * update denied time
+ */
+ mou->mou_deniednext =
+ ktime_add(ktime_get(),
+ ktime_set(mdd->mdd_cl.mc_deniednext,
+ 0));
+ } else {
+ mou->mou_opencount++;
+ /* same user opening file again with same flags:
+ * don't record
+ */
+ GOTO(out, rc);
+ }
}
- mdd_changelog(env, CL_OPEN, flags, md_dev, mdo2fid(mdd_obj));
+ mdd_changelog(env, type, flags, md_dev, mdo2fid(mdd_obj));
+
EXIT;
out:
mdd_write_unlock(env, mdd_obj);
case CL_EXT:
case CL_OPEN:
case CL_GETXATTR:
+ case CL_DN_OPEN:
case CL_LAYOUT:
case CL_MARK:
/* Nothing needs to be done for these entries */