/* enforce recovery for local clients */
lut_local_recovery:1,
lut_cksum_t10pi_enforce:1,
- lut_no_create:1;
+ lut_no_create:1,
+ /* if enabled, MDT inodes UID/GID are checked
+ * against the nodemap mapping rules.
+ */
+ lut_enable_resource_id_check:1;
/* checksum types supported on this node */
enum cksum_types lut_cksum_types_supported;
/** last_rcvd file */
ssize_t nodemap_map_acl(struct lu_nodemap *nodemap, void *buf, size_t size,
enum nodemap_tree_type tree_type);
int nodemap_map_suppgid(struct lu_nodemap *nodemap, int suppgid);
+int nodemap_check_resource_ids(struct obd_export *exp, __u32 fs_uid,
+ __u32 fs_gid);
#ifdef HAVE_SERVER_SUPPORT
void nodemap_test_nid(struct lnet_nid *nid, char *name_buf, size_t name_len);
#else
int mdt_init_ucred(struct mdt_thread_info *info, struct mdt_body *body);
int mdt_init_ucred_reint(struct mdt_thread_info *info);
void mdt_exit_ucred(struct mdt_thread_info *info);
+int mdt_check_resource_ids(struct mdt_thread_info *info,
+ struct mdt_object *obj);
int mdt_version_get_check(struct mdt_thread_info *info, struct mdt_object *mto,
int idx);
void mdt_version_get_save(struct mdt_thread_info *info, struct mdt_object *mto,
return new_init_ucred(info, REC_INIT, NULL);
}
+/**
+ * mdt_check_resource_id() - check client access to resource via nodemap
+ *
+ * @info: mdt thread environment
+ * @obj: mdt object to check
+ *
+ * Check whether the client is allowed to access the resource by consulting
+ * the nodemap with the client's export and the MDT inode's UID/GID attributes.
+ *
+ * Return:
+ * * %0 on success (access is allowed)
+ * * %-ECHRNG if access is denied
+ */
+int mdt_check_resource_ids(struct mdt_thread_info *info, struct mdt_object *obj)
+{
+ struct dt_object *dt;
+ struct lu_attr la = { 0 };
+
+ ENTRY;
+
+ if (info->mti_mdt->mdt_lut.lut_enable_resource_id_check == 0)
+ RETURN(0);
+
+ dt = mdt_obj2dt(obj);
+
+ /* Get attributes from MDT inode */
+ if (dt && dt->do_ops && dt->do_ops->do_attr_get) {
+ dt_attr_get(info->mti_env, mdt_obj2dt(obj), &la);
+ } else {
+ /* log this case but don't return err code */
+ CERROR("%s: no dt object for " DFID ": rc = %d\n",
+ mdt_obd_name(info->mti_mdt), PFID(mdt_object_fid(obj)),
+ -ENOENT);
+ RETURN(0);
+ }
+
+ RETURN(nodemap_check_resource_ids(mdt_info_req(info)->rq_export,
+ la.la_uid, la.la_gid));
+}
+
/* copied from lov/lov_ea.c, just for debugging, will be removed later */
void mdt_dump_lmm(int level, const struct lov_mds_md *lmm, __u64 valid)
{
MDT_BOOL_RW_ATTR(enable_dmv_xattr);
MDT_BOOL_RW_ATTR(enable_rename_trylock);
+/**
+ * enable_resource_id_check_show() - Show if resource ID checking is enabled
+ * on the MDT.
+ *
+ * @kobj: kobject for the MDT device
+ * @attr: attribute for the MDT device
+ * @buf: buffer to write the value to
+ *
+ * When enabled, MDT inodes UID/GID are checked against
+ * the nodemap mapping rules.
+ *
+ * Return:
+ * * %0 on success
+ * * %negative on failure
+ */
+static ssize_t enable_resource_id_check_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct obd_device *obd =
+ container_of(kobj, struct obd_device, obd_kset.kobj);
+ struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n",
+ mdt->mdt_lut.lut_enable_resource_id_check);
+}
+
+/**
+ * enable_resource_id_check_store() - Enable or disable resource ID checking
+ * on the MDT.
+ *
+ * @kobj: kobject for the MDT device
+ * @attr: attribute for the MDT device
+ * @buffer: buffer containing the value to set
+ * @count: length of the buffer
+ *
+ * This is used to interface to userspace administrative tools to enable
+ * or disable resource ID checking on the MDT.
+ *
+ * Return:
+ * * %0 on success
+ * * %negative on failure
+ */
+static ssize_t enable_resource_id_check_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct obd_device *obd =
+ container_of(kobj, struct obd_device, obd_kset.kobj);
+ struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+ bool val;
+ int rc;
+
+ rc = kstrtobool(buffer, &val);
+ if (rc)
+ return rc;
+
+ mdt->mdt_lut.lut_enable_resource_id_check = val;
+
+ return count;
+}
+LUSTRE_RW_ATTR(enable_resource_id_check);
+
static ssize_t enable_pin_gid_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
&lustre_attr_enable_remote_dir_gid.attr,
&lustre_attr_enable_remote_rename.attr,
&lustre_attr_enable_remote_subdir_mount.attr,
+ &lustre_attr_enable_rename_trylock.attr,
+ &lustre_attr_enable_resource_id_check.attr,
&lustre_attr_enable_strict_som.attr,
&lustre_attr_enable_striped_dir.attr,
&lustre_attr_commit_on_sharing.attr,
&lustre_attr_dir_restripe_nsonly.attr,
&lustre_attr_checksum_t10pi_enforce.attr,
&lustre_attr_max_mod_rpcs_in_flight.attr,
- &lustre_attr_enable_rename_trylock.attr,
NULL,
};
LUSTRE_RW_ATTR(degraded);
/**
+ * enable_resource_id_check_show() - Show if resource ID checking is enabled
+ * on the OST.
+ *
+ * @kobj: kobject for the OFD device
+ * @attr: attribute for the OFD device
+ * @buf: buffer to write the value to
+ *
+ * When enabled, an OST object's UID and GID are checked against
+ * the nodemap mapping rules.
+ *
+ * Return:
+ * * %0 on success
+ * * %negative on failure
+ */
+static ssize_t enable_resource_id_check_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct obd_device *obd =
+ container_of(kobj, struct obd_device, obd_kset.kobj);
+ struct ofd_device *ofd = ofd_dev(obd->obd_lu_dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n",
+ ofd->ofd_lut.lut_enable_resource_id_check);
+}
+
+/**
+ * enable_resource_id_check_store() - Enable or disable resource ID checking
+ * on the OST.
+ *
+ * @kobj: kobject for the OFD device
+ * @attr: attribute for the OFD device
+ * @buffer: buffer containing the value to set
+ * @count: length of the buffer
+ *
+ * This is used to interface to userspace administrative tools to enable
+ * or disable resource ID checking on the OST.
+ *
+ * Return:
+ * * %0 on success
+ * * %negative on failure
+ */
+static ssize_t enable_resource_id_check_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct obd_device *obd =
+ container_of(kobj, struct obd_device, obd_kset.kobj);
+ struct ofd_device *ofd = ofd_dev(obd->obd_lu_dev);
+ bool val;
+ int rc;
+
+ rc = kstrtobool(buffer, &val);
+ if (rc)
+ return rc;
+
+ spin_lock(&ofd->ofd_flags_lock);
+ ofd->ofd_lut.lut_enable_resource_id_check = val;
+ spin_unlock(&ofd->ofd_flags_lock);
+
+ return count;
+}
+LUSTRE_RW_ATTR(enable_resource_id_check);
+
+/**
* Show if the OFD is in no precreate mode.
*
* This means OFD has been adminstratively disabled at the OST to prevent
&lustre_attr_access_log_mask.attr,
&lustre_attr_access_log_size.attr,
&lustre_attr_atime_diff.attr,
+ &lustre_attr_at_history.attr,
+ &lustre_attr_at_max.attr,
+ &lustre_attr_at_min.attr,
&lustre_attr_brw_size.attr,
&lustre_attr_checksum_dump.attr,
&lustre_attr_checksum_t10pi_enforce.attr,
&lustre_attr_checksum_type.attr,
&lustre_attr_degraded.attr,
+ &lustre_attr_enable_resource_id_check.attr,
&lustre_attr_evict_client.attr,
&lustre_attr_eviction_count.attr,
&lustre_attr_fstype.attr,
&lustre_attr_job_cleanup_interval.attr,
&lustre_attr_lfsck_speed_limit.attr,
&lustre_attr_no_create.attr,
- &lustre_attr_readonly.attr,
#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 20, 53, 0)
&lustre_attr_no_precreate.attr,
#endif
&lustre_attr_num_exports.attr,
&lustre_attr_precreate_batch.attr,
+ &lustre_attr_readonly.attr,
&lustre_attr_recovery_time_hard.attr,
&lustre_attr_recovery_time_soft.attr,
&lustre_attr_seqs_allocated.attr,
&lustre_attr_tot_pending.attr,
&lustre_attr_soft_sync_limit.attr,
&lustre_attr_sync_journal.attr,
- &lustre_attr_at_min.attr,
- &lustre_attr_at_max.attr,
- &lustre_attr_at_history.attr,
NULL,
};
*/
#define OFD_DEF_ATIME_DIFF 0 /* disabled */
+/* Special mode value for OST objects with unset attributes */
+#define OFD_UNSET_ATTRS_MODE (S_IFREG | S_ISUID | S_ISGID | S_ISVTX | 0666)
+
/* request stats */
enum {
LPROC_OFD_STATS_READ_BYTES = 0,
struct lu_attr *la);
int ofd_attr_handle_id(const struct lu_env *env, struct ofd_object *fo,
struct lu_attr *la, int is_setattr);
+int ofd_check_resource_ids(const struct lu_env *env, struct obd_export *exp);
static inline
struct ofd_object *ofd_object_find_exists(const struct lu_env *env,
#include <dt_object.h>
#include <lustre_lfsck.h>
#include <lustre_export.h>
+#include <lustre_nodemap.h>
#include "ofd_internal.h"
RETURN(-ENOMEM);
info->fti_attr.la_valid = LA_TYPE | LA_MODE;
- info->fti_attr.la_mode = S_IFREG | S_ISUID | S_ISGID | S_ISVTX | 0666;
+ info->fti_attr.la_mode = OFD_UNSET_ATTRS_MODE;
info->fti_dof.dof_type = dt_mode_to_dft(S_IFREG);
info->fti_attr.la_valid |= LA_ATIME | LA_MTIME | LA_CTIME;
}
RETURN(rc);
}
+
+/**
+ * ofd_check_resource_id() - check client access to resource via nodemap
+ *
+ * @env: execution environment
+ * @exp: OBD export of client
+ *
+ * Check whether the client is allowed to access the resource by consulting
+ * the nodemap with the client's export and the OST objects's UID/GID attr.
+ *
+ * Return:
+ * * %0 on success (access is allowed)
+ * * %-ECHRNG if access is denied
+ */
+int ofd_check_resource_ids(const struct lu_env *env, struct obd_export *exp)
+{
+ struct ofd_object *fo;
+ struct lu_attr la = { 0 };
+ int rc = 0;
+
+ ENTRY;
+
+ if (ofd_exp(exp)->ofd_lut.lut_enable_resource_id_check == 0)
+ RETURN(0);
+
+ fo = ofd_info(env)->fti_obj;
+
+ rc = dt_attr_get(env, ofd_object_child(fo), &la);
+ if (rc) {
+ /* log this case but don't return err code */
+ CERROR("%s: failed to get attr for obj " DFID ": rc = %d\n",
+ ofd_name(ofd_exp(exp)),
+ PFID(lu_object_fid(&fo->ofo_obj.do_lu)), rc);
+ RETURN(0);
+ }
+
+ /* Objects with OFD_UNSET_ATTRS_MODE have no ID associated with them
+ * yet. Therefore, we can't verify that the stored IDs are valid.
+ * TODO Instead, the object will be repaired for future accesses based
+ * on the IDs set on the corresponding MDT inode.
+ */
+ if (la.la_mode == OFD_UNSET_ATTRS_MODE) {
+ CDEBUG(D_SEC,
+ "OST object " DFID " has unset attributes (mode=0%o), skipping ID check\n",
+ PFID(lu_object_fid(&fo->ofo_obj.do_lu)), la.la_mode);
+ RETURN(0);
+ }
+
+ RETURN(nodemap_check_resource_ids(exp, la.la_uid, la.la_gid));
+}
EXPORT_SYMBOL(nodemap_map_acl);
/**
- * Map supplementary groups received from client.
+ * nodemap_map_supplementary_groups() - map supplementary groups received
+ * from the client
*
- * \param lu_nodemap nodemap
- * \param id id to map
+ * @nodemap: nodemap
+ * @suppgid: id to map
*
- * \retval mapped id or -1 for invalid suppgid
+ * Return:
+ * * mapped id on success
+ * * %-1 for invalid suppgid
*/
int nodemap_map_suppgid(struct lu_nodemap *nodemap, int suppgid)
{
}
EXPORT_SYMBOL(nodemap_map_suppgid);
+/**
+ * nodemap_check_resource_id() - check if export can access a resource
+ *
+ * @exp: export to check
+ * @fs_uid: uid of the resource
+ * @fs_gid: gid of the resource
+ *
+ * Checks whether an export should be able to access a resource. This is called,
+ * e.g., for an MDT inode or OST object. If both UID and GID are squashed,
+ * the export should not be able to access the object since it is from outside
+ * the nodemap ID range.
+ *
+ * Return:
+ * * %0 on success (access is allowed)
+ * * %-ECHRNG if access is denied
+ */
+int nodemap_check_resource_ids(struct obd_export *exp, __u32 fs_uid,
+ __u32 fs_gid)
+{
+ struct lu_nodemap *nodemap;
+ __u32 client_uid, client_gid;
+ __u32 client_squashed_uid, client_squashed_gid;
+ int rc = 0;
+
+ ENTRY;
+
+ nodemap = nodemap_get_from_exp(exp);
+ if (IS_ERR_OR_NULL(nodemap))
+ RETURN(0);
+
+ client_uid = nodemap_map_id(nodemap, NODEMAP_UID, NODEMAP_FS_TO_CLIENT,
+ fs_uid);
+ client_gid = nodemap_map_id(nodemap, NODEMAP_GID, NODEMAP_FS_TO_CLIENT,
+ fs_gid);
+ client_squashed_uid = nodemap_map_id(nodemap, NODEMAP_UID,
+ NODEMAP_FS_TO_CLIENT,
+ nodemap->nm_squash_uid);
+ client_squashed_gid = nodemap_map_id(nodemap, NODEMAP_GID,
+ NODEMAP_FS_TO_CLIENT,
+ nodemap->nm_squash_gid);
+
+ if (client_uid == client_squashed_uid &&
+ client_gid == client_squashed_gid) {
+ CDEBUG(D_SEC,
+ "Nodemap %s: access denied for export %s (at %s) fs_uid=%u fs_gid=%u\n",
+ nodemap->nm_name, obd_uuid2str(&exp->exp_client_uuid),
+ obd_export_nid2str(exp), fs_uid, fs_gid);
+ GOTO(out, rc = -ECHRNG);
+ }
+
+out:
+ nodemap_putref(nodemap);
+ RETURN(rc);
+}
+EXPORT_SYMBOL(nodemap_check_resource_ids);
+
static int nodemap_inherit_properties(struct lu_nodemap *dst,
struct lu_nodemap *src)
{
lut->lut_cksum_t10pi_enforce = 0;
lut->lut_cksum_types_supported =
obd_cksum_types_supported_server(obd->obd_name);
+ lut->lut_enable_resource_id_check = 0;
spin_lock_init(&lut->lut_slc_locks_guard);
INIT_LIST_HEAD(&lut->lut_slc_locks);