systems since ext3-based ldiskfs is not supported on big-endian
systems. This can be over-riden with "bigendian_extents" mount option.
+Severity : enhancement
+Bugzilla : 12749
+Description: The root squash functionality
+Details : A security feature, which is to prevent users from being able
+ to mount lustre on their desktop, run as root, and delete
+ all of the files in the filesystem. The goal is accomplished by
+ remapping user id (UID) and group id (GID) of the root user to
+ a UID and GID specified by the system administartor via Lustre
+ configuration management server (MGS). The functionality also
+ allows to specify sets of clients for which the remapping does
+ not apply.
--------------------------------------------------------------------------------
2007-08-10 Cluster File Systems, Inc. <info@clusterfs.com>
#define LDD_F_SV_TYPE_MDT 0x0001
#define LDD_F_SV_TYPE_OST 0x0002
#define LDD_F_SV_TYPE_MGS 0x0004
+#define LDD_F_SV_ALL 0x0008
/** need an index assignment */
#define LDD_F_NEED_INDEX 0x0010
/** never registered */
char *name)
{
if (flags & (LDD_F_SV_TYPE_MDT | LDD_F_SV_TYPE_OST)) {
- sprintf(name, "%.8s-%s%04x", fs,
- (flags & LDD_F_SV_TYPE_MDT) ? "MDT" : "OST",
- index);
+ if (!(flags & LDD_F_SV_ALL))
+ sprintf(name, "%.8s-%s%04x", fs,
+ (flags & LDD_F_SV_TYPE_MDT) ? "MDT" : "OST",
+ index);
} else if (flags & LDD_F_SV_TYPE_MGS) {
sprintf(name, "MGS");
} else {
d->ld_obd->obd_namespace = m->mdt_namespace = NULL;
}
+ cfs_free_nidlist(&m->mdt_nosquash_nids);
+ if (m->mdt_nosquash_str) {
+ OBD_FREE(m->mdt_nosquash_str, m->mdt_nosquash_strlen);
+ m->mdt_nosquash_str = NULL;
+ m->mdt_nosquash_strlen = 0;
+ }
+
mdt_seq_fini(env, m);
mdt_seq_fini_cli(m);
mdt_fld_fini(env, m);
m->mdt_capa_timeout = CAPA_TIMEOUT;
m->mdt_capa_alg = CAPA_HMAC_ALG_SHA1;
m->mdt_ck_timeout = CAPA_KEY_TIMEOUT;
+ m->mdt_squash_uid = 0;
+ m->mdt_squash_gid = 0;
+ CFS_INIT_LIST_HEAD(&m->mdt_nosquash_nids);
+ m->mdt_nosquash_str = NULL;
+ m->mdt_nosquash_strlen = 0;
+ init_rwsem(&m->mdt_squash_sem);
spin_lock_init(&m->mdt_client_bitmap_lock);
struct lustre_capa_key mdt_capa_keys[2];
unsigned int mdt_capa_conf:1;
+ /* root squash */
+ uid_t mdt_squash_uid;
+ gid_t mdt_squash_gid;
+ struct list_head mdt_nosquash_nids;
+ char *mdt_nosquash_str;
+ int mdt_nosquash_strlen;
+ struct rw_semaphore mdt_squash_sem;
+
cfs_proc_dir_entry_t *mdt_proc_entry;
struct lprocfs_stats *mdt_stats;
int mdt_sec_level;
#define DEBUG_SUBSYSTEM S_MDS
#include "mdt_internal.h"
+#include <lnet/lib-lnet.h>
typedef enum ucred_init_type {
}
}
-/* XXX: root_squash will be redesigned in Lustre 1.7.
- * Do not root_squash for inter-MDS operations */
-static int mdt_root_squash(struct mdt_thread_info *info)
+static int match_nosquash_list(struct rw_semaphore *sem,
+ struct list_head *nidlist,
+ lnet_nid_t peernid)
{
- return 0;
+ int rc;
+ ENTRY;
+ down_read(sem);
+ rc = cfs_match_nid(peernid, nidlist);
+ up_read(sem);
+ RETURN(rc);
+}
+
+/* root_squash for inter-MDS operations */
+static int mdt_root_squash(struct mdt_thread_info *info, lnet_nid_t peernid)
+{
+ struct md_ucred *ucred = mdt_ucred(info);
+ ENTRY;
+
+ if (!info->mti_mdt->mdt_squash_uid || ucred->mu_fsuid)
+ RETURN(0);
+
+ if (match_nosquash_list(&info->mti_mdt->mdt_squash_sem,
+ &info->mti_mdt->mdt_nosquash_nids,
+ peernid)) {
+ CDEBUG(D_OTHER, "%s is in nosquash_nids list\n",
+ libcfs_nid2str(peernid));
+ RETURN(0);
+ }
+
+ CDEBUG(D_OTHER, "squash req from %s, (%d:%d/%x)=>(%d:%d/%x)\n",
+ libcfs_nid2str(peernid),
+ ucred->mu_fsuid, ucred->mu_fsgid, ucred->mu_cap,
+ info->mti_mdt->mdt_squash_uid, info->mti_mdt->mdt_squash_gid,
+ 0);
+
+ ucred->mu_fsuid = info->mti_mdt->mdt_squash_uid;
+ ucred->mu_fsgid = info->mti_mdt->mdt_squash_gid;
+ ucred->mu_cap = 0;
+ ucred->mu_suppgids[0] = -1;
+ ucred->mu_suppgids[1] = -1;
+
+ RETURN(0);
}
static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type,
ucred->mu_fsuid = pud->pud_fsuid;
ucred->mu_fsgid = pud->pud_fsgid;
- /* XXX: need to process root_squash here. */
- mdt_root_squash(info);
+ /* process root_squash here. */
+ mdt_root_squash(info, peernid);
/* remove fs privilege for non-root user. */
if (ucred->mu_fsuid)
}
uc->mu_identity = identity;
- /* XXX: need to process root_squash here. */
- mdt_root_squash(info);
+ /* process root_squash here. */
+ mdt_root_squash(info, mdt_info_req(info)->rq_peer.nid);
/* remove fs privilege for non-root user. */
if (uc->mu_fsuid)
}
uc->mu_identity = identity;
- /* XXX: need to process root_squash here. */
- mdt_root_squash(info);
+ /* process root_squash here. */
+ mdt_root_squash(info, mdt_info_req(info)->rq_peer.nid);
/* remove fs privilege for non-root user. */
if (uc->mu_fsuid)
#include <lprocfs_status.h>
#include <lu_time.h>
#include "mdt_internal.h"
+#include <lnet/lib-lnet.h>
static const char *mdt_proc_names[LPROC_MDT_NR] = {
};
return count;
}
+static int lprocfs_rd_root_squash(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct obd_device *obd = data;
+ struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+ ENTRY;
+
+ return snprintf(page, count, "%u:%u\n", mdt->mdt_squash_uid,
+ mdt->mdt_squash_gid);
+}
+
+static int safe_strtoul(const char *str, char **endp, unsigned long *res)
+{
+ char n[24];
+
+ *res = simple_strtoul(str, endp, 0);
+ if (str == *endp)
+ return 1;
+
+ sprintf(n, "%lu", *res);
+ if (strncmp(n, str, *endp - str))
+ /* overflow */
+ return 1;
+ return 0;
+}
+
+static int lprocfs_wr_root_squash(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct obd_device *obd = data;
+ struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+ char kernbuf[50], *tmp, *end;
+ unsigned long uid, gid;
+ int nouid, nogid;
+ ENTRY;
+
+ if (count > (sizeof(kernbuf) - 1) ||
+ copy_from_user(kernbuf, buffer, count)) {
+ CWARN("%s: can't copy string to kernel space, "
+ "uid:gid is expected, "
+ "continue with %u:%u, "
+ "there will be 0:0 on MDS restart\n",
+ obd->obd_name, mdt->mdt_squash_uid,
+ mdt->mdt_squash_gid);
+ RETURN(count);
+ }
+
+ if (copy_from_user(kernbuf, buffer, count))
+ RETURN(-EFAULT);
+
+ kernbuf[count] = '\0';
+
+ nouid = nogid = 0;
+ if (safe_strtoul(buffer, &tmp, &uid)) {
+ uid = mdt->mdt_squash_uid;
+ nouid = 1;
+ }
+
+ /* skip ':' */
+ if (*tmp == ':') {
+ tmp++;
+ if (safe_strtoul(tmp, &end, &gid)) {
+ gid = mdt->mdt_squash_gid;
+ nogid = 1;
+ }
+ } else {
+ gid = mdt->mdt_squash_gid;
+ nogid = 1;
+ }
+
+ mdt->mdt_squash_uid = uid;
+ mdt->mdt_squash_gid = gid;
+
+ if (nouid || nogid)
+ CWARN("%s: can't parse \"\%s\", uid:gid is expected, "
+ "continue with %u:%u, "
+ "there will be %u:%u on MDS restart\n",
+ obd->obd_name,
+ buffer, mdt->mdt_squash_uid, mdt->mdt_squash_gid,
+ nouid ? 0 : mdt->mdt_squash_uid,
+ nogid ? 0 : mdt->mdt_squash_gid);
+ else
+ LCONSOLE_INFO("%s: root_squash is set to %u:%u\n",
+ obd->obd_name,
+ mdt->mdt_squash_uid, mdt->mdt_squash_gid);
+ RETURN(count);
+}
+
+static int lprocfs_rd_nosquash_nids(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct obd_device *obd = data;
+ struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+
+ if (mdt->mdt_nosquash_str)
+ return snprintf(page, count, "%s\n", mdt->mdt_nosquash_str);
+ return snprintf(page, count, "NONE\n");
+}
+
+static int lprocfs_wr_nosquash_nids(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct obd_device *obd = data;
+ struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+ int rc;
+ char *new;
+ struct list_head tmp;
+ ENTRY;
+
+ /* copy to kernel space */
+ OBD_ALLOC(new, count + 1);
+ if (new == 0)
+ GOTO(failed, rc = -ENOMEM);
+
+ if (copy_from_user(new, buffer, count))
+ GOTO(failed, rc = -EFAULT);
+
+ new[count] = 0;
+ if (strlen(new) != count)
+ GOTO(failed, rc = -EINVAL);
+
+ if (!strcmp(new, "NONE") || !strcmp(new, "clear")) {
+ /* empty string is special case */
+ down_write(&mdt->mdt_squash_sem);
+ if (!list_empty(&mdt->mdt_nosquash_nids)) {
+ cfs_free_nidlist(&mdt->mdt_nosquash_nids);
+ OBD_FREE(mdt->mdt_nosquash_str,
+ mdt->mdt_nosquash_strlen);
+ mdt->mdt_nosquash_str = NULL;
+ mdt->mdt_nosquash_strlen = 0;
+ }
+ up_write(&mdt->mdt_squash_sem);
+ LCONSOLE_INFO("%s: nosquash_nids is cleared\n",
+ obd->obd_name);
+ OBD_FREE(new, count + 1);
+ RETURN(0);
+ }
+
+ CFS_INIT_LIST_HEAD(&tmp);
+ if (cfs_parse_nidlist(new, count, &tmp) <= 0)
+ GOTO(failed, rc = -EINVAL);
+
+ down_write(&mdt->mdt_squash_sem);
+ if (!list_empty(&mdt->mdt_nosquash_nids)) {
+ cfs_free_nidlist(&mdt->mdt_nosquash_nids);
+ OBD_FREE(mdt->mdt_nosquash_str, mdt->mdt_nosquash_strlen);
+ }
+ mdt->mdt_nosquash_str = new;
+ mdt->mdt_nosquash_strlen = count + 1;
+ list_splice(&tmp, &mdt->mdt_nosquash_nids);
+
+ LCONSOLE_INFO("%s: nosquash_nids is set to %s\n", obd->obd_name, new);
+ up_write(&mdt->mdt_squash_sem);
+ RETURN(count);
+
+ failed:
+ CWARN("%s: failed to set nosquash_nids (rc %d), "
+ "on MDS restart we will try to set it again, "
+ "continue with current nosquash_nids\n",
+ obd->obd_name, rc);
+ if (new)
+ OBD_FREE(new, count + 1);
+ RETURN(count);
+}
+
static struct lprocfs_vars lprocfs_mdt_obd_vars[] = {
{ "uuid", lprocfs_rd_uuid, 0, 0 },
{ "recovery_status", lprocfs_obd_rd_recovery_status, 0, 0 },
{ "sec_level", lprocfs_rd_sec_level,
lprocfs_wr_sec_level, 0 },
{ "commit_on_sharing", lprocfs_rd_cos, lprocfs_wr_cos, 0 },
+ { "root_squash", lprocfs_rd_root_squash,
+ lprocfs_wr_root_squash, 0 },
+ { "nosquash_nids", lprocfs_rd_nosquash_nids,
+ lprocfs_wr_nosquash_nids, 0 },
{ 0 }
};
GOTO(end, rc);
}
- /* All mdt., ost. params in proc */
- if ((class_match_param(ptr, PARAM_MDT, NULL) == 0) ||
- (class_match_param(ptr, PARAM_MDD, NULL) == 0) ||
+ /* All mdt. params in proc */
+ if (class_match_param(ptr, PARAM_MDT, NULL) == 0) {
+ char mdt_index[16];
+ int i;
+ __u32 idx;
+
+ CDEBUG(D_MGS, "%.3s param %s\n", ptr, ptr + 4);
+ if (strncmp(mti->mti_svname, mti->mti_fsname,
+ MTI_NAME_MAXLEN) == 0)
+ /* device is unspecified completely? */
+ rc = LDD_F_SV_TYPE_MDT | LDD_F_SV_ALL;
+ else
+ rc = server_name2index(mti->mti_svname, &idx, NULL);
+ if (rc < 0)
+ goto active_err;
+ if ((rc & LDD_F_SV_TYPE_MDT) == 0)
+ goto active_err;
+ if (rc & LDD_F_SV_ALL) {
+ for (i = 0; i < INDEX_MAP_SIZE * 8; i++) {
+ if (!test_bit(i,
+ fsdb->fsdb_mdt_index_map))
+ continue;
+ sprintf(mdt_index,"-MDT%04x", i);
+ name_create(&logname, mti->mti_fsname,
+ mdt_index);
+ rc = mgs_wlp_lcfg(obd, fsdb, mti,
+ logname, &bufs,
+ logname, ptr);
+ name_destroy(&logname);
+ if (rc)
+ goto active_err;
+ }
+ } else {
+ rc = mgs_wlp_lcfg(obd, fsdb, mti,
+ mti->mti_svname, &bufs,
+ mti->mti_svname, ptr);
+ if (rc)
+ goto active_err;
+ }
+ GOTO(end, rc);
+ }
+
+ /* All mdd., ost. params in proc */
+ if ((class_match_param(ptr, PARAM_MDD, NULL) == 0) ||
(class_match_param(ptr, PARAM_OST, NULL) == 0)) {
CDEBUG(D_MGS, "%.3s param %s\n", ptr, ptr + 4);
if (mgs_log_is_empty(obd, mti->mti_svname))
rc = LDD_F_SV_TYPE_OST;
else
return(-EINVAL);
+ if (strcmp(dash + 4, "all") == 0)
+ return rc | LDD_F_SV_ALL;
index = simple_strtoul(dash + 4, endptr, 16);
*idx = index;