X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fmdd%2Fmdd_permission.c;h=1ce1fe590ec651d72f8fee587134cb061ae5f524;hb=a42a91c783903ea15ad902032166c7e312dad7ee;hp=b74872bac128551138ff3dd346d982795ee7152d;hpb=04898c5e480faa12522570d8aa184eb02e79fc59;p=fs%2Flustre-release.git diff --git a/lustre/mdd/mdd_permission.c b/lustre/mdd/mdd_permission.c index b74872b..1ce1fe5 100644 --- a/lustre/mdd/mdd_permission.c +++ b/lustre/mdd/mdd_permission.c @@ -15,17 +15,15 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. + * + * Copyright (c) 2012, 2015, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -45,39 +43,12 @@ #include #include #include - +#include #include "mdd_internal.h" #ifdef CONFIG_FS_POSIX_ACL /* - * Get default acl EA only. - * Hold read_lock for mdd_obj. - */ -int mdd_def_acl_get(const struct lu_env *env, struct mdd_object *mdd_obj, - struct md_attr *ma) -{ - struct lu_buf *buf; - int rc; - ENTRY; - - if (ma->ma_valid & MA_ACL_DEF) - RETURN(0); - - buf = mdd_buf_get(env, ma->ma_acl, ma->ma_acl_size); - rc = mdo_xattr_get(env, mdd_obj, buf, XATTR_NAME_ACL_DEFAULT, - BYPASS_CAPA); - if (rc > 0) { - ma->ma_acl_size = rc; - ma->ma_valid |= MA_ACL_DEF; - rc = 0; - } else if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) { - rc = 0; - } - RETURN(rc); -} - -/* * Hold write_lock for o. */ int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, @@ -94,7 +65,7 @@ int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, sizeof(mdd_env_info(env)->mti_xattr_buf)); - rc = mdo_xattr_get(env, o, buf, XATTR_NAME_ACL_ACCESS, BYPASS_CAPA); + rc = mdo_xattr_get(env, o, buf, XATTR_NAME_ACL_ACCESS); if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) RETURN(0); else if (rc <= 0) @@ -113,27 +84,23 @@ int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, RETURN(rc); rc = mdo_xattr_set(env, o, buf, XATTR_NAME_ACL_ACCESS, - 0, handle, BYPASS_CAPA); + 0, handle); RETURN(rc); } int mdd_acl_set(const struct lu_env *env, struct mdd_object *obj, - const struct lu_buf *buf, int fl) + struct lu_attr *la, const struct lu_buf *buf, int fl) { struct mdd_device *mdd = mdd_obj2mdd_dev(obj); - struct lu_attr *la = &mdd_env_info(env)->mti_la; struct thandle *handle; posix_acl_xattr_header *head; posix_acl_xattr_entry *entry; - int rc, entry_count; + int entry_count; bool not_equiv, mode_change; mode_t mode; + int rc; ENTRY; - rc = mdd_la_get(env, obj, la, BYPASS_CAPA); - if (rc) - RETURN(rc); - head = (posix_acl_xattr_header *)(buf->lb_buf); entry = head->a_entries; entry_count = (buf->lb_len - sizeof(head->a_version)) / @@ -166,6 +133,7 @@ int mdd_acl_set(const struct lu_env *env, struct mdd_object *obj, if (mode_change) { la->la_mode = mode; + la->la_valid = LA_MODE; rc = mdo_declare_attr_set(env, obj, la, handle); } @@ -177,151 +145,125 @@ int mdd_acl_set(const struct lu_env *env, struct mdd_object *obj, /* whether ACL can be represented by i_mode only */ if (not_equiv) rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_ACCESS, fl, - handle, mdd_object_capa(env, obj)); + handle); else - rc = mdo_xattr_del(env, obj, XATTR_NAME_ACL_ACCESS, handle, - mdd_object_capa(env, obj)); + rc = mdo_xattr_del(env, obj, XATTR_NAME_ACL_ACCESS, handle); if (rc) GOTO(unlock, rc); if (mode_change) - rc = mdo_attr_set(env, obj, la, handle, - mdd_object_capa(env, obj)); + rc = mdo_attr_set(env, obj, la, handle); /* security-replated changes may require sync */ - handle->th_sync |= !!mdd->mdd_sync_permission; + if (S_ISDIR(mdd_object_type(obj))) + handle->th_sync |= !!mdd->mdd_sync_permission; unlock: mdd_write_unlock(env, obj); stop: - mdd_trans_stop(env, mdd, rc, handle); + rc = mdd_trans_stop(env, mdd, rc, handle); RETURN(rc); } -/* - * Hold write_lock for obj. - */ -int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj, - struct lu_buf *buf, __u32 *mode, struct thandle *handle) +/** + * Fix mode and ACL according to the default ACL(buf) + * \retval = 0 ACL does not need to be reset. + * \retval = 1 ACL needs to be reset. + * \retval < 0 error. + **/ +int __mdd_fix_mode_acl(const struct lu_env *env, struct lu_buf *buf, + __u32 *mode) { - posix_acl_xattr_header *head; - posix_acl_xattr_entry *entry; - int entry_count; - __u32 old = *mode; - int rc, rc2; - - ENTRY; - - head = (posix_acl_xattr_header *)(buf->lb_buf); - entry = head->a_entries; - entry_count = (buf->lb_len - sizeof(head->a_version)) / - sizeof(posix_acl_xattr_entry); - if (entry_count <= 0) - RETURN(0); + posix_acl_xattr_header *head; + posix_acl_xattr_entry *entry; + int entry_count; + int rc; - if (S_ISDIR(*mode)) { - rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_DEFAULT, 0, - handle, BYPASS_CAPA); - if (rc) - RETURN(rc); - } + ENTRY; - rc = lustre_posix_acl_create_masq(entry, mode, entry_count); - if (rc < 0) - RETURN(rc); - - /* part of ACL went into i_mode */ - if (*mode != old) { - struct mdd_thread_info *info = mdd_env_info(env); - struct lu_attr *pattr = &info->mti_pattr; - - /* mode was initialized within object creation, - * so we need explict ->attr_set() to update it */ - pattr->la_valid = LA_MODE; - pattr->la_mode = *mode; - rc2 = mdo_attr_set(env, obj, pattr, handle, BYPASS_CAPA); - if (rc2 < 0) - rc = rc2; - } + head = (posix_acl_xattr_header *)(buf->lb_buf); + entry = head->a_entries; + entry_count = (buf->lb_len - sizeof(head->a_version)) / + sizeof(posix_acl_xattr_entry); + if (entry_count <= 0) + RETURN(0); + + rc = lustre_posix_acl_create_masq(entry, mode, entry_count); - if (rc > 0) - rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_ACCESS, 0, - handle, BYPASS_CAPA); RETURN(rc); } + #endif /* * Hold read_lock for obj. */ static int mdd_check_acl(const struct lu_env *env, struct mdd_object *obj, - struct lu_attr *la, int mask) + const struct lu_attr *la, int mask) { #ifdef CONFIG_FS_POSIX_ACL - struct md_ucred *uc = md_ucred(env); - posix_acl_xattr_header *head; - posix_acl_xattr_entry *entry; - struct lu_buf *buf; - int entry_count; - int rc; - ENTRY; - - buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, - sizeof(mdd_env_info(env)->mti_xattr_buf)); - rc = mdo_xattr_get(env, obj, buf, XATTR_NAME_ACL_ACCESS, - mdd_object_capa(env, obj)); - if (rc <= 0) - RETURN(rc ? : -EACCES); - - buf->lb_len = rc; - head = (posix_acl_xattr_header *)(buf->lb_buf); - entry = head->a_entries; - entry_count = (buf->lb_len - sizeof(head->a_version)) / - sizeof(posix_acl_xattr_entry); - - rc = lustre_posix_acl_permission(uc, la, mask, entry, entry_count); - RETURN(rc); + struct lu_ucred *uc = lu_ucred_assert(env); + posix_acl_xattr_header *head; + posix_acl_xattr_entry *entry; + struct lu_buf *buf; + int entry_count; + int rc; + ENTRY; + + buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, + sizeof(mdd_env_info(env)->mti_xattr_buf)); + rc = mdo_xattr_get(env, obj, buf, XATTR_NAME_ACL_ACCESS); + if (rc <= 0) + RETURN(rc ? : -EACCES); + + buf->lb_len = rc; + head = (posix_acl_xattr_header *)(buf->lb_buf); + entry = head->a_entries; + entry_count = posix_acl_xattr_count(buf->lb_len); + + /* Disregard empty ACLs and fall back to + * standard UNIX permissions. See LU-5434 */ + if (entry_count <= 0) + RETURN(-EAGAIN); + + rc = lustre_posix_acl_permission(uc, la, mask, entry, entry_count); + RETURN(rc); #else - ENTRY; - RETURN(-EAGAIN); + ENTRY; + RETURN(-EAGAIN); #endif } int __mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj, - struct lu_attr *la, int mask, int role) + const struct lu_attr *la, int mask, int role) { - struct md_ucred *uc = md_ucred(env); - __u32 mode; - int rc; - ENTRY; + struct lu_ucred *uc = lu_ucred(env); + __u32 mode; + int rc; + ENTRY; - if (mask == 0) - RETURN(0); + if (mask == 0) + RETURN(0); - /* These means unnecessary for permission check */ - if ((uc == NULL) || (uc->mu_valid == UCRED_INIT)) - RETURN(0); + /* These means unnecessary for permission check */ + if ((uc == NULL) || (uc->uc_valid == UCRED_INIT)) + RETURN(0); - /* Invalid user credit */ - if (uc->mu_valid == UCRED_INVALID) - RETURN(-EACCES); - - /* - * Nobody gets write access to an immutable file. - */ - if ((mask & MAY_WRITE) && mdd_is_immutable(obj)) - RETURN(-EACCES); - - if (la == NULL) { - la = &mdd_env_info(env)->mti_la; - rc = mdd_la_get(env, obj, la, BYPASS_CAPA); - if (rc) - RETURN(rc); - } + /* Invalid user credit */ + if (uc->uc_valid == UCRED_INVALID) + RETURN(-EACCES); - mode = la->la_mode; - if (uc->mu_fsuid == la->la_uid) { - mode >>= 6; + /* + * Nobody gets write access to an immutable file. + */ + if (mask & MAY_WRITE && la->la_flags & LUSTRE_IMMUTABLE_FL) + RETURN(-EACCES); + + LASSERT(la != NULL); + + mode = la->la_mode; + if (uc->uc_fsuid == la->la_uid) { + mode >>= 6; } else { if (mode & S_IRWXG) { if (role != -1) @@ -343,126 +285,66 @@ int __mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj, RETURN(0); check_capabilities: - if (!(mask & MAY_EXEC) || - (la->la_mode & S_IXUGO) || S_ISDIR(la->la_mode)) - if (mdd_capable(uc, CFS_CAP_DAC_OVERRIDE)) - RETURN(0); + if (!(mask & MAY_EXEC) || + (la->la_mode & S_IXUGO) || S_ISDIR(la->la_mode)) + if (md_capable(uc, CFS_CAP_DAC_OVERRIDE)) + RETURN(0); + + if ((mask == MAY_READ) || + (S_ISDIR(la->la_mode) && !(mask & MAY_WRITE))) + if (md_capable(uc, CFS_CAP_DAC_READ_SEARCH)) + RETURN(0); - if ((mask == MAY_READ) || - (S_ISDIR(la->la_mode) && !(mask & MAY_WRITE))) - if (mdd_capable(uc, CFS_CAP_DAC_READ_SEARCH)) - RETURN(0); + CDEBUG(D_SEC, "permission denied, mode %x, fsuid %u, uid %u\n", + la->la_mode, uc->uc_fsuid, la->la_uid); - RETURN(-EACCES); + RETURN(-EACCES); } int mdd_permission(const struct lu_env *env, struct md_object *pobj, struct md_object *cobj, struct md_attr *ma, int mask) { - struct mdd_object *mdd_pobj, *mdd_cobj; - struct md_ucred *uc = NULL; - struct lu_attr *la = &mdd_env_info(env)->mti_cattr; - int check_create, check_link; - int check_unlink; - int check_rename_src, check_rename_tar; - int check_vtx_part, check_vtx_full; - int check_rgetfacl; - int rc = 0; - ENTRY; - - LASSERT(cobj); - mdd_cobj = md2mdd_obj(cobj); - - rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA); + struct mdd_object *mdd_pobj = NULL; + struct mdd_object *mdd_cobj; + struct lu_ucred *uc = NULL; + struct lu_attr *pattr = NULL; + struct lu_attr *cattr = MDD_ENV_VAR(env, cattr); + int rc = 0; + ENTRY; + + LASSERT(cobj); + if (pobj != NULL) { + mdd_pobj = md2mdd_obj(pobj); + pattr = MDD_ENV_VAR(env, pattr); + rc = mdd_la_get(env, mdd_pobj, pattr); + if (rc) + RETURN(rc); + } + + mdd_cobj = md2mdd_obj(cobj); + rc = mdd_la_get(env, mdd_cobj, cattr); if (rc) RETURN(rc); - /* For cross_open case, the "mask" is open flags, - * so convert it to permission mask first. - * XXX: MDS_OPEN_CROSS must be NOT equal to permission mask MAY_*. */ + /* For cross_open case, the "mask" is open flags, + * so convert it to permission mask first. + * XXX: MDS_OPEN_CROSS must be NOT equal to permission mask MAY_*. */ if (unlikely(mask & MDS_OPEN_CROSS)) - mask = accmode(env, la, mask & ~MDS_OPEN_CROSS); - - check_create = mask & MAY_CREATE; - check_link = mask & MAY_LINK; - check_unlink = mask & MAY_UNLINK; - check_rename_src = mask & MAY_RENAME_SRC; - check_rename_tar = mask & MAY_RENAME_TAR; - check_vtx_part = mask & MAY_VTX_PART; - check_vtx_full = mask & MAY_VTX_FULL; - check_rgetfacl = mask & MAY_RGETFACL; - - mask &= ~(MAY_CREATE | MAY_LINK | - MAY_UNLINK | - MAY_RENAME_SRC | MAY_RENAME_TAR | - MAY_VTX_PART | MAY_VTX_FULL | - MAY_RGETFACL); - - rc = mdd_permission_internal_locked(env, mdd_cobj, NULL, mask, - MOR_TGT_CHILD); - - if (!rc && (check_create || check_link)) - rc = mdd_may_create(env, mdd_cobj, NULL, 1, check_link); - - if (!rc && check_unlink) - rc = mdd_may_unlink(env, mdd_cobj, la); - - if (!rc && (check_rename_src || check_rename_tar)) { - LASSERT(pobj); - mdd_pobj = md2mdd_obj(pobj); - rc = mdd_may_delete(env, mdd_pobj, mdd_cobj, la, NULL, 1, - check_rename_tar); - } - - if (!rc && (check_vtx_part || check_vtx_full)) { - uc = md_ucred(env); - if (likely(!la)) { - la = &mdd_env_info(env)->mti_la; - rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA); - if (rc) - RETURN(rc); - } - - if (!(la->la_mode & S_ISVTX) || (la->la_uid == uc->mu_fsuid) || - (check_vtx_full && (ma->ma_attr.la_valid & LA_UID) && - (ma->ma_attr.la_uid == uc->mu_fsuid))) { - ma->ma_attr_flags |= MDS_VTX_BYPASS; - } else { - ma->ma_attr_flags &= ~MDS_VTX_BYPASS; - if (check_vtx_full) - rc = -EPERM; - } - } + mask = accmode(env, cattr, mask & ~MDS_OPEN_CROSS); - if (unlikely(!rc && check_rgetfacl)) { - if (likely(!uc)) - uc = md_ucred(env); + rc = mdd_permission_internal_locked(env, mdd_cobj, cattr, + mask & ~MAY_RGETFACL, + MOR_TGT_CHILD); - if (la->la_uid != uc->mu_fsuid && - !mdd_capable(uc, CFS_CAP_FOWNER)) - rc = -EPERM; - } - - RETURN(rc); -} + if (unlikely(rc == 0 && (mask & MAY_RGETFACL))) { + if (likely(!uc)) + uc = lu_ucred_assert(env); -int mdd_capa_get(const struct lu_env *env, struct md_object *obj, - struct lustre_capa *capa, int renewal) -{ - struct mdd_object *mdd_obj = md2mdd_obj(obj); - struct obd_capa *oc; - int rc = 0; - ENTRY; - - oc = mdo_capa_get(env, mdd_obj, renewal ? capa : NULL, - capa->lc_opc); - if (IS_ERR(oc)) { - rc = PTR_ERR(oc); - } else if (likely(oc != NULL)) { - capa_cpy(capa, oc); - capa_put(oc); - } + if (cattr->la_uid != uc->uc_fsuid && + !md_capable(uc, CFS_CAP_FOWNER)) + rc = -EPERM; + } - RETURN(rc); + RETURN(rc); }