From 3064318df90ce7019b83c8a7f80e93a9634c00fa Mon Sep 17 00:00:00 2001 From: Gregoire Pichon Date: Thu, 13 Feb 2014 16:33:34 +0100 Subject: [PATCH] LU-1778 llite: fix inconsistencies of root squash feature Root squash exhibits inconsistent behaviour on a client when enabled. If a file is not cached on the client, then root will get a permission denied error when accessing the file. When the file has recently been accessed by a regular user and is still in cache, root will be able to access the file without error because the permission check is only done by the client that isn't aware of root squash. While the only real security benefit from root squash is to deny clients access to files owned by root itself, it also makes sense to treat file access on the client in a consistent manner regardless of whether the file is in cache or not. This patch adds root squash settings to llite so that client is able to apply root squashing when it is relevant. Configuration of MDT root squash settings will automatically be applied to llite config log as well. Update cfs_str2num_check() routine by removing any modification of the specified string parameter. Since string can come from ls_str field of a lstr structure, this avoids inconsistent ls_len field. Signed-off-by: Gregoire Pichon Change-Id: Ie52d04424d0937af9fed777a4e4912c90405c19b Reviewed-on: http://review.whamcloud.com/5700 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Niu Yawei Reviewed-by: Oleg Drokin --- libcfs/libcfs/libcfs_string.c | 1 - lustre/include/lprocfs_status.h | 6 ++ lustre/include/obd_class.h | 9 ++ lustre/llite/file.c | 54 ++++++++++-- lustre/llite/llite_internal.h | 6 ++ lustre/llite/llite_lib.c | 60 +++++++++++-- lustre/llite/lproc_llite.c | 69 +++++++++++++++ lustre/mdt/mdt_handler.c | 17 ++-- lustre/mdt/mdt_internal.h | 7 +- lustre/mdt/mdt_lib.c | 24 ++--- lustre/mdt/mdt_lproc.c | 183 ++++++++------------------------------- lustre/mgs/mgs_llog.c | 89 ++++++++++++++----- lustre/obdclass/lprocfs_status.c | 133 ++++++++++++++++++++++++++++ lustre/tests/conf-sanity.sh | 53 +++++++++++- 14 files changed, 499 insertions(+), 212 deletions(-) diff --git a/libcfs/libcfs/libcfs_string.c b/libcfs/libcfs/libcfs_string.c index ae6a9e3..4ef54fa 100644 --- a/libcfs/libcfs/libcfs_string.c +++ b/libcfs/libcfs/libcfs_string.c @@ -326,7 +326,6 @@ cfs_str2num_check(char *str, int nob, unsigned *num, { char *endp; - str = cfs_trimwhite(str); *num = strtoul(str, &endp, 0); if (endp == str) return 0; diff --git a/lustre/include/lprocfs_status.h b/lustre/include/lprocfs_status.h index 0d6fd4c..42cec9e 100644 --- a/lustre/include/lprocfs_status.h +++ b/lustre/include/lprocfs_status.h @@ -975,6 +975,12 @@ ssize_t lprocfs_obd_max_pages_per_rpc_seq_write(struct file *file, const char *buffer, size_t count, loff_t *off); +struct root_squash_info; +int lprocfs_wr_root_squash(const char *buffer, unsigned long count, + struct root_squash_info *squash, char *name); +int lprocfs_wr_nosquash_nids(const char *buffer, unsigned long count, + struct root_squash_info *squash, char *name); + /* all quota proc functions */ extern int lprocfs_quota_rd_bunit(char *page, char **start, off_t off, int count, diff --git a/lustre/include/obd_class.h b/lustre/include/obd_class.h index 8db8904..b5e2ab5 100644 --- a/lustre/include/obd_class.h +++ b/lustre/include/obd_class.h @@ -2102,6 +2102,15 @@ void class_exit_uuidlist(void); /* prng.c */ #define ll_generate_random_uuid(uuid_out) cfs_get_random_bytes(uuid_out, sizeof(class_uuid_t)) +/* root squash info */ +struct rw_semaphore; +struct root_squash_info { + uid_t rsi_uid; + gid_t rsi_gid; + struct list_head rsi_nosquash_nids; + struct rw_semaphore rsi_sem; +}; + #ifdef __KERNEL__ int server_name2index(const char *svname, __u32 *idx, const char **endptr); #else diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 99dc465..8b4e3a3 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -45,6 +45,7 @@ #include #include #include +#include #include "llite_internal.h" #include #include @@ -3507,8 +3508,14 @@ int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd) # endif #endif { - int rc = 0; - ENTRY; + int rc = 0; + struct ll_sb_info *sbi; + struct root_squash_info *squash; + struct cred *cred = NULL; + const struct cred *old_cred = NULL; + cfs_cap_t cap; + bool squash_id = false; + ENTRY; #ifdef MAY_NOT_BLOCK if (mask & MAY_NOT_BLOCK) @@ -3531,11 +3538,46 @@ int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd) CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), inode mode %x mask %o\n", PFID(ll_inode2fid(inode)), inode, inode->i_mode, mask); - if (ll_i2sbi(inode)->ll_flags & LL_SBI_RMT_CLIENT) - return lustre_check_remote_perm(inode, mask); + /* squash fsuid/fsgid if needed */ + sbi = ll_i2sbi(inode); + squash = &sbi->ll_squash; + if (unlikely(squash->rsi_uid != 0 && + current_fsuid() == 0 && + !(sbi->ll_flags & LL_SBI_NOROOTSQUASH))) { + squash_id = true; + } + if (squash_id) { + CDEBUG(D_OTHER, "squash creds (%d:%d)=>(%d:%d)\n", + current_fsuid(), current_fsgid(), + squash->rsi_uid, squash->rsi_gid); + + /* update current process's credentials + * and FS capability */ + cred = prepare_creds(); + if (cred == NULL) + RETURN(-ENOMEM); - ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_INODE_PERM, 1); - rc = ll_generic_permission(inode, mask, flags, ll_check_acl); + cred->fsuid = squash->rsi_uid; + cred->fsgid = squash->rsi_gid; + for (cap = 0; cap < sizeof(cfs_cap_t) * 8; cap++) { + if ((1 << cap) & CFS_CAP_FS_MASK) + cap_lower(cred->cap_effective, cap); + } + old_cred = override_creds(cred); + } + + ll_stats_ops_tally(sbi, LPROC_LL_INODE_PERM, 1); + + if (sbi->ll_flags & LL_SBI_RMT_CLIENT) + rc = lustre_check_remote_perm(inode, mask); + else + rc = ll_generic_permission(inode, mask, flags, ll_check_acl); + + /* restore current process's credentials and FS capability */ + if (squash_id) { + revert_creds(old_cred); + put_cred(cred); + } RETURN(rc); } diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index 71ebd55..edebe5d 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -429,6 +429,7 @@ enum stats_track_type { #define LL_SBI_LAYOUT_LOCK 0x20000 /* layout lock support */ #define LL_SBI_USER_FID2PATH 0x40000 /* allow fid2path by unprivileged users */ #define LL_SBI_XATTR_CACHE 0x80000 /* support for xattr cache */ +#define LL_SBI_NOROOTSQUASH 0x100000 /* do not apply root squash */ #define LL_SBI_FLAGS { \ "nolck", \ @@ -451,6 +452,7 @@ enum stats_track_type { "layout", \ "user_fid2path",\ "xattr", \ + "norootsquash", \ } #define RCE_HASHES 32 @@ -549,6 +551,9 @@ struct ll_sb_info { * clustred nfs */ struct rmtacl_ctl_table ll_rct; struct eacl_table ll_et; + + /* root squash */ + struct root_squash_info ll_squash; }; #define LL_DEFAULT_MAX_RW_CHUNK (32 * 1024 * 1024) @@ -885,6 +890,7 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, void ll_finish_md_op_data(struct md_op_data *op_data); int ll_get_obd_name(struct inode *inode, unsigned int cmd, unsigned long arg); char *ll_get_fsname(struct super_block *sb, char *buf, int buflen); +void ll_compute_rootsquash_state(struct ll_sb_info *sbi); /* llite/llite_nfs.c */ extern struct export_operations lustre_export_operations; diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index e3dda71e..9b09581 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -71,14 +71,14 @@ static struct ll_sb_info *ll_init_sbi(void) struct ll_sb_info *sbi = NULL; unsigned long pages; unsigned long lru_page_max; - struct sysinfo si; - class_uuid_t uuid; - int i; - ENTRY; + struct sysinfo si; + class_uuid_t uuid; + int i; + ENTRY; - OBD_ALLOC(sbi, sizeof(*sbi)); - if (!sbi) - RETURN(NULL); + OBD_ALLOC_PTR(sbi); + if (sbi == NULL) + RETURN(NULL); spin_lock_init(&sbi->ll_lock); mutex_init(&sbi->ll_lco.lco_lock); @@ -139,6 +139,12 @@ static struct ll_sb_info *ll_init_sbi(void) atomic_set(&sbi->ll_agl_total, 0); sbi->ll_flags |= LL_SBI_AGL_ENABLED; + /* root squash */ + sbi->ll_squash.rsi_uid = 0; + sbi->ll_squash.rsi_gid = 0; + INIT_LIST_HEAD(&sbi->ll_squash.rsi_nosquash_nids); + init_rwsem(&sbi->ll_squash.rsi_sem); + RETURN(sbi); } @@ -151,6 +157,8 @@ static void ll_free_sbi(struct super_block *sb) spin_lock(&ll_sb_lock); list_del(&sbi->ll_list); spin_unlock(&ll_sb_lock); + if (!list_empty(&sbi->ll_squash.rsi_nosquash_nids)) + cfs_free_nidlist(&sbi->ll_squash.rsi_nosquash_nids); OBD_FREE(sbi, sizeof(*sbi)); } EXIT; @@ -2733,3 +2741,41 @@ void ll_dirty_page_discard_warn(struct page *page, int ioret) if (buf != NULL) free_page((unsigned long)buf); } + +/* + * Compute llite root squash state after a change of root squash + * configuration setting or add/remove of a lnet nid + */ +void ll_compute_rootsquash_state(struct ll_sb_info *sbi) +{ + struct root_squash_info *squash = &sbi->ll_squash; + int i; + bool matched; + lnet_process_id_t id; + + /* Update norootsquash flag */ + down_write(&squash->rsi_sem); + if (list_empty(&squash->rsi_nosquash_nids)) + sbi->ll_flags &= ~LL_SBI_NOROOTSQUASH; + else { + /* Do not apply root squash as soon as one of our NIDs is + * in the nosquash_nids list */ + matched = false; + i = 0; + while (LNetGetId(i++, &id) != -ENOENT) { + if (LNET_NETTYP(LNET_NIDNET(id.nid)) == LOLND) + continue; + if (cfs_match_nid(id.nid, &squash->rsi_nosquash_nids)) { + matched = true; + break; + } + } + if (matched) + sbi->ll_flags |= LL_SBI_NOROOTSQUASH; + else + sbi->ll_flags &= ~LL_SBI_NOROOTSQUASH; + } + up_write(&squash->rsi_sem); +} + + diff --git a/lustre/llite/lproc_llite.c b/lustre/llite/lproc_llite.c index 97cfc09..8595822 100644 --- a/lustre/llite/lproc_llite.c +++ b/lustre/llite/lproc_llite.c @@ -831,6 +831,71 @@ static int ll_unstable_stats_seq_show(struct seq_file *m, void *v) } LPROC_SEQ_FOPS_RO(ll_unstable_stats); +static int ll_root_squash_seq_show(struct seq_file *m, void *v) +{ + struct super_block *sb = m->private; + struct ll_sb_info *sbi = ll_s2sbi(sb); + struct root_squash_info *squash = &sbi->ll_squash; + + return seq_printf(m, "%u:%u\n", squash->rsi_uid, squash->rsi_gid); +} + +static ssize_t ll_root_squash_seq_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *off) +{ + struct seq_file *m = file->private_data; + struct super_block *sb = m->private; + struct ll_sb_info *sbi = ll_s2sbi(sb); + struct root_squash_info *squash = &sbi->ll_squash; + + return lprocfs_wr_root_squash(buffer, count, squash, + ll_get_fsname(sb, NULL, 0)); +} +LPROC_SEQ_FOPS(ll_root_squash); + +static int ll_nosquash_nids_seq_show(struct seq_file *m, void *v) +{ + struct super_block *sb = m->private; + struct ll_sb_info *sbi = ll_s2sbi(sb); + struct root_squash_info *squash = &sbi->ll_squash; + int len, rc; + + down_read(&squash->rsi_sem); + if (!list_empty(&squash->rsi_nosquash_nids)) { + len = cfs_print_nidlist(m->buf + m->count, m->size - m->count, + &squash->rsi_nosquash_nids); + m->count += len; + rc = seq_printf(m, "\n"); + } else { + rc = seq_printf(m, "NONE\n"); + } + up_read(&squash->rsi_sem); + + return rc; +} + +static ssize_t ll_nosquash_nids_seq_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *off) +{ + struct seq_file *m = file->private_data; + struct super_block *sb = m->private; + struct ll_sb_info *sbi = ll_s2sbi(sb); + struct root_squash_info *squash = &sbi->ll_squash; + int rc; + + rc = lprocfs_wr_nosquash_nids(buffer, count, squash, + ll_get_fsname(sb, NULL, 0)); + if (rc < 0) + return rc; + + ll_compute_rootsquash_state(sbi); + + return rc; +} +LPROC_SEQ_FOPS(ll_nosquash_nids); + struct lprocfs_seq_vars lprocfs_llite_obd_vars[] = { { .name = "uuid", .fops = &ll_sb_uuid_fops }, @@ -892,6 +957,10 @@ struct lprocfs_seq_vars lprocfs_llite_obd_vars[] = { .fops = &ll_xattr_cache_fops }, { .name = "unstable_stats", .fops = &ll_unstable_stats_fops }, + { .name = "root_squash", + .fops = &ll_root_squash_fops }, + { .name = "nosquash_nids", + .fops = &ll_nosquash_nids_fops }, { 0 } }; diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index 8f4c86d..0c9ab85 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -4369,12 +4369,7 @@ static void mdt_fini(const struct lu_env *env, struct mdt_device *m) mdt_quota_fini(env, m); - 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; - } + cfs_free_nidlist(&m->mdt_squash.rsi_nosquash_nids); mdt_seq_fini(env, m); mdt_fld_fini(env, m); @@ -4460,12 +4455,10 @@ static int mdt_init0(const struct lu_env *env, struct mdt_device *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); + m->mdt_squash.rsi_uid = 0; + m->mdt_squash.rsi_gid = 0; + INIT_LIST_HEAD(&m->mdt_squash.rsi_nosquash_nids); + init_rwsem(&m->mdt_squash.rsi_sem); spin_lock_init(&m->mdt_osfs_lock); m->mdt_osfs_age = cfs_time_shift_64(-1000); m->mdt_enable_remote_dir = 0; diff --git a/lustre/mdt/mdt_internal.h b/lustre/mdt/mdt_internal.h index bce5d12..116d98f 100644 --- a/lustre/mdt/mdt_internal.h +++ b/lustre/mdt/mdt_internal.h @@ -219,12 +219,7 @@ struct mdt_device { spinlock_t mdt_osfs_lock; /* root squash */ - uid_t mdt_squash_uid; - gid_t mdt_squash_gid; - cfs_list_t mdt_nosquash_nids; - char *mdt_nosquash_str; - int mdt_nosquash_strlen; - struct rw_semaphore mdt_squash_sem; + struct root_squash_info mdt_squash; struct rename_stats mdt_rename_stats; struct lu_fid mdt_md_root_fid; diff --git a/lustre/mdt/mdt_lib.c b/lustre/mdt/mdt_lib.c index 1c60854..eb839a6 100644 --- a/lustre/mdt/mdt_lib.c +++ b/lustre/mdt/mdt_lib.c @@ -95,28 +95,28 @@ static int match_nosquash_list(struct rw_semaphore *sem, static int mdt_root_squash(struct mdt_thread_info *info, lnet_nid_t peernid) { struct lu_ucred *ucred = mdt_ucred(info); + struct root_squash_info *squash = &info->mti_mdt->mdt_squash; ENTRY; LASSERT(ucred != NULL); - if (!info->mti_mdt->mdt_squash_uid || ucred->uc_fsuid) + if (!squash->rsi_uid || ucred->uc_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); - } + if (match_nosquash_list(&squash->rsi_sem, + &squash->rsi_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->uc_fsuid, ucred->uc_fsgid, ucred->uc_cap, - info->mti_mdt->mdt_squash_uid, info->mti_mdt->mdt_squash_gid, - 0); + squash->rsi_uid, squash->rsi_gid, 0); - ucred->uc_fsuid = info->mti_mdt->mdt_squash_uid; - ucred->uc_fsgid = info->mti_mdt->mdt_squash_gid; + ucred->uc_fsuid = squash->rsi_uid; + ucred->uc_fsgid = squash->rsi_gid; ucred->uc_cap = 0; ucred->uc_suppgids[0] = -1; ucred->uc_suppgids[1] = -1; diff --git a/lustre/mdt/mdt_lproc.c b/lustre/mdt/mdt_lproc.c index 2603c79..70eba85 100644 --- a/lustre/mdt/mdt_lproc.c +++ b/lustre/mdt/mdt_lproc.c @@ -688,169 +688,58 @@ static int lprocfs_wr_cos(struct file *file, const char __user *buffer, return count; } -static int lprocfs_rd_root_squash(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int lprocfs_rd_mdt_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); + struct obd_device *obd = data; + struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); + struct root_squash_info *squash = &mdt->mdt_squash; - return snprintf(page, count, "%u:%u\n", mdt->mdt_squash_uid, - mdt->mdt_squash_gid); + return snprintf(page, count, "%u:%u\n", squash->rsi_uid, + squash->rsi_gid); } -static int safe_strtoul(const char *str, char **endp, unsigned long *res) +static int lprocfs_wr_mdt_root_squash(struct file *file, + const char __user *buffer, + unsigned long count, void *data) { - char n[24]; - - *res = simple_strtoul(str, endp, 0); - if (str == *endp) - return 1; + struct obd_device *obd = data; + struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); + struct root_squash_info *squash = &mdt->mdt_squash; - sprintf(n, "%lu", *res); - if (strncmp(n, str, *endp - str)) - /* overflow */ - return 1; - return 0; + return lprocfs_wr_root_squash(buffer, count, squash, + mdt_obd_name(mdt)); } -static int lprocfs_wr_root_squash(struct file *file, const char __user *buffer, - unsigned long count, void *data) +static int lprocfs_rd_mdt_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); + struct root_squash_info *squash = &mdt->mdt_squash; int rc; - char kernbuf[64], *tmp, *end, *errmsg; - unsigned long uid, gid; - int nouid, nogid; - ENTRY; - if (count >= sizeof(kernbuf)) { - errmsg = "string too long"; - GOTO(failed_noprint, rc = -EINVAL); - } - if (copy_from_user(kernbuf, buffer, count)) { - errmsg = "bad address"; - GOTO(failed_noprint, rc = -EFAULT); - } - kernbuf[count] = '\0'; + down_read(&squash->rsi_sem); + if (!list_empty(&squash->rsi_nosquash_nids)) { + rc = cfs_print_nidlist(page, count, &squash->rsi_nosquash_nids); + rc += snprintf(page + rc, count - rc, "\n"); + } else + rc = snprintf(page, count, "NONE\n"); + up_read(&squash->rsi_sem); - nouid = nogid = 0; - if (safe_strtoul(kernbuf, &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) { - errmsg = "needs uid:gid format"; - GOTO(failed, rc = -EINVAL); - } - - LCONSOLE_INFO("%s: root_squash is set to %u:%u\n", - mdt_obd_name(mdt), - mdt->mdt_squash_uid, mdt->mdt_squash_gid); - RETURN(count); - -failed: - CWARN("%s: failed to set root_squash to \"%s\", %s: rc %d\n", - mdt_obd_name(mdt), kernbuf, errmsg, rc); - RETURN(rc); -failed_noprint: - CWARN("%s: failed to set root_squash due to %s: rc %d\n", - mdt_obd_name(mdt), errmsg, rc); - RETURN(rc); + return rc; } -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 __user *buffer, - unsigned long count, void *data) +static int lprocfs_wr_mdt_nosquash_nids(struct file *file, + const char __user *buffer, + unsigned long count, void *data) { struct obd_device *obd = data; struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev); - int rc; - char *kernbuf, *errmsg; - cfs_list_t tmp; - ENTRY; - - OBD_ALLOC(kernbuf, count + 1); - if (kernbuf == NULL) { - errmsg = "no memory"; - GOTO(failed, rc = -ENOMEM); - } - if (copy_from_user(kernbuf, buffer, count)) { - errmsg = "bad address"; - GOTO(failed, rc = -EFAULT); - } - kernbuf[count] = '\0'; - - if (!strcmp(kernbuf, "NONE") || !strcmp(kernbuf, "clear")) { - /* empty string is special case */ - down_write(&mdt->mdt_squash_sem); - if (!cfs_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", - mdt_obd_name(mdt)); - OBD_FREE(kernbuf, count + 1); - RETURN(count); - } - - CFS_INIT_LIST_HEAD(&tmp); - if (cfs_parse_nidlist(kernbuf, count, &tmp) <= 0) { - errmsg = "can't parse"; - GOTO(failed, rc = -EINVAL); - } + struct root_squash_info *squash = &mdt->mdt_squash; - down_write(&mdt->mdt_squash_sem); - if (!cfs_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 = kernbuf; - mdt->mdt_nosquash_strlen = count + 1; - cfs_list_splice(&tmp, &mdt->mdt_nosquash_nids); - - LCONSOLE_INFO("%s: nosquash_nids is set to %s\n", - mdt_obd_name(mdt), kernbuf); - up_write(&mdt->mdt_squash_sem); - RETURN(count); - -failed: - CWARN("%s: failed to set nosquash_nids to \"%s\", %s: rc %d\n", - mdt_obd_name(mdt), kernbuf, errmsg, rc); - if (kernbuf) - OBD_FREE(kernbuf, count + 1); - RETURN(rc); + return lprocfs_wr_nosquash_nids(buffer, count, squash, + mdt_obd_name(mdt)); } static int lprocfs_rd_mdt_som(char *page, char **start, off_t off, @@ -1011,11 +900,11 @@ static struct lprocfs_vars lprocfs_mdt_obd_vars[] = { NULL, NULL, 0 }, { "commit_on_sharing", lprocfs_rd_cos, lprocfs_wr_cos, NULL, NULL, 0 }, - { "root_squash", lprocfs_rd_root_squash, - lprocfs_wr_root_squash, + { "root_squash", lprocfs_rd_mdt_root_squash, + lprocfs_wr_mdt_root_squash, NULL, NULL, 0 }, - { "nosquash_nids", lprocfs_rd_nosquash_nids, - lprocfs_wr_nosquash_nids, + { "nosquash_nids", lprocfs_rd_mdt_nosquash_nids, + lprocfs_wr_mdt_nosquash_nids, NULL, NULL, 0 }, { "som", lprocfs_rd_mdt_som, lprocfs_wr_mdt_som, diff --git a/lustre/mgs/mgs_llog.c b/lustre/mgs/mgs_llog.c index 753dcfc..55ffe90 100644 --- a/lustre/mgs/mgs_llog.c +++ b/lustre/mgs/mgs_llog.c @@ -3415,9 +3415,22 @@ static int mgs_write_log_param(const struct lu_env *env, if (rc) GOTO(end, rc); - CDEBUG(D_MGS, "%.3s param %s\n", ptr, ptr + 4); + /* Forbid direct update of llite root squash parameters. + * These parameters are indirectly set via the MDT settings. + * See (LU-1778) */ + if ((class_match_param(ptr, PARAM_LLITE, &tmp) == 0) && + ((memcmp(tmp, "root_squash=", 12) == 0) || + (memcmp(tmp, "nosquash_nids=", 14) == 0))) { + LCONSOLE_ERROR("%s: root squash parameters can only " + "be updated through MDT component\n", + mti->mti_fsname); + name_destroy(&cname); + GOTO(end, rc = -EINVAL); + } + + CDEBUG(D_MGS, "%.3s param %s\n", ptr, ptr + 4); - /* Modify client */ + /* Modify client */ rc = name_create(&logname, mti->mti_fsname, "-client"); if (rc) { name_destroy(&cname); @@ -3453,13 +3466,13 @@ static int mgs_write_log_param(const struct lu_env *env, } } } - name_destroy(&logname); - name_destroy(&cname); - GOTO(end, rc); - } + name_destroy(&logname); + name_destroy(&cname); + GOTO(end, rc); + } - /* All mdt. params in proc */ - if (class_match_param(ptr, PARAM_MDT, NULL) == 0) { + /* All mdt. params in proc */ + if (class_match_param(ptr, PARAM_MDT, &tmp) == 0) { int i; __u32 idx; @@ -3485,20 +3498,56 @@ static int mgs_write_log_param(const struct lu_env *env, goto active_err; rc = mgs_wlp_lcfg(env, mgs, fsdb, mti, logname, &mgi->mgi_bufs, - logname, ptr); - name_destroy(&logname); - if (rc) - goto active_err; - } - } else { + logname, ptr); + name_destroy(&logname); + if (rc) + goto active_err; + } + } else { + if ((memcmp(tmp, "root_squash=", 12) == 0) || + (memcmp(tmp, "nosquash_nids=", 14) == 0)) { + LCONSOLE_ERROR("%s: root squash parameters " + "cannot be applied to a single MDT\n", + mti->mti_fsname); + GOTO(end, rc = -EINVAL); + } rc = mgs_wlp_lcfg(env, mgs, fsdb, mti, mti->mti_svname, &mgi->mgi_bufs, - mti->mti_svname, ptr); - if (rc) - goto active_err; - } - GOTO(end, rc); - } + mti->mti_svname, ptr); + if (rc) + goto active_err; + } + + /* root squash settings are also applied to llite + * config log (see LU-1778) */ + if (rc == 0 && + ((memcmp(tmp, "root_squash=", 12) == 0) || + (memcmp(tmp, "nosquash_nids=", 14) == 0))) { + char *cname; + char *ptr2; + + rc = name_create(&cname, mti->mti_fsname, "-client"); + if (rc) + GOTO(end, rc); + rc = name_create(&logname, mti->mti_fsname, "-client"); + if (rc) { + name_destroy(&cname); + GOTO(end, rc); + } + rc = name_create(&ptr2, PARAM_LLITE, tmp); + if (rc) { + name_destroy(&cname); + name_destroy(&logname); + GOTO(end, rc); + } + rc = mgs_wlp_lcfg(env, mgs, fsdb, mti, logname, + &mgi->mgi_bufs, cname, ptr2); + name_destroy(&ptr2); + name_destroy(&logname); + name_destroy(&cname); + } + GOTO(end, rc); + } /* All mdd., ost. and osd. params in proc */ if ((class_match_param(ptr, PARAM_MDD, NULL) == 0) || diff --git a/lustre/obdclass/lprocfs_status.c b/lustre/obdclass/lprocfs_status.c index 938cb7a..dcc00a84 100644 --- a/lustre/obdclass/lprocfs_status.c +++ b/lustre/obdclass/lprocfs_status.c @@ -3748,4 +3748,137 @@ int lprocfs_obd_max_pages_per_rpc_seq_show(struct seq_file *m, void *data) return rc; } EXPORT_SYMBOL(lprocfs_obd_max_pages_per_rpc_seq_show); + +int lprocfs_wr_root_squash(const char __user *buffer, unsigned long count, + struct root_squash_info *squash, char *name) +{ + int rc; + char kernbuf[64], *tmp, *errmsg; + unsigned long uid, gid; + ENTRY; + + if (count >= sizeof(kernbuf)) { + errmsg = "string too long"; + GOTO(failed_noprint, rc = -EINVAL); + } + if (copy_from_user(kernbuf, buffer, count)) { + errmsg = "bad address"; + GOTO(failed_noprint, rc = -EFAULT); + } + kernbuf[count] = '\0'; + + /* look for uid gid separator */ + tmp = strchr(kernbuf, ':'); + if (tmp == NULL) { + errmsg = "needs uid:gid format"; + GOTO(failed, rc = -EINVAL); + } + *tmp = '\0'; + tmp++; + + /* parse uid */ + if (kstrtoul(kernbuf, 0, &uid) != 0) { + errmsg = "bad uid"; + GOTO(failed, rc = -EINVAL); + } + + /* parse gid */ + if (kstrtoul(tmp, 0, &gid) != 0) { + errmsg = "bad gid"; + GOTO(failed, rc = -EINVAL); + } + + squash->rsi_uid = uid; + squash->rsi_gid = gid; + + LCONSOLE_INFO("%s: root_squash is set to %u:%u\n", + name, squash->rsi_uid, squash->rsi_gid); + RETURN(count); + +failed: + if (tmp != NULL) { + tmp--; + *tmp = ':'; + } + CWARN("%s: failed to set root_squash to \"%s\", %s, rc = %d\n", + name, kernbuf, errmsg, rc); + RETURN(rc); +failed_noprint: + CWARN("%s: failed to set root_squash due to %s, rc = %d\n", + name, errmsg, rc); + RETURN(rc); +} +EXPORT_SYMBOL(lprocfs_wr_root_squash); + + +int lprocfs_wr_nosquash_nids(const char __user *buffer, unsigned long count, + struct root_squash_info *squash, char *name) +{ + int rc; + char *kernbuf = NULL; + char *errmsg; + struct list_head tmp; + ENTRY; + + if (count > 4096) { + errmsg = "string too long"; + GOTO(failed, rc = -EINVAL); + } + + OBD_ALLOC(kernbuf, count + 1); + if (kernbuf == NULL) { + errmsg = "no memory"; + GOTO(failed, rc = -ENOMEM); + } + if (copy_from_user(kernbuf, buffer, count)) { + errmsg = "bad address"; + GOTO(failed, rc = -EFAULT); + } + kernbuf[count] = '\0'; + + if (count > 0 && kernbuf[count - 1] == '\n') + kernbuf[count - 1] = '\0'; + + if (strcmp(kernbuf, "NONE") == 0 || strcmp(kernbuf, "clear") == 0) { + /* empty string is special case */ + down_write(&squash->rsi_sem); + if (!list_empty(&squash->rsi_nosquash_nids)) + cfs_free_nidlist(&squash->rsi_nosquash_nids); + up_write(&squash->rsi_sem); + LCONSOLE_INFO("%s: nosquash_nids is cleared\n", name); + OBD_FREE(kernbuf, count + 1); + RETURN(count); + } + + INIT_LIST_HEAD(&tmp); + if (cfs_parse_nidlist(kernbuf, count, &tmp) <= 0) { + errmsg = "can't parse"; + GOTO(failed, rc = -EINVAL); + } + LCONSOLE_INFO("%s: nosquash_nids set to %s\n", + name, kernbuf); + OBD_FREE(kernbuf, count + 1); + kernbuf = NULL; + + down_write(&squash->rsi_sem); + if (!list_empty(&squash->rsi_nosquash_nids)) + cfs_free_nidlist(&squash->rsi_nosquash_nids); + list_splice(&tmp, &squash->rsi_nosquash_nids); + up_write(&squash->rsi_sem); + + RETURN(count); + +failed: + if (kernbuf) { + CWARN("%s: failed to set nosquash_nids to \"%s\", %s rc = %d\n", + name, kernbuf, errmsg, rc); + OBD_FREE(kernbuf, count + 1); + } else { + CWARN("%s: failed to set nosquash_nids due to %s rc = %d\n", + name, errmsg, rc); + } + RETURN(rc); +} +EXPORT_SYMBOL(lprocfs_wr_nosquash_nids); + #endif /* LPROCFS*/ diff --git a/lustre/tests/conf-sanity.sh b/lustre/tests/conf-sanity.sh index cb29b9a..8595230 100644 --- a/lustre/tests/conf-sanity.sh +++ b/lustre/tests/conf-sanity.sh @@ -2587,16 +2587,30 @@ run_test 42 "allow client/server mount/unmount with invalid config param" test_43() { [ $UID -ne 0 -o $RUNAS_ID -eq 0 ] && skip_env "run as root" + + ID1=${ID1:-501} + USER1=$(cat /etc/passwd | grep :$ID1:$ID1: | cut -d: -f1) + [ -z "$USER1" ] && skip_env "missing user with uid=$ID1 gid=$ID1" && + return + setup chmod ugo+x $DIR || error "chmod 0 failed" set_conf_param_and_check mds \ "lctl get_param -n mdt.$FSNAME-MDT0000.root_squash" \ "$FSNAME.mdt.root_squash" \ "0:0" + wait_update $HOSTNAME \ + "lctl get_param -n llite.${FSNAME}*.root_squash" \ + "0:0" || + error "check llite root_squash failed!" set_conf_param_and_check mds \ "lctl get_param -n mdt.$FSNAME-MDT0000.nosquash_nids" \ "$FSNAME.mdt.nosquash_nids" \ "NONE" + wait_update $HOSTNAME \ + "lctl get_param -n llite.${FSNAME}*.nosquash_nids" \ + "NONE" || + error "check llite nosquash_nids failed!" # # create set of test files @@ -2612,6 +2626,10 @@ test_43() { chmod go-rwx $DIR/$tdir-rootdir || error "chmod 3 failed" touch $DIR/$tdir-rootdir/tfile-1 || error "touch failed" + echo "777" > $DIR/$tfile-user1file || error "write 7 failed" + chmod go-rw $DIR/$tfile-user1file || error "chmod 7 failed" + chown $ID1.$ID1 $DIR/$tfile-user1file || error "chown failed" + # # check root_squash: # set root squash UID:GID to RUNAS_ID @@ -2621,6 +2639,10 @@ test_43() { "lctl get_param -n mdt.$FSNAME-MDT0000.root_squash" \ "$FSNAME.mdt.root_squash" \ "$RUNAS_ID:$RUNAS_ID" + wait_update $HOSTNAME \ + "lctl get_param -n llite.${FSNAME}*.root_squash" \ + "$RUNAS_ID:$RUNAS_ID" || + error "check llite root_squash failed!" ST=$(stat -c "%n: owner uid %u (%A)" $DIR/$tfile-userfile) dd if=$DIR/$tfile-userfile 1>/dev/null 2>/dev/null || \ @@ -2628,7 +2650,7 @@ test_43() { echo "$ST: root read permission is granted - ok" echo "444" | \ - dd conv=notrunc if=$DIR/$tfile-userfile 1>/dev/null 2>/dev/null || \ + dd conv=notrunc of=$DIR/$tfile-userfile 1>/dev/null 2>/dev/null || \ error "$ST: root write permission is denied" echo "$ST: root write permission is granted - ok" @@ -2651,6 +2673,31 @@ test_43() { error "$ST: root create permission is granted" echo "$ST: root create permission is denied - ok" + + # LU-1778 + # check root_squash is enforced independently + # of client cache content + # + # access file by USER1, keep access open + # root should be denied access to user file + + runas -u $ID1 tail -f $DIR/$tfile-user1file 1>/dev/null 2>&1 & + pid=$! + sleep 1 + + ST=$(stat -c "%n: owner uid %u (%A)" $DIR/$tfile-user1file) + dd if=$DIR/$tfile-user1file 1>/dev/null 2>&1 && + { kill $pid; error "$ST: root read permission is granted"; } + echo "$ST: root read permission is denied - ok" + + echo "777" | \ + dd conv=notrunc of=$DIR/$tfile-user1file 1>/dev/null 2>&1 && + { kill $pid; error "$ST: root write permission is granted"; } + echo "$ST: root write permission is denied - ok" + + kill $pid + wait $pid + # # check nosquash_nids: # put client's NID into nosquash_nids list, @@ -2663,6 +2710,10 @@ test_43() { "lctl get_param -n mdt.$FSNAME-MDT0000.nosquash_nids" \ "$FSNAME-MDTall.mdt.nosquash_nids" \ "$NIDLIST" + wait_update $HOSTNAME \ + "lctl get_param -n llite.${FSNAME}*.nosquash_nids" \ + "$NIDLIST" || + error "check llite nosquash_nids failed!" ST=$(stat -c "%n: owner uid %u (%A)" $DIR/$tfile-rootfile) dd if=$DIR/$tfile-rootfile 1>/dev/null 2>/dev/null || \ -- 1.8.3.1