diff --git a/config/spl-build.m4 b/config/spl-build.m4 index 35cc8e4012..79fcd25486 100644 --- a/config/spl-build.m4 +++ b/config/spl-build.m4 @@ -64,6 +64,8 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [ SPL_AC_ZONE_STAT_ITEM_FIA SPL_AC_2ARGS_VFS_UNLINK SPL_AC_4ARGS_VFS_RENAME + SPL_AC_CRED_STRUCT + SPL_AC_GROUPS_SEARCH ]) AC_DEFUN([SPL_AC_MODULE_SYMVERS], [ @@ -1099,3 +1101,34 @@ AC_DEFUN([SPL_AC_4ARGS_VFS_RENAME], AC_MSG_RESULT(no) ]) ]) + +dnl # +dnl # 2.6.29 API change, +dnl # check whether 'struct cred' exists +dnl # +AC_DEFUN([SPL_AC_CRED_STRUCT], [ + AC_MSG_CHECKING([whether struct cred exists]) + SPL_LINUX_TRY_COMPILE([ + #include + ],[ + struct cred *cr; + cr = NULL; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_CRED_STRUCT, 1, [struct cred exists]) + ],[ + AC_MSG_RESULT(no) + ]) +]) + +dnl # +dnl # Custom SPL patch may export this symbol +dnl # +AC_DEFUN([SPL_AC_GROUPS_SEARCH], [ + SPL_CHECK_SYMBOL_EXPORT( + [groups_search], + [], + [AC_DEFINE(HAVE_GROUPS_SEARCH, 1, + [groups_search() is available])], + []) +]) diff --git a/configure b/configure index 5e3358490d..a342d73a23 100755 --- a/configure +++ b/configure @@ -21342,6 +21342,113 @@ fi + + echo "$as_me:$LINENO: checking whether struct cred exists" >&5 +echo $ECHO_N "checking whether struct cred exists... $ECHO_C" >&6 + + +cat >conftest.c <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + + #include + +int +main (void) +{ + + struct cred *cr; + cr = NULL; + + ; + return 0; +} + +_ACEOF + + + rm -Rf build && mkdir -p build + echo "obj-m := conftest.o" >build/Makefile + if { ac_try='cp conftest.c build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } >/dev/null && { ac_try='test -s build/conftest.o' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_CRED_STRUCT 1 +_ACEOF + + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + + + +fi + + rm -Rf build + + + + + echo "$as_me:$LINENO: checking whether symbol groups_search is exported" >&5 +echo $ECHO_N "checking whether symbol groups_search is exported... $ECHO_C" >&6 + grep -q -E '[[:space:]]groups_search[[:space:]]' \ + $LINUX_OBJ/Module*.symvers 2>/dev/null + rc=$? + if test $rc -ne 0; then + export=0 + for file in ; do + grep -q -E "EXPORT_SYMBOL.*(groups_search)" \ + "$LINUX_OBJ/$file" 2>/dev/null + rc=$? + if test $rc -eq 0; then + export=1 + break; + fi + done + if test $export -eq 0; then + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + + else + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_GROUPS_SEARCH 1 +_ACEOF + + fi + else + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_GROUPS_SEARCH 1 +_ACEOF + + fi + + ;; user) ;; all) @@ -23736,6 +23843,113 @@ fi + echo "$as_me:$LINENO: checking whether struct cred exists" >&5 +echo $ECHO_N "checking whether struct cred exists... $ECHO_C" >&6 + + +cat >conftest.c <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + + #include + +int +main (void) +{ + + struct cred *cr; + cr = NULL; + + ; + return 0; +} + +_ACEOF + + + rm -Rf build && mkdir -p build + echo "obj-m := conftest.o" >build/Makefile + if { ac_try='cp conftest.c build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } >/dev/null && { ac_try='test -s build/conftest.o' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_CRED_STRUCT 1 +_ACEOF + + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + + + +fi + + rm -Rf build + + + + + echo "$as_me:$LINENO: checking whether symbol groups_search is exported" >&5 +echo $ECHO_N "checking whether symbol groups_search is exported... $ECHO_C" >&6 + grep -q -E '[[:space:]]groups_search[[:space:]]' \ + $LINUX_OBJ/Module*.symvers 2>/dev/null + rc=$? + if test $rc -ne 0; then + export=0 + for file in ; do + grep -q -E "EXPORT_SYMBOL.*(groups_search)" \ + "$LINUX_OBJ/$file" 2>/dev/null + rc=$? + if test $rc -eq 0; then + export=1 + break; + fi + done + if test $export -eq 0; then + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + + else + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_GROUPS_SEARCH 1 +_ACEOF + + fi + else + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_GROUPS_SEARCH 1 +_ACEOF + + fi + + + ;; *) echo "$as_me:$LINENO: result: Error!" >&5 diff --git a/include/splat-ctl.h b/include/splat-ctl.h index 7f49b9ffff..fc68395e81 100644 --- a/include/splat-ctl.h +++ b/include/splat-ctl.h @@ -105,6 +105,7 @@ typedef struct splat_cmd { #define SPLAT_SUBSYSTEM_ATOMIC 0x0b00 #define SPLAT_SUBSYSTEM_LIST 0x0c00 #define SPLAT_SUBSYSTEM_GENERIC 0x0d00 +#define SPLAT_SUBSYSTEM_CRED 0x0e00 #define SPLAT_SUBSYSTEM_UNKNOWN 0xff00 #endif /* _SPLAT_CTL_H */ diff --git a/include/sys/cred.h b/include/sys/cred.h index 47eeda2cb0..9717b66bc8 100644 --- a/include/sys/cred.h +++ b/include/sys/cred.h @@ -9,69 +9,33 @@ extern "C" { #include #include -/* XXX - Portions commented out because we really just want to have the type - * defined and the contents aren't nearly so important at the moment. */ -typedef struct cred { - uint_t cr_ref; /* reference count */ - uid_t cr_uid; /* effective user id */ - gid_t cr_gid; /* effective group id */ - uid_t cr_ruid; /* real user id */ - gid_t cr_rgid; /* real group id */ - uid_t cr_suid; /* "saved" user id (from exec) */ - gid_t cr_sgid; /* "saved" group id (from exec) */ - uint_t cr_ngroups; /* number of groups returned by */ - /* crgroups() */ -#if 0 - cred_priv_t cr_priv; /* privileges */ - projid_t cr_projid; /* project */ - struct zone *cr_zone; /* pointer to per-zone structure */ - struct ts_label_s *cr_label; /* pointer to the effective label */ - credsid_t *cr_ksid; /* pointer to SIDs */ -#endif - gid_t cr_groups[1]; /* cr_groups size not fixed */ - /* audit info is defined dynamically */ - /* and valid only when audit enabled */ - /* auditinfo_addr_t cr_auinfo; audit info */ -} cred_t; +#ifdef HAVE_CRED_STRUCT -#define kcred NULL -#define CRED() NULL +typedef struct cred cred_t; -static __inline__ uid_t -crgetuid(cred_t *cr) -{ - return 0; -} +#define kcred ((cred_t *)(init_task.cred)) +#define CRED() ((cred_t *)current_cred()) -static __inline__ gid_t -crgetgid(cred_t *cr) -{ - return 0; -} +#else -static __inline__ int -crgetngroups(cred_t *cr) -{ - return 0; -} +typedef struct task_struct cred_t; -static __inline__ gid_t * -crgetgroups(cred_t *cr) -{ - return NULL; -} +#define kcred ((cred_t *)&init_task) +#define CRED() ((cred_t *)current) -static __inline__ int -groupmember(gid_t gid, const cred_t *cr) -{ - /* Primary group check */ - if ((cr) && (gid == cr->cr_gid)) - return 1; - - /* Supplemental group check (unsupported) */ - return 0; -} +#endif /* HAVE_CRED_STRUCT */ +extern void crhold(cred_t *cr); +extern void crfree(cred_t *cr); +extern uid_t crgetuid(const cred_t *cr); +extern uid_t crgetruid(const cred_t *cr); +extern uid_t crgetsuid(const cred_t *cr); +extern gid_t crgetgid(const cred_t *cr); +extern gid_t crgetrgid(const cred_t *cr); +extern gid_t crgetsgid(const cred_t *cr); +extern int crgetngroups(const cred_t *cr); +extern gid_t * crgetgroups(const cred_t *cr); +extern int groupmember(gid_t gid, const cred_t *cr); #ifdef __cplusplus } diff --git a/include/sys/debug.h b/include/sys/debug.h index f19231b903..8da76863c6 100644 --- a/include/sys/debug.h +++ b/include/sys/debug.h @@ -53,6 +53,7 @@ extern unsigned long spl_debug_subsys; #define S_GENERIC 0x00002000 #define S_PROC 0x00004000 #define S_MODULE 0x00008000 +#define S_CRED 0x00010000 #define D_TRACE 0x00000001 #define D_INFO 0x00000002 diff --git a/module/spl/Makefile.in b/module/spl/Makefile.in index e9c8d34708..ad29af4066 100644 --- a/module/spl/Makefile.in +++ b/module/spl/Makefile.in @@ -23,3 +23,4 @@ spl-objs += spl-mutex.o spl-objs += spl-kstat.o spl-objs += spl-condvar.o spl-objs += spl-xdr.o +spl-objs += spl-cred.o diff --git a/module/spl/spl-cred.c b/module/spl/spl-cred.c new file mode 100644 index 0000000000..c5994aa205 --- /dev/null +++ b/module/spl/spl-cred.c @@ -0,0 +1,308 @@ +/* + * This file is part of the SPL: Solaris Porting Layer. + * + * Copyright (c) 2009 Lawrence Livermore National Security, LLC. + * Produced at Lawrence Livermore National Laboratory + * Written by: + * Brian Behlendorf , + * UCRL-CODE-235197 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#ifdef DEBUG_SUBSYSTEM +#undef DEBUG_SUBSYSTEM +#endif + +#define DEBUG_SUBSYSTEM S_CRED + +#ifdef HAVE_GROUPS_SEARCH +/* Symbol may be exported by custom kernel patch */ +#define cr_groups_search(gi, grp) groups_search(gi, grp) +#else +/* Implementation from 2.6.30 kernel */ +static int +cr_groups_search(const struct group_info *group_info, gid_t grp) +{ + unsigned int left, right; + + if (!group_info) + return 0; + + left = 0; + right = group_info->ngroups; + while (left < right) { + unsigned int mid = (left+right)/2; + int cmp = grp - GROUP_AT(group_info, mid); + if (cmp > 0) + left = mid + 1; + else if (cmp < 0) + right = mid; + else + return 1; + } + return 0; +} +#endif + +#ifdef HAVE_CRED_STRUCT + +/* + * As of 2.6.29 a clean credential API appears in the linux kernel. + * We attempt to layer the Solaris API on top of the linux API. + */ + +/* Hold a reference on the credential and group info */ +void +crhold(cred_t *cr) +{ + (void)get_cred((const cred_t *)cr); + (void)get_group_info(cr->group_info); +} + +/* Free a reference on the credential and group info */ +void +crfree(cred_t *cr) +{ + put_group_info(cr->group_info); + put_cred((const cred_t *)cr); +} + +/* Return the effective user id */ +uid_t +crgetuid(const cred_t *cr) +{ + return cr->euid; +} + +/* Return the real user id */ +uid_t +crgetruid(const cred_t *cr) +{ + return cr->uid; +} + +/* Return the saved user id */ +uid_t +crgetsuid(const cred_t *cr) +{ + return cr->suid; +} + +/* Return the effective group id */ +gid_t +crgetgid(const cred_t *cr) +{ + return cr->egid; +} + +/* Return the real group id */ +gid_t +crgetrgid(const cred_t *cr) +{ + return cr->gid; +} + +/* Return the saved group id */ +gid_t +crgetsgid(const cred_t *cr) +{ + return cr->sgid; +} + +/* Return the number of supplemental groups */ +int +crgetngroups(const cred_t *cr) +{ + struct group_info *gi; + int rc; + + gi = get_group_info(cr->group_info); + rc = gi->ngroups; + put_group_info(gi); + + return rc; +} + +/* + * Return an array of supplemental gids. The returned address is safe + * to use as long as the caller has taken a reference with crhold(). + * The caller is responsible for releasing the reference with crfree(). + */ +gid_t * +crgetgroups(const cred_t *cr) +{ + struct group_info *gi; + gid_t *gids; + + gi = get_group_info(cr->group_info); + gids = gi->blocks[0]; + put_group_info(gi); + + return gids; +} + +/* Check if the passed gid is available is in supplied credential. */ +int +groupmember(gid_t gid, const cred_t *cr) +{ + struct group_info *gi; + int rc; + + gi = get_group_info(cr->group_info); + rc = cr_groups_search(cr->group_info, gid); + put_group_info(gi); + + return rc; +} + +#else /* HAVE_CRED_STRUCT */ + +/* + * Until very recently all credential information was embedded in + * the linux task struct. For this reason to simulate a Solaris + * cred_t we need to pass the entire task structure around. + */ + +/* Hold a reference on the credential and group info */ +void +crhold(cred_t *cr) +{ + get_task_struct(cr); +} + +/* Free a reference on the credential and group info */ +void +crfree(cred_t *cr) +{ + put_task_struct(cr); +} + +/* Return the effective user id */ +uid_t +crgetuid(const cred_t *cr) { + return cr->euid; +} + +/* Return the effective real id */ +uid_t +crgetruid(const cred_t *cr) { + return cr->uid; +} + +/* Return the effective saved id */ +uid_t +crgetsuid(const cred_t *cr) { + return cr->suid; +} + +/* Return the effective group id */ +gid_t +crgetgid(const cred_t *cr) { + return cr->egid; +} + +/* Return the real group id */ +gid_t +crgetrgid(const cred_t *cr) { + return cr->gid; +} + +/* Return the saved group id */ +gid_t +crgetsgid(const cred_t *cr) { + return cr->sgid; +} + +/* Return the number of supplemental groups */ +int +crgetngroups(const cred_t *cr) +{ + int lock, rc; + + lock = (cr != current); + if (lock) + task_lock((struct task_struct *)cr); + + get_group_info(cr->group_info); + rc = cr->group_info->ngroups; + put_group_info(cr->group_info); + + if (lock) + task_unlock((struct task_struct *)cr); + + return rc; +} + +/* + * Return an array of supplemental gids. The returned address is safe + * to use as long as the caller has taken a reference with crhold(). + * The caller is responsible for releasing the reference with crfree(). + */ +gid_t * +crgetgroups(const cred_t *cr) +{ + gid_t *gids; + int lock; + + lock = (cr != current); + if (lock) + task_lock((struct task_struct *)cr); + + get_group_info(cr->group_info); + gids = cr->group_info->blocks[0]; + put_group_info(cr->group_info); + + if (lock) + task_unlock((struct task_struct *)cr); + + return gids; +} + +/* Check if the passed gid is available is in supplied credential. */ +int +groupmember(gid_t gid, const cred_t *cr) +{ + int lock, rc; + + lock = (cr != current); + if (lock) + task_lock((struct task_struct *)cr); + + get_group_info(cr->group_info); + rc = cr_groups_search(cr->group_info, gid); + put_group_info(cr->group_info); + + if (lock) + task_unlock((struct task_struct *)cr); + + return rc; +} + +#endif /* HAVE_CRED_STRUCT */ + +EXPORT_SYMBOL(crhold); +EXPORT_SYMBOL(crfree); +EXPORT_SYMBOL(crgetuid); +EXPORT_SYMBOL(crgetruid); +EXPORT_SYMBOL(crgetsuid); +EXPORT_SYMBOL(crgetgid); +EXPORT_SYMBOL(crgetrgid); +EXPORT_SYMBOL(crgetsgid); +EXPORT_SYMBOL(crgetngroups); +EXPORT_SYMBOL(crgetgroups); +EXPORT_SYMBOL(groupmember); diff --git a/module/spl/spl-debug.c b/module/spl/spl-debug.c index a60740519f..6d71f4b829 100644 --- a/module/spl/spl-debug.c +++ b/module/spl/spl-debug.c @@ -157,6 +157,8 @@ spl_debug_subsys2str(int subsys) return "proc"; case S_MODULE: return "module"; + case S_CRED: + return "cred"; } } diff --git a/module/splat/Makefile.in b/module/splat/Makefile.in index c2d4c3f220..2f63b458a2 100644 --- a/module/splat/Makefile.in +++ b/module/splat/Makefile.in @@ -20,3 +20,4 @@ splat-objs += splat-kobj.o splat-objs += splat-atomic.o splat-objs += splat-list.o splat-objs += splat-generic.o +splat-objs += splat-cred.o diff --git a/module/splat/splat-cred.c b/module/splat/splat-cred.c new file mode 100644 index 0000000000..f808625e87 --- /dev/null +++ b/module/splat/splat-cred.c @@ -0,0 +1,247 @@ +/* + * This file is part of the SPL: Solaris Porting Layer. + * + * Copyright (c) 2009 Lawrence Livermore National Security, LLC. + * Produced at Lawrence Livermore National Laboratory + * Written by: + * Brian Behlendorf , + * UCRL-CODE-235197 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "splat-internal.h" + +#define SPLAT_CRED_NAME "cred" +#define SPLAT_CRED_DESC "Kernel Cred Tests" + +#define SPLAT_CRED_TEST1_ID 0x0e01 +#define SPLAT_CRED_TEST1_NAME "cred" +#define SPLAT_CRED_TEST1_DESC "Task Credential Test" + +#define SPLAT_CRED_TEST2_ID 0x0e02 +#define SPLAT_CRED_TEST2_NAME "kcred" +#define SPLAT_CRED_TEST2_DESC "Kernel Credential Test" + +#define SPLAT_CRED_TEST3_ID 0x0e03 +#define SPLAT_CRED_TEST3_NAME "groupmember" +#define SPLAT_CRED_TEST3_DESC "Group Member Test" + +#define GROUP_STR_SIZE 128 +#define GROUP_STR_REDZONE 16 + +static int +splat_cred_test1(struct file *file, void *arg) +{ + char str[GROUP_STR_SIZE]; + uid_t uid, ruid, suid; + gid_t gid, rgid, sgid, *groups; + int ngroups, i, count = 0; + + uid = crgetuid(CRED()); + ruid = crgetruid(CRED()); + suid = crgetsuid(CRED()); + + gid = crgetgid(CRED()); + rgid = crgetrgid(CRED()); + sgid = crgetsgid(CRED()); + + crhold(CRED()); + ngroups = crgetngroups(CRED()); + groups = crgetgroups(CRED()); + + memset(str, 0, GROUP_STR_SIZE); + for (i = 0; i < ngroups; i++) { + count += sprintf(str + count, "%d ", groups[i]); + + if (count > (GROUP_STR_SIZE - GROUP_STR_REDZONE)) { + splat_vprint(file, SPLAT_CRED_TEST1_NAME, + "Failed too many group entries for temp " + "buffer: %d, %s\n", ngroups, str); + return -ENOSPC; + } + } + + crfree(CRED()); + + splat_vprint(file, SPLAT_CRED_TEST1_NAME, + "uid: %d ruid: %d suid: %d " + "gid: %d rgid: %d sgid: %d\n", + uid, ruid, suid, gid, rgid, sgid); + splat_vprint(file, SPLAT_CRED_TEST1_NAME, + "ngroups: %d groups: %s\n", ngroups, str); + + if (uid || ruid || suid || gid || rgid || sgid) { + splat_vprint(file, SPLAT_CRED_TEST1_NAME, + "Failed expected all uids+gids to be %d\n", 0); + return -EIDRM; + } + + if (ngroups > NGROUPS_MAX) { + splat_vprint(file, SPLAT_CRED_TEST1_NAME, + "Failed ngroups must not exceed NGROUPS_MAX: " + "%d > %d\n", ngroups, NGROUPS_MAX); + return -EIDRM; + } + + splat_vprint(file, SPLAT_CRED_TEST1_NAME, + "Success sane CRED(): %d\n", 0); + + return 0; +} /* splat_cred_test1() */ + +static int +splat_cred_test2(struct file *file, void *arg) +{ + char str[GROUP_STR_SIZE]; + uid_t uid, ruid, suid; + gid_t gid, rgid, sgid, *groups; + int ngroups, i, count = 0; + + uid = crgetuid(kcred); + ruid = crgetruid(kcred); + suid = crgetsuid(kcred); + + gid = crgetgid(kcred); + rgid = crgetrgid(kcred); + sgid = crgetsgid(kcred); + + crhold(kcred); + ngroups = crgetngroups(kcred); + groups = crgetgroups(kcred); + + memset(str, 0, GROUP_STR_SIZE); + for (i = 0; i < ngroups; i++) { + count += sprintf(str + count, "%d ", groups[i]); + + if (count > (GROUP_STR_SIZE - GROUP_STR_REDZONE)) { + splat_vprint(file, SPLAT_CRED_TEST2_NAME, + "Failed too many group entries for temp " + "buffer: %d, %s\n", ngroups, str); + return -ENOSPC; + } + } + + crfree(kcred); + + splat_vprint(file, SPLAT_CRED_TEST2_NAME, + "uid: %d ruid: %d suid: %d " + "gid: %d rgid: %d sgid: %d\n", + uid, ruid, suid, gid, rgid, sgid); + splat_vprint(file, SPLAT_CRED_TEST2_NAME, + "ngroups: %d groups: %s\n", ngroups, str); + + if (uid || ruid || suid || gid || rgid || sgid) { + splat_vprint(file, SPLAT_CRED_TEST2_NAME, + "Failed expected all uids+gids to be %d\n", 0); + return -EIDRM; + } + + if (ngroups > NGROUPS_MAX) { + splat_vprint(file, SPLAT_CRED_TEST2_NAME, + "Failed ngroups must not exceed NGROUPS_MAX: " + "%d > %d\n", ngroups, NGROUPS_MAX); + return -EIDRM; + } + + splat_vprint(file, SPLAT_CRED_TEST2_NAME, + "Success sane kcred: %d\n", 0); + + return 0; +} /* splat_cred_test2() */ + +/* + * On most/all systems it can be expected that a task with root + * permissions also is a member of the root group, Since the + * test suite is always run as root we check first that CRED() is + * a member of the root group, and secondly that it is not a member + * of our fake group. This test will break is someone happens to + * create group number NGROUPS_MAX-1 and then added root to it. + */ +static int +splat_cred_test3(struct file *file, void *arg) +{ + gid_t root_gid, fake_gid; + int rc; + + root_gid = 0; + fake_gid = NGROUPS_MAX-1; + + rc = groupmember(root_gid, CRED()); + if (!rc) { + splat_vprint(file, SPLAT_CRED_TEST3_NAME, + "Failed root git %d expected to be member " + "of CRED() groups: %d\n", root_gid, rc); + return -EIDRM; + } + + rc = groupmember(fake_gid, CRED()); + if (rc) { + splat_vprint(file, SPLAT_CRED_TEST3_NAME, + "Failed fake git %d expected not to be member " + "of CRED() groups: %d\n", fake_gid, rc); + return -EIDRM; + } + + splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Success root gid " + "is a member of the expected groups: %d\n", rc); + + return rc; +} /* splat_cred_test3() */ + +splat_subsystem_t * +splat_cred_init(void) +{ + splat_subsystem_t *sub; + + sub = kmalloc(sizeof(*sub), GFP_KERNEL); + if (sub == NULL) + return NULL; + + memset(sub, 0, sizeof(*sub)); + strncpy(sub->desc.name, SPLAT_CRED_NAME, SPLAT_NAME_SIZE); + strncpy(sub->desc.desc, SPLAT_CRED_DESC, SPLAT_DESC_SIZE); + INIT_LIST_HEAD(&sub->subsystem_list); + INIT_LIST_HEAD(&sub->test_list); + spin_lock_init(&sub->test_lock); + sub->desc.id = SPLAT_SUBSYSTEM_CRED; + + SPLAT_TEST_INIT(sub, SPLAT_CRED_TEST1_NAME, SPLAT_CRED_TEST1_DESC, + SPLAT_CRED_TEST1_ID, splat_cred_test1); + SPLAT_TEST_INIT(sub, SPLAT_CRED_TEST2_NAME, SPLAT_CRED_TEST2_DESC, + SPLAT_CRED_TEST2_ID, splat_cred_test2); + SPLAT_TEST_INIT(sub, SPLAT_CRED_TEST3_NAME, SPLAT_CRED_TEST3_DESC, + SPLAT_CRED_TEST3_ID, splat_cred_test3); + + return sub; +} /* splat_cred_init() */ + +void +splat_cred_fini(splat_subsystem_t *sub) +{ + ASSERT(sub); + + SPLAT_TEST_FINI(sub, SPLAT_CRED_TEST3_ID); + SPLAT_TEST_FINI(sub, SPLAT_CRED_TEST2_ID); + SPLAT_TEST_FINI(sub, SPLAT_CRED_TEST1_ID); + + kfree(sub); +} /* splat_cred_fini() */ + +int +splat_cred_id(void) +{ + return SPLAT_SUBSYSTEM_CRED; +} /* splat_cred_id() */ diff --git a/module/splat/splat-ctl.c b/module/splat/splat-ctl.c index c8925636a1..1591039807 100644 --- a/module/splat/splat-ctl.c +++ b/module/splat/splat-ctl.c @@ -630,6 +630,7 @@ splat_init(void) SPLAT_SUBSYSTEM_INIT(atomic); SPLAT_SUBSYSTEM_INIT(list); SPLAT_SUBSYSTEM_INIT(generic); + SPLAT_SUBSYSTEM_INIT(cred); dev = MKDEV(SPLAT_MAJOR, 0); if ((rc = register_chrdev_region(dev, SPLAT_MINORS, SPLAT_NAME))) @@ -676,6 +677,7 @@ splat_fini(void) cdev_del(&splat_cdev); unregister_chrdev_region(dev, SPLAT_MINORS); + SPLAT_SUBSYSTEM_FINI(cred); SPLAT_SUBSYSTEM_FINI(generic); SPLAT_SUBSYSTEM_FINI(list); SPLAT_SUBSYSTEM_FINI(atomic); diff --git a/module/splat/splat-internal.h b/module/splat/splat-internal.h index 0fa177c029..c1c84d8d1c 100644 --- a/module/splat/splat-internal.h +++ b/module/splat/splat-internal.h @@ -208,6 +208,7 @@ splat_subsystem_t *splat_kobj_init(void); splat_subsystem_t *splat_atomic_init(void); splat_subsystem_t *splat_list_init(void); splat_subsystem_t *splat_generic_init(void); +splat_subsystem_t *splat_cred_init(void); void splat_condvar_fini(splat_subsystem_t *); void splat_kmem_fini(splat_subsystem_t *); @@ -222,6 +223,7 @@ void splat_kobj_fini(splat_subsystem_t *); void splat_atomic_fini(splat_subsystem_t *); void splat_list_fini(splat_subsystem_t *); void splat_generic_fini(splat_subsystem_t *); +void splat_cred_fini(splat_subsystem_t *); int splat_condvar_id(void); int splat_kmem_id(void); @@ -236,5 +238,6 @@ int splat_kobj_id(void); int splat_atomic_id(void); int splat_list_id(void); int splat_generic_id(void); +int splat_cred_id(void); #endif /* _SPLAT_INTERNAL_H */ diff --git a/spl_config.h.in b/spl_config.h.in index 3b07d993c6..582a47603a 100644 --- a/spl_config.h.in +++ b/spl_config.h.in @@ -36,6 +36,9 @@ /* class_device_create() is available */ #undef HAVE_CLASS_DEVICE_CREATE +/* struct cred exists */ +#undef HAVE_CRED_STRUCT + /* unnumbered sysctl support exists */ #undef HAVE_CTL_UNNUMBERED @@ -72,6 +75,9 @@ /* global_page_state() is available */ #undef HAVE_GLOBAL_PAGE_STATE +/* groups_search() is available */ +#undef HAVE_GROUPS_SEARCH + /* init_utsname() is available */ #undef HAVE_INIT_UTSNAME