X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=libcfs%2Flibcfs%2Flinux%2Flinux-curproc.c;h=fee47a23fc0a5654361607ce53c7fdda0a8256d8;hb=b1e7be00cb6e1e7b3e35877cf8b8a209e456a2ea;hp=eb12dae5463b8e02b7039b65cdef524087fce006;hpb=14c1444535f2474268741795fabcec8541741f31;p=fs%2Flustre-release.git diff --git a/libcfs/libcfs/linux/linux-curproc.c b/libcfs/libcfs/linux/linux-curproc.c index eb12dae..fee47a2 100644 --- a/libcfs/libcfs/linux/linux-curproc.c +++ b/libcfs/libcfs/linux/linux-curproc.c @@ -1,6 +1,4 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * +/* * GPL HEADER START * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -17,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 2008 Sun Microsystems, Inc. All rights reserved + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. + * + * Copyright (c) 2012, 2017, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -41,6 +37,14 @@ */ #include +#ifdef HAVE_SCHED_HEADERS +#include +#include +#endif +#include +#include +#include +#include #define DEBUG_SUBSYSTEM S_LNET @@ -51,134 +55,244 @@ * for Linux kernel. */ -uid_t cfs_curproc_uid(void) -{ - return current->uid; -} - -gid_t cfs_curproc_gid(void) -{ - return current->gid; -} +/* Currently all the CFS_CAP_* defines match CAP_* ones. */ +#define cfs_cap_pack(cap) (cap) +#define cfs_cap_unpack(cap) (cap) -uid_t cfs_curproc_fsuid(void) +void cfs_cap_raise(cfs_cap_t cap) { - return current->fsuid; + struct cred *cred; + if ((cred = prepare_creds())) { + cap_raise(cred->cap_effective, cfs_cap_unpack(cap)); + commit_creds(cred); + } } -gid_t cfs_curproc_fsgid(void) +void cfs_cap_lower(cfs_cap_t cap) { - return current->fsgid; + struct cred *cred; + if ((cred = prepare_creds())) { + cap_lower(cred->cap_effective, cfs_cap_unpack(cap)); + commit_creds(cred); + } } -pid_t cfs_curproc_pid(void) +int cfs_cap_raised(cfs_cap_t cap) { - return current->pid; + return cap_raised(current_cap(), cfs_cap_unpack(cap)); } -int cfs_curproc_groups_nr(void) +static void cfs_kernel_cap_pack(kernel_cap_t kcap, cfs_cap_t *cap) { - int nr; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4) - task_lock(current); - nr = current->group_info->ngroups; - task_unlock(current); +#if defined (_LINUX_CAPABILITY_VERSION) && _LINUX_CAPABILITY_VERSION == 0x19980330 + *cap = cfs_cap_pack(kcap); +#elif defined (_LINUX_CAPABILITY_VERSION) && _LINUX_CAPABILITY_VERSION == 0x20071026 + *cap = cfs_cap_pack(kcap[0]); +#elif defined(_KERNEL_CAPABILITY_VERSION) && _KERNEL_CAPABILITY_VERSION == 0x20080522 + /* XXX lost high byte */ + *cap = cfs_cap_pack(kcap.cap[0]); #else - nr = current->ngroups; + #error "need correct _KERNEL_CAPABILITY_VERSION " #endif - return nr; } -void cfs_curproc_groups_dump(gid_t *array, int size) +static void cfs_kernel_cap_unpack(kernel_cap_t *kcap, cfs_cap_t cap) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4) - task_lock(current); - size = min_t(int, size, current->group_info->ngroups); - memcpy(array, current->group_info->blocks[0], size * sizeof(__u32)); - task_unlock(current); +#if defined (_LINUX_CAPABILITY_VERSION) && _LINUX_CAPABILITY_VERSION == 0x19980330 + *kcap = cfs_cap_unpack(cap); +#elif defined (_LINUX_CAPABILITY_VERSION) && _LINUX_CAPABILITY_VERSION == 0x20071026 + (*kcap)[0] = cfs_cap_unpack(cap); +#elif defined(_KERNEL_CAPABILITY_VERSION) && _KERNEL_CAPABILITY_VERSION == 0x20080522 + kcap->cap[0] = cfs_cap_unpack(cap); #else - LASSERT(size <= NGROUPS); - size = min_t(int, size, current->ngroups); - memcpy(array, current->groups, size * sizeof(__u32)); + #error "need correct _KERNEL_CAPABILITY_VERSION " #endif } - -int cfs_curproc_is_in_groups(gid_t gid) +cfs_cap_t cfs_curproc_cap_pack(void) { - return in_group_p(gid); + cfs_cap_t cap; + cfs_kernel_cap_pack(current_cap(), &cap); + return cap; } -mode_t cfs_curproc_umask(void) +void cfs_curproc_cap_unpack(cfs_cap_t cap) { - return current->fs->umask; + struct cred *cred; + if ((cred = prepare_creds())) { + cfs_kernel_cap_unpack(&cred->cap_effective, cap); + commit_creds(cred); + } } -char *cfs_curproc_comm(void) +int cfs_capable(cfs_cap_t cap) { - return current->comm; + return capable(cfs_cap_unpack(cap)); } -/* Currently all the CFS_CAP_* defines match CAP_* ones. */ -#define cfs_cap_pack(cap) (cap) -#define cfs_cap_unpack(cap) (cap) - -void cfs_cap_raise(cfs_cap_t cap) +static int cfs_access_process_vm(struct task_struct *tsk, + struct mm_struct *mm, + unsigned long addr, + void *buf, int len, int write) { - cap_raise(cfs_current()->cap_effective, cfs_cap_unpack(cap)); -} + /* Just copied from kernel for the kernels which doesn't + * have access_process_vm() exported */ + struct vm_area_struct *vma; + struct page *page; + void *old_buf = buf; -void cfs_cap_lower(cfs_cap_t cap) -{ - cap_lower(cfs_current()->cap_effective, cfs_cap_unpack(cap)); -} + /* Avoid deadlocks on mmap_sem if called from sys_mmap_pgoff(), + * which is already holding mmap_sem for writes. If some other + * thread gets the write lock in the meantime, this thread will + * block, but at least it won't deadlock on itself. LU-1735 */ + if (down_read_trylock(&mm->mmap_sem) == 0) + return -EDEADLK; -int cfs_cap_raised(cfs_cap_t cap) -{ - return cap_raised(cfs_current()->cap_effective, cfs_cap_unpack(cap)); -} + /* ignore errors, just check how much was successfully transferred */ + while (len) { + int bytes, rc, offset; + void *maddr; -cfs_cap_t cfs_curproc_cap_pack(void) { -#if _LINUX_CAPABILITY_VERSION == 0x19980330 - return cfs_cap_pack(current->cap_effective); -#elif _LINUX_CAPABILITY_VERSION == 0x20071026 - return cfs_cap_pack(current->cap_effective[0]); +#if defined(HAVE_GET_USER_PAGES_GUP_FLAGS) + rc = get_user_pages(addr, 1, write ? FOLL_WRITE : 0, &page, &vma); +#elif defined(HAVE_GET_USER_PAGES_6ARG) + rc = get_user_pages(addr, 1, write, 1, &page, &vma); #else - #error "need correct _LINUX_CAPABILITY_VERSION " + rc = get_user_pages(tsk, mm, addr, 1, write, 1, &page, &vma); #endif -} + if (rc <= 0) + break; -void cfs_curproc_cap_unpack(cfs_cap_t cap) { -#if _LINUX_CAPABILITY_VERSION == 0x19980330 - current->cap_effective = cfs_cap_unpack(cap); -#elif _LINUX_CAPABILITY_VERSION == 0x20071026 - current->cap_effective[0] = cfs_cap_unpack(cap); -#else - #error "need correct _LINUX_CAPABILITY_VERSION " -#endif + bytes = len; + offset = addr & (PAGE_SIZE-1); + if (bytes > PAGE_SIZE-offset) + bytes = PAGE_SIZE-offset; + + maddr = kmap(page); + if (write) { + copy_to_user_page(vma, page, addr, + maddr + offset, buf, bytes); + set_page_dirty_lock(page); + } else { + copy_from_user_page(vma, page, addr, + buf, maddr + offset, bytes); + } + kunmap(page); + put_page(page); + len -= bytes; + buf += bytes; + addr += bytes; + } + up_read(&mm->mmap_sem); + + return buf - old_buf; } -int cfs_capable(cfs_cap_t cap) +/* Read the environment variable of current process specified by @key. */ +int cfs_get_environ(const char *key, char *value, int *val_len) { - return capable(cfs_cap_unpack(cap)); + struct mm_struct *mm; + char *buffer; + int buf_len = PAGE_SIZE; + int key_len = strlen(key); + unsigned long addr; + int rc; + bool skip = false; + ENTRY; + + buffer = kmalloc(buf_len, GFP_USER); + if (!buffer) + RETURN(-ENOMEM); + + mm = get_task_mm(current); + if (!mm) { + kfree(buffer); + RETURN(-EINVAL); + } + + addr = mm->env_start; + while (addr < mm->env_end) { + int this_len, retval, scan_len; + char *env_start, *env_end; + + memset(buffer, 0, buf_len); + + this_len = min_t(int, mm->env_end - addr, buf_len); + retval = cfs_access_process_vm(current, mm, addr, buffer, + this_len, 0); + if (retval < 0) + GOTO(out, rc = retval); + else if (retval != this_len) + break; + + addr += retval; + + /* Parse the buffer to find out the specified key/value pair. + * The "key=value" entries are separated by '\0'. */ + env_start = buffer; + scan_len = this_len; + while (scan_len) { + char *entry; + int entry_len; + + env_end = memscan(env_start, '\0', scan_len); + LASSERT(env_end >= env_start && + env_end <= env_start + scan_len); + + /* The last entry of this buffer cross the buffer + * boundary, reread it in next cycle. */ + if (unlikely(env_end - env_start == scan_len)) { + /* Just skip the entry larger than page size, + * it can't be jobID env variable. */ + if (unlikely(scan_len == this_len)) + skip = true; + else + addr -= scan_len; + break; + } else if (unlikely(skip)) { + skip = false; + goto skip; + } + + entry = env_start; + entry_len = env_end - env_start; + + /* Key length + length of '=' */ + if (entry_len > key_len + 1 && + !memcmp(entry, key, key_len)) { + entry += key_len + 1; + entry_len -= key_len + 1; + + /* The 'value' buffer passed in is too small. + * Copy what fits, but return -EOVERFLOW. */ + if (entry_len >= *val_len) { + memcpy(value, entry, *val_len); + value[*val_len - 1] = 0; + GOTO(out, rc = -EOVERFLOW); + } + + memcpy(value, entry, entry_len); + *val_len = entry_len; + GOTO(out, rc = 0); + } +skip: + scan_len -= (env_end - env_start + 1); + env_start = env_end + 1; + } + } + GOTO(out, rc = -ENOENT); + +out: + mmput(mm); + kfree((void *)buffer); + return rc; } +EXPORT_SYMBOL(cfs_get_environ); -EXPORT_SYMBOL(cfs_curproc_uid); -EXPORT_SYMBOL(cfs_curproc_pid); -EXPORT_SYMBOL(cfs_curproc_gid); -EXPORT_SYMBOL(cfs_curproc_fsuid); -EXPORT_SYMBOL(cfs_curproc_fsgid); -EXPORT_SYMBOL(cfs_curproc_umask); -EXPORT_SYMBOL(cfs_curproc_comm); -EXPORT_SYMBOL(cfs_curproc_groups_nr); -EXPORT_SYMBOL(cfs_curproc_groups_dump); -EXPORT_SYMBOL(cfs_curproc_is_in_groups); EXPORT_SYMBOL(cfs_cap_raise); EXPORT_SYMBOL(cfs_cap_lower); EXPORT_SYMBOL(cfs_cap_raised); EXPORT_SYMBOL(cfs_curproc_cap_pack); -EXPORT_SYMBOL(cfs_curproc_cap_unpack); EXPORT_SYMBOL(cfs_capable); /*