Whamcloud - gitweb
LU-9727 lustre: record denied OPEN in Changelogs 12/28812/24
authorSebastien Buisson <sbuisson@ddn.com>
Tue, 29 Aug 2017 08:45:30 +0000 (17:45 +0900)
committerOleg Drokin <oleg.drokin@intel.com>
Wed, 14 Feb 2018 00:52:06 +0000 (00:52 +0000)
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>
lustre/include/uapi/linux/lustre/lustre_idl.h
lustre/include/uapi/linux/lustre/lustre_user.h
lustre/mdd/mdd_device.c
lustre/mdd/mdd_internal.h
lustre/mdd/mdd_lproc.c
lustre/mdd/mdd_object.c
lustre/utils/lustre_rsync.c

index b4ee226..39419fe 100644 (file)
@@ -2702,11 +2702,12 @@ struct llog_size_change_rec {
 /** 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"
index fabf9db..46c72b4 100644 (file)
@@ -1065,6 +1065,7 @@ enum changelog_rec_type {
        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
 };
 
@@ -1073,7 +1074,7 @@ static inline const char *changelog_type2str(int type) {
                "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)
index d87685f..842bc38 100644 (file)
@@ -125,6 +125,7 @@ static int mdd_init0(const struct lu_env *env, struct mdd_device *mdd,
        /* 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)
index 5503f54..a8befd5 100644 (file)
@@ -94,6 +94,9 @@ struct mdd_changelog {
        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)
index 923cca1..6d6af2f 100644 (file)
@@ -394,6 +394,41 @@ mdd_changelog_min_free_cat_entries_seq_write(struct file *file,
 }
 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;
@@ -521,6 +556,8 @@ static struct lprocfs_vars lprocfs_mdd_obd_vars[] = {
          .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",
index 1b3cb2b..d816c53 100644 (file)
@@ -58,6 +58,9 @@ struct mdd_object_user {
        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,
@@ -112,6 +115,7 @@ static struct mdd_object_user *mdd_obj_user_alloc(int flags,
        mou->mou_flags = flags;
        mou->mou_uidgid = ((__u64)uid << 32) | gid;
        mou->mou_opencount = 0;
+       mou->mou_deniednext = ktime_set(0, 0);
 
        RETURN(mou);
 }
@@ -163,8 +167,10 @@ struct mdd_object_user *mdd_obj_user_find(struct mdd_object *mdd_obj,
  * \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);
@@ -178,7 +184,15 @@ static int mdd_obj_user_add(struct mdd_object *mdd_obj,
 
        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);
 }
@@ -850,7 +864,7 @@ static int mdd_changelog_data_store_by_fid(const struct lu_env *env,
                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;
@@ -2869,6 +2883,7 @@ static int mdd_open(const struct lu_env *env, struct md_object *obj,
        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);
@@ -2878,15 +2893,17 @@ static int mdd_open(const struct lu_env *env, struct md_object *obj,
                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:
@@ -2894,23 +2911,47 @@ 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);
index fe8406a..509c67d 100644 (file)
@@ -1637,6 +1637,7 @@ int lr_replicate()
                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 */