diff --git a/Documentation/rsbac/COPYING b/Documentation/rsbac/COPYING new file mode 100644 index 000000000000..7e082789ba80 --- /dev/null +++ b/Documentation/rsbac/COPYING @@ -0,0 +1,19 @@ +Copyright Notice +---------------- + +All RSBAC code is copyrighted by me (Amon Ott) unless specified otherwise, +and published under the restrictions of the GNU General Public Licence +as to be read in file COPYING in the main directory of the kernel source tree. +All statements therein apply fully to all RSBAC sources. + +RSBAC 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 software 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. + +Amon Ott diff --git a/Documentation/rsbac/Changes b/Documentation/rsbac/Changes new file mode 100644 index 000000000000..a294a49e0c4a --- /dev/null +++ b/Documentation/rsbac/Changes @@ -0,0 +1,709 @@ +RSBAC Changes +------------- +1.5.0: + - Port to 4.4 + - Remove ALLOW_DAC_DISABLE feature + - Add feature "Prevent memory write and execute (RSBAC mprotect)" + to enable the RSBAC prevention of process memory segments being both + writable and executable. + +1.4.9: + - Port to 3.12 and 3.14. + - debug_adf_rc|jail: only log, if rsbac_log_levels[request][target] != LL_none + - new JAIL flag JAIL_allow_netdev_mod_system, MODIFY_SYSTEM_DATA on NETDEV + - Do not check SEND_SIGNAL to a process that is already exiting. + - JAIL: DO_NOT_CARE about SIGCHLD signal to process outside jail + - Add kernel parameter rsbac_list_noread to avoid reading lists from disk. + - Make sys_rsbac_rc_set_item() work in softmode, if current role is undefined + +1.4.8: + - Remove PM module + - Add UDF module + - Various small fixes + +1.4.7: + - Port to kernel 3.10.1 + - Add optional MOVETO request with kernel config option: + used when moving into a dir instead of old WRITE on DIR target. + +1.4.6: + - Port everything to kernel 3.1.5 + - Show process name and parent when logging PROCESS target accesses + - Add RSBAC syscalls to get and set UM password history size per + user. + - Do not allow to set attributes for FD targets with + sys_rsbac_set_attr() + +1.4.5: + - Fix symlink's stat() call to return the real symlink size + Fixes program that would assert on stat->s_size being the same size as when using readlink() + - Remove use of task_capability_lock. + - Fixes FS object hidding for most cases (still experimental) + - Backport fixes and internal features from 1.5: + - Add generic list option to use a separate kmem cache / slab per list. + - Use that option for several lists, general ACI, RC, ACL, UM. + - rkmem.h: define RSBAC_MAX_KMALLOC KMALLOC_MAX_SIZE + - Do not create our kmem caches with SLAB_DESTROY_BY_RCU, not needed. + - Big cleanup of DAZ code. + - Make DAZ path subselection by scanners optional, default is on in 1.4. + - Change DAZ module filename allocation to fixed size slabs. + - Remove rsbac_get_full_path_length(), which is not used anywhere any more. + - Use fixed DAZ filename size PATH_MAX, defined in include/linux/limits.h. + - DAZ: allocate memory with _unlocked functions where possible. + - Put device items into own slabs. + - Fix memory leak in case of failed list rehashing. + - Fix notification for setuid() etc: move after commit_creds(). + - In Unix send and receive, use remote peercred.pid, if local is not available. + - Fix NULL pointer deref, if sk_socket is unset. + - Move SEND and RECEIVE for Unix sockets from net/socket.c to net/unix/af_inet.c. + - This makes interception code cleaner and more reliable, specially for named + sockets. + - Fix file_p handling in list read functions. + - Use mntget() instead of path_get() in rsbac_read_open(). + +1.4.4: + - Port to 2.6.33.2 + - Fix RC check for CREATE right on new objects. + - Backport rsbac_read_open() and rsbac_read_close() fixes from 1.5. + +1.4.3: + - Depend CONFIG_RSBAC_RC_LEARN on CONFIG_RSBAC_DEBUG. + - Show transaction number in learning info messages. + - Add transaction names for human use and set names for learn transactions. + - Move CREATE checks in rc_main.c into common function rc_check_create() with lea + - Fix proc function return types in reg samples. + - Remove rsbac_read_lock(), rsbac_write_lock() etc. + - Remove rsbac_vmalloc, rsbac_vkmalloc, rsbac_vfree, rsbac_vkfree. + - New kernel config RSBAC_SWITCH_BOOT_OFF: 'Allow to switch modules off with kernel parameter' + - Join ta_committing and ta_forgetting to ta_committing. + - Fix three small memory leaks. + - Show program path in CAP learning messages and use INFO level, not DEBUG. + - Allow SCD mlock in PM. + - Show program path in AUTH learning messages. + - When committing or forgetting, lock per list and make other list functions sleep while committing or forgetting. + - Optionally put learning mode results into transactions, one per module. + - Add global RC learning mode for role rights to types. + - Control CAP learning mode switch in CAP module. + - Implement CAP learning mode for user and program max_caps. + - Move AUTH auth_program_file kernel-only attribute to GEN program_file. + - Fix lockup in rehashing, after failing of new hashed struct memory allocation, forgot to spin_unlock. Alloc unlocked instead, better anyway. + - Add notes for locking to generic lists. + - Store compare results in variable to avoid doing same compare twice. + - Only reset curr pointer, if same as removed item (usually the case). + - Show rcu_batches_completed() in proc gen_list_counts. + - Store nr_hashes in variable, if used after unlocking - might change. + - Fix *remove_count(): calling rcu_free on wrong updated pointer, so store. + - Do not use count values for checks, can be wrong. Always use head. + - Allow rcu rate >= 1 for testing purposes, config help still says 100. + - Reorder syscall case struct by frequency of calls (stats from real systems). + - Ifdef syscalls for disabled modules instead of returning error in them. + - Make RCU rate limit boot and runtime configurable. + +1.4.2: + - Change generic lists to use RCU instead of rw spinlocks + - Show a total of reads and writes in list statistics in gen_lists_count + - Disable rsbac attributes store on fuse + - Fix RC dev inheritance: Explicitely set minor to 0 before getting major attr + - Use Pseudo also for RC ADF debug messages + - Use RCU callbacks with a rate limit of 1000/s, use sync, if exceeded, configurable in kernel config + +1.4.1: + - Support ANY value 255 for NETLINK protocol + - Return -EPERM in sys_rsbac_um_check_account, if user does not exist. + - Add config option RSBAC_ENFORCE_CLOSE to really deny close, if decided. + - Check CLOSE requests in RC. + - Add SCD target videomem and kernel attribute pagenr. + - Split SCD kmem into kmem and videomem, split hooks in drivers/char/mem.c. + - Allow R_MODIFY_SYSTEM_DATA notifications on SCD in adf_check.c. + - ext4 secure delete support +1.4.0: + - Added VUM (Virtual User Management) support + - OTP support for UM + - Converted the common code to 2.6 only. From now on changes will be 2.6 only as well. +1.3.5: + - Check crypto return codes (2.6) and fixed UM password hashing. + - Fix compilation issues for "disable writing to disk". See bug #98. + - Safety mesures for inheritence in case of null pointers. + - Disable debug message "rsbac_get_parent(): oops - d_parent == dentry_p". + - Increase string lengths in user and group items significantly. + - Add RSBAC memory slab 384 for new user item sizes. + - Do not try to write lists, if device is not writable. + - Do not sleep in rsbac_get_vfsmount(), can be called while atomic. + - Do not write attributes on Oracle Cluster FS 2 (OCFS2). + - Complete hook review. +1.3.4: + - No changes :) +1.3.3: + - Change FD cache counters to 64 Bit to avoid wrapping. + - Make FD Cache xstats output look nicer. + - Make an adf_request permission check when modyfing capabilities is the new set >> old one. + - Copy auth_last_auth on CLONE, gets reset on EXECUTE. + - Provide pid and process name in some UM debug output. + - 2.6 WARNING: sysrq key 'w' is GONE! no more wake up trigger possible +1.3.2: + - mark FS_OBJ_HIDE as EXPERIMENTAL and depends on it + - clean compilation warnings, data types and such. + - removed double "ready" message in rsbac_do_init() + - disable partner process check for unix socks by default. + - Show fd cache hits/misses ratio in xstats. Really inline rsbac_is_initialized(). + - Change fd cache descriptor to get rid of separate compare function in 2.4 kernels. + - Add FD inherited attribute value cache. Hash device list. Allow per-list max_ite +ms_per_hash. + - Change return code in AUTH syscalls to INVALIDATTR, if group or eff/fs support i +s not compiled in. + - port from ex 1.4 trunk: do not intercept PTRACE_DETACH request + - rewrite of error handling to be more logical in rsbac_handle_filldir(). + - Also take partner pid from other on Unix socket stream connects. + - Accept syscalls from tools with all versions 1.3.x. + - Take partner process on UNIXSOCK CONNECT from other->sk_peercred. + - Try to get partner process for UNIXSOCK RECEIVE from other sources, if peercred is not filled. + - New error code INVALIDLIST, if list handle is invalid. + - New jail flags for syslog jail. + - Extra check before reiserfs secure_delete call. + - Fix Dazuko device registration in 2.6. Return INVALIDPOINTER for invalid pointer +s in some syscalls. + - lvm/md automount fix + - Fix oops on loop umounts: device was auto-mounted, if there were dirty lists. Ne +ver auto-mount loop devices. + - +1.3.1: + - Add xstats counter for get_parent calls. + - Fix sort order of network templates. + - Add missing DAZ request in vector. Add role number in RC syscall denied log message. + - Create bitmasks for each module of which requests it is interested in and only call request_xy and set_attr_xy, if necessary. + - small performance tunning: removed usage of rsbac_list_compare_u32 (always use memcmp which is asm-tuned per arch) + - Reduce stack usage in list, ACL and RC init. + - Optimize list hash functions with bit masks instead of % operation. + - make sure that rsbac_list_max_hashes and rsbac_list_lol_max_hashes are always potential of 2 and warn the user at configuration time. (127 will round to 64). + +1.3.0: + - Restarted 1.3 tree from the 1.2.7 release + - System call rsbac_version to return numeric version without checking the caller’s version provided to syscall. + - JAIL: allow_parent_ipc to allow IPC into parent jail. Useful with Apache mod_jail and others. Needs another process attribute jail_parent + - JAIL: add a flag to allow suid/sgid files and dirs. + - Optionally check CHANGE_OWNER for PROCESS targets also as CHANGE_OWNER on the new USER. This allows fine grained control also in RC and ACL models. + - Change network templates to hold up to 25 ip networks and up to 10 port ranges. + - Automatic online resizing of per-list hash table. As list identifiers are pointers to list headers, which must not change, the arrays of list heads are allocated separately and accessed through a pointer. + - Change named UNIX sockets to be new filesystem target type T_UNIXSOCK and unnamed to be new IPC type anonunix (like pipes) + - RC role def_unixsock_create_type, which overrides the def_(ind_)fd_create_type. Default value use_def_fd. + - Change aci, acl and auth devices lists to use RCU on 2.6 kernels + - Dazuko udev support + - UM password history with configurable length to avoid password reuse. + - Update HTML doc in Documentation/rsbac, or point all docs to the website. + - Hide dir entries a process has no SEARCH right for + - Limit number of items per single list to 50000, so real limit is at 50000 * nr_hashes. + - New request type AUTHENTICATE against USER targets. No authentication against RSBAC UM without this right in RC and ACL. + - Complete hook review with several small fixes. + - More detailed JAIL decision logging for IPC and UNIXSOCK targets with rsbac_debug_adf_jail. + +1.2.7: + - Use new PaX flags location at current->mm->pax_flags. + - Removed remaining non-RSBAC code +1.2.6: + - DAZ Renaming of files from non-scanned to scanned directory + now works correctly (does not cache results from non scanned + as CLEAN - and/but keep INFECTED status if set when moving file + from scanned to non-scanned) + - DAZ unscanned files decision is now DO_NOT_CARE instead of + GRANTED + - Full pathes returned by RSBAC do not display double + (or more) / with double (or more) mounts anymore. + ex: /home//bob => /home/bob + This allows DAZ path based scanning to function normally. + - Fix setting of RC IPC type with def_ipc_create_type. + - Added ptrace hook for m32r architecture. + - New kthread notification code. + - Fix xstats to include GROUP targets. + - Mark lists dirty again, if saving failed. + - Fix FF to allow file READ (but not READ_OPEN) even with execute_only. + - Stop making SEND and RECEIVE requests for STREAM sockets, if + CONFIG_RSBAC_NET_OBJ_RW is not set. + - Notify that shm is destroyed only when it really is (thanks rtp). + - Minor compile fixes + +1.2.5: - AUTH config switch to globally allow setuid to user (real, eff, fs), + who started the program. Boot time option and proc setting to enable + per uid type. + - Show missing Linux caps in JAIL like in CAP. + - Change device attribute backup to use a list of attribute objects + instead of traversing /dev and possibly missing some. + - Device attribute inheritance: Use values at type:major as default for + type:major:minor. + - Add a generic request directly in sys_ioctl with new request type + IOCTL on DEV and NETOBJ target. + - Finish ioctl extra interception with GET_STATUS_DATA and + MODIFY_SYSTEM_DATA, e.g. for SCSI. + - Store remote IP when process accepted its first INET connection as + process attribute and pass on to children. Log remote IP in request + log. + - Symlink redirection based on remote IP. + - Optional UM password limits: Min length, non-alpha char required + - Fix EINVALIDPOINTER when changing UM password with passwd via + pam_rsbac. + - Complete system call interception review with additional hooks where + necessary. See Interceptions log for details. + - Change USER attribute backup to list of known items. + - Fix dereference bug related to rsbac_get_parent: set_attr call in + do_exec sometimes used file struct after freeing. + - Fix 2.6.11 random file not found errors, caused by symlink redirection + and ext2/ext3 kernel fs layer violation. + - Add CREATE and DELETE notifications in um syscalls. + - Make RC apply default_{user|group}_create_type on {USER|GROUP} CREATE. + - Configure module switching per module. Only allow switching stateful + models on after switching off with extra kernel config switch. + - Review all devision modules, whether they decide on all relevant + request to target combinations and whether they protect all relevant + attributes. + - Full review of all interceptions to make them locks safe + - Fix initrd problems showing up with the Adamantix kernel + +1.2.4: - Per dir FD type RC default_fd_create_type + - Full kernel space user management as a replacement for /etc/passwd, + /etc/shadow, /etc/group + - Add GROUP target type + - Change RC copy_role to be allowed with role in admin_roles + - Log full program path, get dentry from mappings for this + - Make RSBAC remote logging target configurable at boot or runtime. + Suppress remote logging, if address or port is 0. + - audit_uid: Default value "unset". Set at CHANGE_OWNER away from a uid + != 0, kept, inherited to child processes and logged. Allows to log + actions of users who did an su etc. Configurable additional uid per + program which works like uid 0, e.g. for SSHD privilege separation + (new attr auid_exempt). + - AUTH protection for Linux group IDs. + - New kernel flag: rsbac_softmode_once: Sets softmode, but denies + setting it again during runtime. For those systems that for some + reason must start in softmode, disable it and do not want to have it + set again later. + - New kernel flag: rsbac_softmode_never: Disallows setting softmode + during this runtime. + - Keep last UM authenticated users in a per-process attribute + auth_last_auth. Allow processes with auth_may_set_cap flag to set + last_auth. + - New kernel flag: rsbac_freeze: Disallows all modifying administration + in RSBAC syscalls. Added new switch target FREEZE. + - Make PaX default flags configurable. + - RC check access to UNIX socket partner process + - Transaction support for administration: begin, add a set of desired + changes, commit atomically or forget. + - Add RC copy_type, to be allowed with ADMIN right. + - User Management "exclusive mode": Only users and groups known to + RSBAC UM can be reached. Kernel parameter and /proc setting to + temporarily disable the restrictions. + - Randomize UM password salt better + - Optionally randomize transaction numbers + - Reduce memory consumption of rsbac_do_init. + - Further reduce RSBAC's stack usage to prepare for 4 KB kernel stack + size. + - Password protection for transaction operations refresh, forget, commit + - Add hooks with MODIFY_SYSTEM_DATA on SCD network to queueing + administration + - Warn explicitely, if CAP max_caps do not get applied because of + running in softmode. + - Update Dazuko interface to 2.0.5 + - Update defconfig in all archs + - ACLs for Users and Linux groups + - Extend AUTH auth_may_setuid flag with values last_auth_only and + last_auth_and_gid to allow last authenticated uid to be reached. + The second allows all group ids, too, because you cannot auth for + them. No longer add process cap at UM authentication, but rather + check at CHANGE_OWNER with last_auth process attribute. + - Fix severe Oopses when forgetting transactions with lists of lists. + - Optionally log all denied calls to capable() function with + CONFIG_RSBAC_CAP_LOG_MISSING + +1.2.3: - Port to linux kernel 2.6.0-test with LSM + - New JAIL flag allow_clock for ntpd encapsulation + - Removed LSM support (see http://rsbac.org/documentation/why_rsbac_does_not_use_lsm). + - Global AUTH learning mode + - AUTH cap inheritance from parent dir (single step only, not + accumulated) + - RC pretty-print config output + - Remove 2.2 kernel support. + - Improve AUTH learning mode to use special value for same user + - Trigger AUTH learning mode per program + - Show type, name and mode of new object in T_DIR/CREATE request log. + - Statix PaX support decision module + - Faked (root) user ID in ''getuid()'' to make stupid programs with uid + checks happy. + - Full log separation between syslog and RSBAC log, also for debug + messages (except rsbac_debug_aef). RSBAC now really shuts up, if + rsbac_nosyslog is set, and sends everything to RSBAC own log only. + - ACL learning mode for user rights to filesystem objects, parameter + rsbac_acl_learn + - New RC syscall to get current role + - mac_trusted_for_user with list instead of single user. + - Block fchdir outside the jail, if some stupid program opened a dir, + called rsbac_jail() and then called fchdir(). Done by simply closing + all open dirs after rsbac_jail() called chroot. + - Fixed some JAIL bugs found, all relevant chroot items from regression + suite solved. Not urgent enough and too many changes to make a 1.2.2 + bugfix. + - Added JAIL Linux Capability restriction + - Dazuko integration as fixed module, as replacement for MS module + - Dazuko result caching with generic lists (as in old MS module) + - AUTH special value for eff and fs uid (thanks to Arnout Engelen) + - New optional rsbac_jail parameter max_caps, which limits the Linux + capabilities of all processes in the jail + - Optionally hide process ids without GET_STATUS_DATA in /proc/ + dir listing + - /proc/rsbac-info/active to get current version and list of active + modules: One line each for version, mode: Secure/Softmode/Maintenance, + softmode: available/unavailable and one line per module: on/softmode/off + - Solve the new "kernel complains about vmalloc with lock" uglyness: + removed all vmalloc use in 2.6 kernels, too many workarounds needed. + - Protect sysfs objects in 2.6 kernels + - Added three real life example REG modules to rsbac/adf/reg, + contributed by Michal Purzynski + - Changed DEV list descriptor to be compatible between 2.4 and 2.6 + kernels + - Added RC types and compatibility settings for USER targets + - Allow to set a different RC boot role than that of user root + - Add RC process type for kernel threads + +1.2.2: - Added ms_need_scan attribute for selective scanning + - MS module support for F-Protd as scanning engine + - ms_need_scan FD attribute for selective scanning + - JAIL flag allow_inet_localhost to additionally allow to/from + local/remote IP 127.0.0.1 + - RSBAC syscall version numbers + - New RES module with minimum and maximum resource settings for + users and programs + - Moved AUTH module to generic lists with ttl + - Added new requests CHANGE_DAC_(EFF|FS)_OWNER on PROCESS targets + for seteuid and setfsuid (configurable) + - Added caps and checks for effective and fs owner to AUTH module + (optional) + - Changed behaviour on setuid etc.: Notification is always sent, even + if the uid was set to the same value. This allows for restricted RC + initial roles with correct role after setuid to root. + - New Process Hiding feature in CAP module + - Delayed init for initial ramdisks: delay RSBAC init until the first + real device mount. + - rsbac_init() syscall to trigger init by hand, if not yet + initialized - can be used with e.g. rsbac_delayed_root=99:99, which + will never trigger init automatically. + - MS module support for clamd as scanning engine. + - Almost complete reimplementation of the MAC model with many new + features. + - New system role 'auditor' for most models, which may read and flush + RSBAC own log. + +1.2.1: - Added support for all other architectures. + - Cleaned up rsbac syscall filesystem name lookup and target type + checks. + - New module JAIL: preconfigured process encapsulation (see kernel + config help). + +1.2.0: - Moved most lists to generic lists, splitting up between modules on + the way (GEN = general for all modules). + - DS for each module only included, if module is compiled in. + - New Linux Capabilities (CAP) module + - Split system_role into mac_role, fc_role, etc. Please do not use + old A_system_role attribute any longer. + - Changed rsbac_get/set_attr interface to include target module + - Added module guessing from attribute into sys_rsbac_get/set_attr, + if module is not given (value SW_NONE). + - Added user and RC role based symlink redirection + - Added network and firewall config protection as SCD network and + firewall targets + - Added NETDEV, NETTEMP and NETOBJ targets for network access control. + - Added network templates for default NETOBJ attribute values + - Renamed /rsbac dir to /rsbac.dat to avoid name conflicts. + - RC model with unlimited roles and types + - Selective dir tree disabling of Linux DAC + - Generic list ordering (needed for templates and optimization) + - List optimization + - Generic time-to-live support in generic lists (new on-disk version) + - Support time-to-live for ACL group members and ACL entries + - copy_net_temp + - Individual module soft mode + - Support time-to-live for RC entries + - Backport to 2.2.20 + +1.1.2: - Own RSBAC memory allocation functions. Own RSBAC mem slabs in 2.4 + kernels. + - Generic lists - simply register your list item sizes with filename + and persist flag, and a persistent list will be kept for you. + - Generic lists of lists, two level version. + - Moved pm_data_structures.c to new lists with proc backup files + Attention: There is no auto-update from older versions possible! + - proc backup files for RC and ACL are now optional + - New proc subdir pm, replaces old write_list call + - rsbac_pm write_list call removed + - New FD aci version with new rc_initial_role and 16 bit ff_flags + - New FF flag append_only, which limits all write accesses to + APPEND_OPEN and WRITE + - Fix for rename hole: rename could replace and thus delete an + existing file without DELETE check. Also performs secure_delete, if + necessary + - New rsbac_mount hook in change_root for initial ramdisk + - Fixed missing Linux check in bad_signal + - Added optional switch rsbac_dac_disable to disable Linux filesystem + access control + - Added count support for multiple mounts + - Added optional switch rsbac_nosyslog to temporarily disable logging + to syslog + - Added config option for DEBUG code + +1.1.1: - New target type FIFO, with a lot of cleanup, e.g. IPC type fifo + removed + - MAC module reworked, including MAC-Light option + - Several bugfixes + - Port to 2.4.0, 2.4.1 and 2.4.2 + - New Makefiles with lists for 2.4 and without for 2.2 kernels + (Thanks to Edward Brocklesby for samples) + - init process default ACI now partly depends on root's ACI + - Optional interception of sys_read and sys_write. + Attention: you might have to add READ and WRITE rights to files, + fifos, dirs and sockets first, if upgrading from an older version + - REG overhaul. Now you can register syscall functions, everything is + kept in unlimited lists instead of arrays and registering is + versioned to allow for binary module shipping with REG version + checks. + - Inheritance is now fixed, except for MAC model + - MAC: optional inheritance, new option Smart Inheritance that tries + to avoid new attribute objects (see config help) + - New soft mode option: all decisions and logging are performed, but + DO_NOT_CARE is returned to enforcement. Off by default. See config + help for details. + - Optional initialization in extra rsbac_initd thread. + +1.1.0: - Port to 2.4.0-test11 + - Interception of sys_mmap and sys_mprotect added. Now execution of + library code requires EXECUTE privilege on the library file, and + setting non-mmapped memory to EXEC mode requires EXECUTE on target + NONE. + - MAC Light option by Stanislav Ievlev added. See kernel config help or + modules.htm. + +1.0.9c: + - Port to 2.4.0-test{[789]|10}, this means major changes to the lookup and + inheritance code - of course #ifdef'd + - Change string declarations to kmalloc. On the way moved + MAX_PATH_LEN restriction from 1999 to max_kmalloc - 256 + (>127K). + - Renamed several PM xy.class to xy.object_class for C++ + compatibility + - Added SCD type ST_kmem + - Changed rc_force_role default to rc_role_inherit_parent, + terminated at root dir with old default rc_role_inherit_mixed. + This makes it much easier to keep a dir of force-roled binaries. +1.0.9b: + - Port to 2.3.42 - 2.3.99-pre3 + - Port to 2.2.14 - 2.2.16 + - 32 Bit Uid/Gid with new attribute versions + - User and program based logging + - AUTH capability ranges + - Made write to MSDOS fs a config option, so use it on your own risk + (see config help) + - MAC levels 0-252 + - Added config option for ioport access (X support) + +1.0.9a: + - Added group management to ACL module. + - Removed CONFIG_RSBAC_SYNC option. + - Added module hints to logging + - Added RC separation of duty (see models.htm) + - Added RC force role inherit_up_mixed and made it default setting + +1.0.9: - Added registration of additional decision modules (REG) + - Wrote decision module examples (see README-reg and reg_samples dir) + - Port to 2.2.8, 2.2.9, 2.2.10, 2.2.11, 2.2.12 (pre versions) + - Heavily changed RC model: Now it has a distinguished role-to-type + compatibility setting for each request type, instead of one setting + for all request types. This allows for much finer grained access + control. + Unfortunately there was no way to update existing role settings, + so those have to be reentered by hand. Still, the types entries are + kept. + - Set all MSDOS based file systems to read-only, because inode + numbers are likely to change between boots. + - Added Access Control List module. ACLs are kept on FILE, DIR, + DEV, IPC, SCD and PROCESS targets (IPC and PROCESS have only + one default ACL each). Each entry contains subject type (user, + rc_role, group), subject id and the rights this subject has. Also, + rights are inherited from parents and from a target specific default + ACL. + See html/models.htm for details. + - Added optional full path logging. + +1.0.8a: + - Port to 2.2.7 + - File Flag no_execute added to prevent execution, e.g. of user + binaries under /home tree. Can be circumvented by scripts via + 'interpreter scriptname'. + +1.0.8: - Port to 2.2.1 + - Added /proc/rsbac-info/backup to provide an easier means of backup + for not device dependent stuff. To be extended. + - Added new Role Compatibility (RC) module. + - New on-disk binary layout, auto update from all versioned data + (1.0.5 upwards). + - AUTH module added to support proper authentification by enforcing + externally granted CHANGE_OWNER capabilities. + - Save to disk inconsistency in PM sets fixed. + - MAC categories added, but limited to a fixed number of 64. Apart + from that, the MAC module categories are as proposed in the + Bell-LaPadula model. + - Port to 2.2.2 + - Port to 2.2.3 with minor changes + - Port to 2.2.4 + - Port to 2.2.5 + +1.0.7a: + - Added alpha support (with Shaun Savage). Has different storage sizes, + so default useraci does not work and you need a maint kernel. + - Added new error detection features for file/dir entries. + - Increasing of NR_FD_LISTS is now handled differently for error + detection reasons. See README-nrlists. + - Marked init functions as __init - though saving a few KB doesn't + make such a big difference while using RSBAC... ;) + - Fixed memory leaks in write_*_list while introducing vmalloc for + large lists. The number of file/dir lists is now only a matter of + performance and available memory. + - Added two flags to File Flags + - Port to 2.2.0-pre6 + - Added secure deletion/truncation, needs a config switch to be + enabled. If on, all files marked with (inheritable) FF-flag + secure_delete and all files marked as PM-personal data are zeroed on + deletion and truncation - if the regarding modules are switched on. + +1.0.7: - Port to 2.1.131 + - Added more fs types to non-writable: smbfs, ncpfs, codafs - so + there should be no writing on network mounts (unfortunately there + is no afs SUPER_MAGIC) + - Added configuration option NO_DECISION_ON_NETMOUNTS, which + additionally turns off all decisions for all these fs, so that + they are completely ignored + - Added attribute inheritance: Some attributes for files and dirs + have a special value 'inherit'. If this is set, the value of the + parent dir's attribute is used instead. This mechanism ends on + fs boundaries - each fs root dir gets old style standard values, + if attribute is set to 'inherit'. + Currently security_level, object_category and data_type are + inheritable. + - Added configuration option DEF_INHERIT. If set, default values for + inheritable attributes are *inherit, rather than the old default. + This option setting should not differ between different RSBAC + kernels to avoid deeper confusion for administrators and + rsbac_check(). + - To support inheritance, added parameter inherit to both get_attr + system calls. If on, the effective (possibly inherited) value is + returned, if off, the real value is returned. + - Corrected a security hole in receiving from / sending via datagram + sockets (thanks to Simone). Now a read/append open and a close + request are done for every datagram (if net support is configured, + as usual). + Attention: Programs that open an UDP socket as one user (e.g. root) + and then setuid to another (e.g. bin) may not be able + to access that socket, if the new user has insufficent + rights! (see config help) + Checking of net access can as before be turned on/off via + CONFIG_RSBAC_NET. + - Worked on rsbac_check(). Is more stable now, but should only be + called under maximum of moderate load. + +1.0.6: - Moved to 2.1.128 + - Cleaned up old includes in syscalls.c + - Added RSBAC own logging in /proc/rsbac-info/rmsg, to be accessed + by modified klogd or sys_rsbac_log, restricted by most modules to + security officers. + Additionally, logging to standard syslog can be turned off to hide + security relevant log from all but those with explicit access. + - Added module File Flags with attribute ff_flags for FILE/DIR + targets + - Added auto-update of last version attributes (only FD changed + though) + - Changed ms_trusted from boolean to tristate: non-trusted, read, + full + - Fixed rm -r hang bug + - Added consistency check for RSBAC items, which can remove items for + deleted inodes (ext2 only) and entries containing only default + values (FILE/DIR targets only). It also recalculates item counts. + - Added sys_rsbac_check to trigger this check. + +1.0.5: + - Rewrote most of attribute saving to disk. Now disk writing is never + done with a spinlock held, increasing stability significantly + (is this a taboo? if yes, where is it documented?) + - Changed write-to-disk behaviour: The old immediate write is no + longer default, but optional (CONFIG_RSBAC_SYNC_WRITE). Instead, + sys_rsbac_write can be used from user space or a kernel daemon can + be activated to write changes automatically every n seconds + (CONFIG_RSBAC_AUTO_WRITE) + - Added kernel param rsbac_debug_auto for the daemon - gives a good + overview of attribute change rate + - Added proc interface for statistics and many RSBAC settings + - Added rsbac_adf_request calls MODIFY_SYSTEM_DATA to sysctl.c + - Wrote man pages for all RSBAC syscalls (in Documentation/rsbac/man) + - Added version information and check for all file/dir/dev aci and + for log_levels + - Added some more scan strings to Malware Scan module, had to change + string representation to a more general way + +1.0.4: + - Port via 2.1.115 and 2.1.124 to 2.1.125 + - IPC targets: changed ids for sockets from pid/fd combination to + pointer to sock structure, including (many) changes in the + handling. + - Added socket level scanning (tcp and udp) to module Malware Scan. + This feature can stop malware while still being transferred to + your system. Added new attributes for IPC, process and file/dir + targets to manage socket scan. + - Reordered configuration options + - Added CONFIG_RSBAC_NO_WRITE to totally disable writing to disk for + testing purposes and kernel parameter rsbac_debug_no_write to + temporarily disable disk writing + - Added CONFIG_RSBAC_*_ROLE_PROTection for all role dependant + modules: Now change-owner (setuid etc.) can be restricted between + users with special roles - see configuration help for details + - Some more bugfixes, mostly to decision modules + +1.0.4-pre2: + - Port to 2.1.111 + - Attribute mac_trusted_for_user added to FILE aci. Value meanings: + RSBAC_NO_USER (-3): program is not MAC-trusted + RSBAC_ALL_USERS (-4): program is MAC-trusted for all users + other user-ID: program is MAC-trusted, if invoked by this user + Especially the last is useful for daemon programs that can be + started by all users. + Init process is checked, too, but is MAC-trusted by default. + - Syscalls rsbac_mac_set/get_max_seclevel added. Now a process can + reduce its own maximum security level. Useful for wrapper daemons + like inetd after forking and before invoking another program. + - Object dependent logging #ifdef'd with configuration option. + - Configuration option 'Maintenance Kernel' added. Disables all other + options. + - removed CONFIG_RSBAC_ADMIN and rsbac_admin() stuff - now we have + capabilities, and there is no suser() anymore to extend + - changed locking for Data Structures component from semaphores to + read/write spinlocks + - added (U)MOUNT requests for target DEV to sys_(u)mount. Now both + target dir and device are checked for access (MAC: dir: read-write, + dev: depending on mount mode read or read-write). Note: After + mount, all file/dir accesses on this device are checked as usual. + - Moved checks for valid request/target combinations from MAC module + to extra functions in rsbac/adf/check.c. + +1.0.3: - Target DEV added. Now devices can get their own attributes based + on major/minor numbers. Attributes based on their file representations + in /dev are no longer used for open, but still for all other calls. + MAC decisions on open requests for devices must be explicitely enabled + by mac_check to keep system bootable. + Short rule: Only if contents is accessed, DEV attributes apply. + - Attribute object_type removed, was not used anyway and maintained in + linux structures. + - Attributes log_array_low and log_array_high for FILE/DIR/DEV added, + providing individial request based logging for those objects. + - PM module: if DEV is personal_data, neccessary access is checked + for new class DEV (can be changed to custom class) + - A couple of minor bugfixes done + +1.0.2A: - Port to 2.0.34 + - A few #ifdef CONFIG_RSBAC_USE_RSBAC_OWNER were missing, causing + error messages "rsbac_set/get_attr returned error" -> added + + +13/Jun/2001 +Amon Ott diff --git a/Documentation/rsbac/Credits b/Documentation/rsbac/Credits new file mode 100644 index 000000000000..7f5921a59efc --- /dev/null +++ b/Documentation/rsbac/Credits @@ -0,0 +1,18 @@ +Credits +------- + +You can find information about the RSBAC team on: + +Credits for many patches showing bugs and possible fixes and lots of good +ideas go to many people. We cannot recall them all so only a few are included +here, if you are missing let us know :) + + - 'Our Russian RSBAC Team', + - AltLinux with their AltLinux Castle distribution. + - Adamantix + - rtp, addobie, and the people from #rsbac[-dev] + +Also, there are several people doing lots of helpful promotion, too many to +name them here. Their part cannot be rated too low. + +The RSBAC team. diff --git a/Documentation/rsbac/INSTALL b/Documentation/rsbac/INSTALL new file mode 100644 index 000000000000..6c6f9feade09 --- /dev/null +++ b/Documentation/rsbac/INSTALL @@ -0,0 +1,18 @@ +RSBAC INSTALL +============= + +Installation from a RSBAC tarball +--------------------------------- + +You probably already untar'ed the rsbac-x.y.z.tar.gz archive. You can safely +untar this archive into your kernel main directory, or copy all files there +- no file should be overwritten. + +To get RSBAC working, you must then patch the kernel using an RSBAC kernel +patch patch-x.y.z-va.b.c.bz2, matching your kernel version. In kernel main dir +call +bzip2 -dc patch-x.y.z-va.b.c.bz2 | patch -p1 &>perr +After patching, everything should be in place and a log should be in perr. + +If your kernel version is not supported, check at + for newer patch files. diff --git a/Documentation/rsbac/Interceptions-2.4 b/Documentation/rsbac/Interceptions-2.4 new file mode 100644 index 000000000000..e27986508127 --- /dev/null +++ b/Documentation/rsbac/Interceptions-2.4 @@ -0,0 +1,97 @@ +Interceptions for access decisions (AEF) in RSBAC 1.2.5 for 2.4.30: +(ordered as in asm-i386/unistd.h) + +Not necessary: +sys_waitpid, sys_time, sys_lseek, sys_getpid, sys_alarm, sys_pause, +sys_sync, sys_getuid, sys_alarm, sys_ftime, sys_dup, sys_times, sys_brk, +sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_olduname, sys_umask, +sys_ustat, sys_dup2, sys_getppid, sys_getpgrp, sys_setsid, sys_sigaction, +sys_sgetmask, sys_ssetmask, sys_sigsuspend, sys_sigpending, sys_getrlimit, +sys_getrusage, sys_gettimeofday, sys_getgroups, sys_select, sys_munmap, +sys_getpriority, sys_setitimer, sys_getitimer, sys_uname, sys_vhangup, +sys_vm86old, sys_wait4, sys_sysinfo, sys_fsync, sys_sigreturn, sys_newuname, +sys_modify_ldt, sys_sigprocmask, sys_get_kernel_syms(? - see discussion), +sys_sysfs, sys_personality, sys__llseek, sys_newselect, sys_flock, +sys_msync, sys_fdatasync, sys_mlock, sys_munlock, sys_mlockall, +sys_munlockall, sys_sched_getparam, sys_sched_getscheduler, sys_sched_yield, +sys_sched_get_priority_max, sys_sched_get_priority_min, +sys_sched_rr_get_interval, sys_nanosleep, sys_mremap, sys_getresuid, +sys_vm86, sys_poll, sys_getresgid, sys_prctl, sys_rt_sigreturn, +sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending, +sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_getcwd, +sys_sigaltstack, sys_ugetrlimit, sys_getuid32, sys_getgid32, sys_geteuid32, +sys_getegid32, sys_getgroups32, sys_getresuid32, sys_getresgid32, +sys_mincore, sys_madvise, sys_gettid, sys_readahead, sys_setxattr, +sys_munlockl, sys_munlockall + +Not implemented in this kernel: +sys_ftime, sys_break, sys_stty, sys_gtty, sys_prof, sys_lock, sys_mpx, +sys_ulimit, sys_profil, sys_idle, sys_afs_syscall, sys_getpmsg, +sys_putpmsg, sys_security (used by RSBAC where available) + +Intercepted: +sys_exit, sys_fork, sys_read, sys_write, sys_open, sys_close, sys_creat, +sys_link, sys_unlink, sys_execve, sys_chdir, sys_mknod, sys_chmod, +sys_lchmod, sys_oldstat, sys_mount, sys_umount (= oldumount), sys_setuid, +sys_stime, sys_ptrace, sys_oldfstat, sys_utime, sys_access, sys_nice (if +priority is raised), sys_rename, sys_mkdir, sys_rmdir, sys_setgid, sys_acct +(APPEND_OPEN on file), sys_umount2 (= umount), sys_ioctl (socket_ioctl, +tty_ioctl (tiocsti)), sys_fcntl (except locking - see discussion), +sys_setpgid, sys_chroot, sys_setreuid, sys_setregid, sys_sethostname, +sys_setrlimit, sys_settimeofday, sys_setgroups, sys_symlink, sys_oldlstat, +sys_readlink, sys_uselib, sys_swapon, sys_reboot, sys_readdir, +sys_mmap (for MAP_EXEC), sys_truncate, sys_ftruncate, sys_fchmod, +sys_fchown, sys_setpriority, sys_statfs, sys_fstatfs, sys_ioperm, +sys_socketcall, sys_stat, sys_lstat, sys_fstat, sys_iopl, sys_swapoff, +sys_ipc, sys_clone, sys_setdomainname, sys_adjtimex, sys_mprotect, +sys_create_module, sys_init_module, sys_delete_module, +sys_getpgid, sys_fchdir, sys_setfsuid, sys_setfsgid, sys_vfsreaddir, +sys_readv, sys_writev, sys_getsid, sys_sysctl, sys_setresuid, +sys_setresgid, sys_pread, sys_pwrite, sys_chown, sys_capget, sys_capset, +sys_vfork, sys_mmap2, sys_truncate64, sys_ftruncate64, sys_stat64, +sys_lstat64, sys_fstat64, sys_lchown32, sys_setreuid32, sys_setregid32, +sys_setgroups32, sys_fchown, sys_setresuid32, sys_setresgid32, +sys_chown32, sys_setuid32, sys_setgid32, sys_setfsuid32, sys_setfsgid32, +sys_pivot_root, sys_getdents64, sys_fcntl64, sys_tkill, sys_sendfile64, + + +Found missing in 1.2.4-bf5 and intercepted in 1.2.5-pre: +ptrace (on sparc and sparc64), ioctl: BRCTL* (bridging control), +sys_reboot: add reboot_cmd parameter to see command in log, +sys_mount: lookback mounts in do_loopback(), +sys_mount: move mounts in do_move_mounts(), +sys_socketcall (sys_socketpair, sys_setsockopt, sys_getsockopt, +sys_getsockname, sys_getpeername), +sys_getxattr, sys_lgetxattr, sys_fgetxattr, sys_setxattr, sys_lsetxattr, +sys_fsetxattr, sys_listxattr, sys_llistxattr, sys_flistxattr, +sys_removexattr, sys_lremovexattr, sys_fremovexattr, +sys_quotactl (new SCD quota), sys_bdflush, sys_sched_setparam, +sys_sched_setscheduler, sys_query_module, sys_nfsservctl, sys_sendfile, +NETLINK sockets (additional IP addresses, routing, firewall, tcpdiag, rules), +sys_ioctl: fs/ext[3]2/ioctl.c:ext[23]_ioctl(), sys_pipe, +sys_ioctl: drivers/ide/ide.c:ide_ioctl(), +sys_ioctl: tty_ioctl, +sys_fcntl: fs/fcntl.c:do_fcntl(): Control file locking, +sys_flock: fs/locks.c:sys_flock(): Control file advisory locking, +sys_get_kernel_syms: kernel/module.c: SCD ksyms, same for /proc/ksyms, +sys_mlock, sys_mlockall: SCD mlock, +sys_swapon: Also check access to the device as ADD_TO_KERNEL and +REMOVE_FROM_KERNEL + +Not yet intercepted, for discussion: + +- netlink-sockets: iptables_ULOG, decnet, ipv6 + +Other notes: +- Added SCD target sysctl, now used by sys_sysctl and /proc/sys instead of + non-intuitive ST_other + +- Added SCD target nfsd for kernel NFS server control + +- Added IPC type anonpipe, used by anonymous T_FIFO (if inode on PIPEFS) + +- Added requests GET_STATUS_DATA, GET_PERMISSIONS_DATA, MODIFY_PERMISSIONS_DATA, + SEND for target type DEV + +- JAIL module: generally deny read, write, GET_STATUS_DATA and MODIFY_SYSTEM_DATA + accesses to devices, flags to allow diff --git a/Documentation/rsbac/Interceptions-2.6 b/Documentation/rsbac/Interceptions-2.6 new file mode 100644 index 000000000000..bac1409155b3 --- /dev/null +++ b/Documentation/rsbac/Interceptions-2.6 @@ -0,0 +1,330 @@ +Interceptions for access decisions (AEF) in RSBAC for the kernel 2.6 as of 2.6.23.13: +to check against LSM interceptions: +egrep "static inline (.*) security_" include/linux/security.h |cut -d ' ' -f4|cut -d '(' -f1 + +#define __NR_restart_syscall 0 +#define __NR_exit 1 * +#define __NR_fork 2 * +#define __NR_read 3 * +#define __NR_write 4 * +#define __NR_open 5 * +#define __NR_close 6 * +#define __NR_waitpid 7 - +#define __NR_creat 8 * +#define __NR_link 9 * [we do not need to check for T_DIR - hardlinks are not allowed for dirs anyway] +#define __NR_unlink 10 * +#define __NR_execve 11 * +#define __NR_chdir 12 * +#define __NR_time 13 * +#define __NR_mknod 14 * +#define __NR_chmod 15 * +#define __NR_lchown 16 * +#define __NR_break 17 +#define __NR_oldstat 18 +#define __NR_lseek 19 - +#define __NR_getpid 20 - +#define __NR_mount 21 ! +[do_loopback(), do_move_mount(), do_remount() are missing. we should take care of them, also reading rsbac attributes dirs when necesary] +#define __NR_umount 22 * +#define __NR_setuid 23 * +#define __NR_getuid 24 - +#define __NR_stime 25 * +#define __NR_ptrace 26 * +#define __NR_alarm 27 - +#define __NR_oldfstat 28 +#define __NR_pause 29 - +#define __NR_utime 30 * +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 * +#define __NR_nice 34 * +#define __NR_ftime 35 +#define __NR_sync 36 - +#define __NR_kill 37 * +#define __NR_rename 38 * +#define __NR_mkdir 39 * +#define __NR_rmdir 40 * +#define __NR_dup 41 - +#define __NR_pipe 42 ! [see Interceptions-2.4] +#define __NR_times 43 - +#define __NR_prof 44 +#define __NR_brk 45 - +#define __NR_setgid 46 * +#define __NR_getgid 47 - +#define __NR_signal 48 - +#define __NR_geteuid 49 - +#define __NR_getegid 50 - +#define __NR_acct 51 ! [missing in 2.6, _and_ also on intercepted on 2.4 !!] +#define __NR_umount2 52 +#define __NR_lock 53 +#define __NR_ioctl 54 ! [missing interception - should be fine grained] +#define __NR_fcntl 55 ! [missing interception - should be fine grained] +#define __NR_mpx 56 +#define __NR_setpgid 57 * +#define __NR_ulimit 58 +#define __NR_oldolduname 59 +#define __NR_umask 60 - +#define __NR_chroot 61 * +#define __NR_ustat 62 - +#define __NR_dup2 63 - +#define __NR_getppid 64 - +#define __NR_getpgrp 65 - +#define __NR_setsid 66 - +#define __NR_sigaction 67 - +#define __NR_sgetmask 68 - +#define __NR_ssetmask 69 - +#define __NR_setreuid 70 * +#define __NR_setregid 71 * +#define __NR_sigsuspend 72 - +#define __NR_sigpending 73 - +#define __NR_sethostname 74 * +#define __NR_setrlimit 75 * +#define __NR_getrlimit 76 - +#define __NR_getrusage 77 - +#define __NR_gettimeofday 78 - +#define __NR_settimeofday 79 * +#define __NR_getgroups 80 - +#define __NR_setgroups 81 * +#define __NR_select 82 - +#define __NR_symlink 83 * +#define __NR_oldlstat 84 +#define __NR_readlink 85 * +#define __NR_uselib 86 * +#define __NR_swapon 87 * +#define __NR_reboot 88 * +#define __NR_readdir 89 +#define __NR_mmap 90 * +#define __NR_munmap 91 - +#define __NR_truncate 92 * +#define __NR_ftruncate 93 * +#define __NR_fchmod 94 * +#define __NR_fchown 95 * +#define __NR_getpriority 96 - +#define __NR_setpriority 97 * +#define __NR_profil 98 +#define __NR_statfs 99 * +#define __NR_fstatfs 100 * +#define __NR_ioperm 101 * +#define __NR_socketcall 102 ! [missing interception] +#define __NR_syslog 103 * +#define __NR_setitimer 104 - +#define __NR_getitimer 105 - +#define __NR_stat 106 * +#define __NR_lstat 107 * +#define __NR_fstat 108 * +#define __NR_olduname 109 - +#define __NR_iopl 110 * +#define __NR_vhangup 111 +#define __NR_idle 112 +#define __NR_vm86old 113 +#define __NR_wait4 114 - +#define __NR_swapoff 115 * +#define __NR_sysinfo 116 - +#define __NR_ipc 117 ! [missing interception] +#define __NR_fsync 118 - +#define __NR_sigreturn 119 - +#define __NR_clone 120 * +#define __NR_setdomainname 121 * +#define __NR_uname 122 - +#define __NR_modify_ldt 123 +#define __NR_adjtimex 124 * +#define __NR_mprotect 125 * +#define __NR_sigprocmask 126 - +#define __NR_create_module 127 +#define __NR_init_module 128 * +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 ! [missing interception] +#define __NR_getpgid 132 - +#define __NR_fchdir 133 * +#define __NR_bdflush 134 - +#define __NR_sysfs 135 - +#define __NR_personality 136 ? [what about it] +#define __NR_afs_syscall 137 +#define __NR_setfsuid 138 * +#define __NR_setfsgid 139 * +#define __NR__llseek 140 - +#define __NR_getdents 141 ! [missing interception - should be in vfs_readdir] +#define __NR__newselect 142 - +#define __NR_flock 143 - +#define __NR_msync 144 - +#define __NR_readv 145 * +#define __NR_writev 146 * +#define __NR_getsid 147 * +#define __NR_fdatasync 148 - +#define __NR__sysctl 149 ! [missing interception] +#define __NR_mlock 150 ? [to care or not to care. this is a question !] +#define __NR_munlock 151 ? [see above] +#define __NR_mlockall 152 ? [see above] +#define __NR_munlockall 153 ? [see above] +#define __NR_sched_setparam 154 ! [missing interception] +#define __NR_sched_getparam 155 - +#define __NR_sched_setscheduler 156 ! [missing interception] +#define __NR_sched_getscheduler 157 - +#define __NR_sched_yield 158 - +#define __NR_sched_get_priority_max 159 - +#define __NR_sched_get_priority_min 160 - +#define __NR_sched_rr_get_interval 161 - +#define __NR_nanosleep 162 - +#define __NR_mremap 163 - +#define __NR_setresuid 164 * +#define __NR_getresuid 165 - +#define __NR_vm86 166 +#define __NR_query_module 167 ! [intercepted on 2.4, not found on 2.6] +#define __NR_poll 168 +#define __NR_nfsservctl 169 ! [missing interception] +#define __NR_setresgid 170 * +#define __NR_getresgid 171 - +#define __NR_prctl 172 - +#define __NR_rt_sigreturn 173 - +#define __NR_rt_sigaction 174 - +#define __NR_rt_sigprocmask 175 - +#define __NR_rt_sigpending 176 - +#define __NR_rt_sigtimedwait 177 - +#define __NR_rt_sigqueueinfo 178 - +#define __NR_rt_sigsuspend 179 - +#define __NR_pread64 180 * +#define __NR_pwrite64 181 * +#define __NR_chown 182 * +#define __NR_getcwd 183 - +#define __NR_capget 184 * +#define __NR_capset 185 * +#define __NR_sigaltstack 186 - +#define __NR_sendfile 187 * +#define __NR_getpmsg 188 +#define __NR_putpmsg 189 +#define __NR_vfork 190 * +#define __NR_ugetrlimit 191 - +#define __NR_mmap2 192 * +#define __NR_truncate64 193 * +#define __NR_ftruncate64 194 * +#define __NR_stat64 195 * vfs_stat() seems to be ok, but there is also cp_new_stat()/cp_new_stat64()] +#define __NR_lstat64 196 * +#define __NR_fstat64 197 * +#define __NR_lchown32 198 * +#define __NR_getuid32 199 - +#define __NR_getgid32 200 - +#define __NR_geteuid32 201 - +#define __NR_getegid32 202 - +#define __NR_setreuid32 203 +#define __NR_setregid32 204 +#define __NR_getgroups32 205 - +#define __NR_setgroups32 206 +#define __NR_fchown32 207 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 - +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 - +#define __NR_chown32 212 +#define __NR_setuid32 213 +#define __NR_setgid32 214 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 +#define __NR_pivot_root 217 * +#define __NR_mincore 218 ? [not intercepted - i do not think it is necesary thought] +#define __NR_madvise 219 ? [not intercepted - maybe this one should be] +#define __NR_madvise1 219 +#define __NR_getdents64 220 ! [same as sys_getdents()] +#define __NR_fcntl64 221 ! [same as sys_fcntl()] +/* 223 is unused */ +#define __NR_gettid 224 ? [not intercepted, rather no need to] +#define __NR_readahead 225 ? [not intercepted - shall we ?] +#define __NR_setxattr 226 ? [do we care about xattr ?] +#define __NR_lsetxattr 227 ? [see above] +#define __NR_fsetxattr 228 ? [see above] +#define __NR_getxattr 229 ? [see above] +#define __NR_lgetxattr 230 ? [see above] +#define __NR_fgetxattr 231 ? [see above] +#define __NR_listxattr 232 ? [see above] +#define __NR_llistxattr 233 ? [see above] +#define __NR_flistxattr 234 ? [see above] +#define __NR_removexattr 235 ? [see above] +#define __NR_lremovexattr 236 ? [see above] +#define __NR_fremovexattr 237 ? [see above] +#define __NR_tkill 238 * +#define __NR_sendfile64 239 * +#define __NR_futex 240 ! [multiplexer - check it out] +#define __NR_sched_setaffinity 241 ! [not intercepted - shall we ?] +#define __NR_sched_getaffinity 242 ! [not intercepted, there is no need to] +#define __NR_set_thread_area 243 +#define __NR_get_thread_area 244 +#define __NR_io_setup 245 ? [not intercepted - wtf is it ?] +#define __NR_io_destroy 246 [see above] +#define __NR_io_getevents 247 [see above] +#define __NR_io_submit 248 [see above] +#define __NR_io_cancel 249 [see above] +#define __NR_fadvise64 250 ? [not intercepted - don't ask me what the heck is it] + +#define __NR_exit_group 252 ? [not intercepted - should be treated like sys_exit() ?] +#define __NR_lookup_dcookie 253 ? [not intercepted - not necesary] +#define __NR_epoll_create 254 ? [do we care about epool ?] +#define __NR_epoll_ctl 255 ? [see above] +#define __NR_epoll_wait 256 ? [see above] +#define __NR_remap_file_pages 257 ? [not intercepted - may be dangerous ?] +#define __NR_set_tid_address 258 ? [not intercepted - no need to] +#define __NR_timer_create 259 ? [not intercepted - no need to ?] +#define __NR_timer_settime ? [see above] +#define __NR_timer_gettime ? [see above] +#define __NR_timer_getoverrun ? [see above] +#define __NR_timer_delete ? [see above] +#define __NR_clock_settime * +#define __NR_clock_gettime - +#define __NR_clock_getres - +#define __NR_clock_nanosleep - +#define __NR_statfs64 268 * +#define __NR_fstatfs64 269 * +#define __NR_tgkill 270 * +#define __NR_utimes 271 * +#define __NR_fadvise64_64 272 ? [not intercepted - look fadvise above] +#define __NR_vserver 273 - [reservation for friendly project] +#define __NR_mbind 274 ? [not intercepted - i am borring, but will ask once more - what the heck ? (memory allocation policy stuff ?)] +#define __NR_get_mempolicy 275 ? [see above] +#define __NR_set_mempolicy 276 ? [see above] +#define __NR_mq_open 277 ? [message queues - i think that may be security revelant] +#define __NR_mq_unlink ? [see above] +#define __NR_mq_timedsend ? [see above] +#define __NR_mq_timedreceive ? [see above] +#define __NR_mq_notify ? [see above] +#define __NR_mq_getsetattr ? [see above] +#define __NR_sys_kexec_load 283 ! [not found, but kexec is very dangerous - should be imidiatelly be taken care of] +#define __NR_waitid 284 ? [not intercepted, probably no need to] +/* #define __NR_sys_setaltroot 285 ? [if any day it will come out from deep shadows we will be playing with it hard] */ +#define __NR_add_key 286 ? [key infrastructure recently hit kernels, another redhat (read: stupid, wastefull and security risky) idea ?] +#define __NR_request_key 287 ? [see above] +#define __NR_keyctl 288 ? [see above] +#define __NR_ioprio_set 289 * +#define __NR_ioprio_get 290 - +#define __NR_inotify_init 291 +#define __NR_inotify_add_watch 292 +#define __NR_inotify_rm_watch 293 +#define __NR_migrate_pages 294 +#define __NR_openat 295 +#define __NR_mkdirat 296 +#define __NR_mknodat 297 +#define __NR_fchownat 298 +#define __NR_futimesat 299 +#define __NR_fstatat64 300 +#define __NR_unlinkat 301 +#define __NR_renameat 302 +#define __NR_linkat 303 +#define __NR_symlinkat 304 +#define __NR_readlinkat 305 +#define __NR_fchmodat 306 +#define __NR_faccessat 307 +#define __NR_pselect6 308 +#define __NR_ppoll 309 +#define __NR_unshare 310 +#define __NR_set_robust_list 311 +#define __NR_get_robust_list 312 +#define __NR_splice 313 +#define __NR_sync_file_range 314 +#define __NR_tee 315 +#define __NR_vmsplice 316 +#define __NR_move_pages 317 +#define __NR_getcpu 318 +#define __NR_epoll_pwait 319 +#define __NR_utimensat 320 +#define __NR_signalfd 321 +#define __NR_timerfd 322 +#define __NR_eventfd 323 +#define __NR_fallocate 324 * diff --git a/Documentation/rsbac/README b/Documentation/rsbac/README new file mode 100644 index 000000000000..fd676e979589 --- /dev/null +++ b/Documentation/rsbac/README @@ -0,0 +1,49 @@ +RSBAC README +------------ + +Documentation in this section is here for information only. + +The full RSBAC documentation is available online, at: + + +New RSBAC versions as well as support for other kernel versions and bugfixes +can be downloaded from: + +For installation instructions read INSTALL. + +Files description: +------------------ + +README-kernparam: +Describes the various kernel parameters that can be used with RSBAC. + +README-proc: +Describes the proc interface to RSBAC. + +Information about the registration of additional RSBAC decision modules +(option CONFIG_RSBAC_REG) can be found in README-reg and html/reg.htm. + +(Quite old) man pages for many RSBAC syscalls are in the man directory. +Russian versions can be found in man-rus. + +README-nrlists: +For large systems (very many files per partition) you might consider +increasing RSBAC_NR_FD_LISTS in include/rsbac/aci_data_structures.h before +compiling. Please read README-nrlists first. +There is also now a kernel configuration option. + +README-patching: +If you patched against another kernel version than stated in the patch +filename, it is important to work through README-patching. + +README-reg: +Information about the registration of additional RSBAC decision modules +(option CONFIG_RSBAC_REG) can be found in README-reg. + + +If you run into problems or have questions, please write to the RSBAC +mailing list at rsbac@rsbac.org (commands like 'subscribe rsbac' as single +line in the message body to majordomo@rsbac.org), or see: + + +The RSBAC team. diff --git a/Documentation/rsbac/README-kernparam b/Documentation/rsbac/README-kernparam new file mode 100644 index 000000000000..c3c149fa15a2 --- /dev/null +++ b/Documentation/rsbac/README-kernparam @@ -0,0 +1,92 @@ +RSBAC README for the kernel parameters. +--------------------------------------- + +Also see: + +The RSBAC system accepts the following parameters: + - rsbac_debug_ds: Debug messages from the Data Structures component. + - rsbac_debug_aef: Debug messages from the enforcement component (AEF). + - rsbac_debug_no_adf: Set default log level value for all request + types to 0: Do not log. + - rsbac_debug_adf (default, so obsolete): Set default log level value for all + request types to 1: Logging messages + from the decision component (ADF) for all requests that were denied (highly + recommended for testing, even in normal use). If provided, pseudonyms of + users are used. + - rsbac_debug_adf_all: Set default log level value for all request types to 2: + Logging messages from the decision component (ADF) for all requests. If + provided, pseudonyms of users are used. Gives a real lot of logging stuff + - never try this, if checking of sys_syslog is turned on and log levels + have not yet been saved to keep them permanent... + - rsbac_debug_ds_pm: Debug messages from the Data Structures component, + on access to privacy model data. + - rsbac_debug_aef_pm: Debug messages for privacy model specific system + calls. + - rsbac_debug_adf_pm: Debug messages for access control in privacy module. + - rsbac_debug_pm: Sets rsbac_debug_ds_pm, rsbac_debug_aef_pm, + rsbac_debug_adf_pm (recommended for testing privacy model). + - rsbac_debug_adf_ms: Debug messages for access control in Malware Scan. + - rsbac_debug_ds_rc: Debug messages from the Data Structures component, + on access to Role Compatibility model data. + - rsbac_debug_aef_rc: Debug messages for Role Compatibility model specific + system calls. + - rsbac_debug_adf_rc: Debug messages for access control in RC module. + - rsbac_debug_rc: Sets rsbac_debug_ds_rc, rsbac_debug_aef_rc, + rsbac_debug_adf_rc. + - rsbac_debug_ds_auth: Debug messages from the Data Structures component, + on access to AUTH model data. + - rsbac_debug_aef_auth: Debug messages for AUTH model specific system calls. + - rsbac_debug_adf_auth: Debug messages for access control in AUTH module. + - rsbac_debug_auth: Sets rsbac_debug_ds_auth, rsbac_debug_aef_auth, + rsbac_debug_adf_auth. + - rsbac_debug_ds_acl: Debug messages from the Data Structures component, + on access to Access Control Lists (ACL) model data. + - rsbac_debug_aef_acl: Debug messages for ACL model specific + system calls. + - rsbac_debug_adf_acl: Debug messages for access control in ACL module. + - rsbac_debug_acl: Sets rsbac_debug_ds_acl, rsbac_debug_aef_acl, + rsbac_debug_adf_acl. + - rsbac_debug_all: Sets all debug options - in fact turns on a huge amount + of logging. Beware of a fast growing system log. Hardly ever recommended. + - rsbac_debug_no_write: Turn writing to disk off for this + single boot time. For testing. + - rsbac_debug_auto: Debug messages from auto-write / rsbacd. Recommended + for a good disk saving overview. + - rsbac_debug_write: Debug messages from all attribute writing related + procedures. + - rsbac_no_defaults: suppress creation of default settings, useful for + restore from existing backup. Warning: An unconfigured system will only + come up in softmode or maint mode, and softmode will produce loads of + logging (see rsbac_nosyslog option...). + - rsbac_auth_enable_login: Sets auth_may_setuid for /bin/login, if AUTH + module is on. A good emergency helper, if you cannot login anymore. + - rsbac_softmode (only, if enabled on kernel config): switch to softmode + - rsbac_softmode_once (only, if enabled on kernel config): switch to softmode + and disallow to switch it on again later + - rsbac_softmode_never (only, if softmode enabled on kernel config): + disallow to switch softmode on during this runtime + - rsbac_softmode_ (module name in lowercase, e.g. rc, only if enabled): + switch individual model softmode to on + - rsbac_freeze (only, if enabled in kernel config): Disallow RSBAC + administration for this runtime. + - rsbac_nosyslog: do not log to syslog for this boot time + - rsbac_no_init_delay: disable delayed init for this single boot (if + init delay is enabled in kernel config) + - rsbac_delayed_root=major[:minor]: initialize, when this device gets + mounted. Omit minor or set to 00 to match all devices with this major + number. Delayed init must be enabled in kernel config. + - rsbac_auth_learn (only, if enabled in kernel config): enable AUTH + learning mode, where AUTH module adds all missing capabilities + automatically instead of denying the request. + - rsbac_acl_learn and rsbac_acl_learn_fd (only, if enabled in kernel + config): enable ACL learning mode for user rights to filesystem objects + - rsbac_log_remote_addr=a.b.c.d: Set remote logging address to a.b.c.d + - rsbac_log_remote_port=n: Set remote logging port to n. Remote logging + must be enabled in kernel config. + - rsbac_um_no_excl: Disable exlusive user management for this uptime. + - rsbac_daz_ttl=n: Set DAZ cache item ttl to n seconds for this boot. + - rsbac_cap_log_missing: Log all calls to capable() for caps, which are + not in the process set of effective Linux capabilities, i.e., failed + capable() checks. + +Last updated: 01/Aug/2016 diff --git a/Documentation/rsbac/README-nrlists b/Documentation/rsbac/README-nrlists new file mode 100644 index 000000000000..496aad4ab854 --- /dev/null +++ b/Documentation/rsbac/README-nrlists @@ -0,0 +1,28 @@ +RSBAC README-nrlists +-------------------- + +For large systems (very many files per partition) you should increase +RSBAC_NR_FD_LISTS in include/rsbac/aci_data_structures.h before compiling. + +You should earnestly consider increasing, if you get warning messages like +"write_fd_list(): list n too large (m bytes), calling partial_write_fd_list()!" +(this does not lead to data loss though - it only decreases stability a +bit). This should not happen any longer though - if it does, please send a +note to RSBAC mailing list containing your /proc/rsbac-info/stats output and +the output of free at the time when the messages appear for examination. + +CAUTION: +- When restarting with a larger number of lists for the first time, you *must* + use the kernel parameter rsbac_change_nr! Only then old attributes are + allowed to be sorted into the now correct lists, otherwise they get lost and + that's it. +- Please remember mounting rw all partitions used by RSBAC so far, while + rsbac_change_nr is still active. +- There is definately no way back to a smaller number. All following RSBAC + versions must be set to the same value, and rebooting with an older kernel + can result in unnoticable attribute losses. + +To test this feature, you can use rsbac_debug_no_write. This prevents +attribute saving and thus attribute loss from previous runs. Those +partitions that are not mounted rw at boot time can be tested by mounting +read-only. diff --git a/Documentation/rsbac/README-patching b/Documentation/rsbac/README-patching new file mode 100644 index 000000000000..2cf1691a49c0 --- /dev/null +++ b/Documentation/rsbac/README-patching @@ -0,0 +1,27 @@ +RSBAC README for patching against other versions. +------------------------------------------------- + +To make my point clear: I do not recommend patching against other kernel +versions than stated in the patch filename. Rather check RSBAC homepage +for new versions or send a note to the RSBAC mailing list (see README). + +If you had to patch against another version, you will have to do the following: + - Make sure you understand how rsbac_adf_request() and rsbac_adf_set_attr() + calls work + - Patch in all rejects by hand. + - Edit fs/namei.c: + rsbac_lookup_one_len/hash must be lookup_one_len/hash minus + checks (permission(), rsbac_adf_request()). + Please do not forget to change the call to lookup_hash in + rsbac_lookup_one_len into rsbac_lookup_hash. + - arch/i386/kernel/entry.S must contain the RSBAC syscall number added, + embraced by #ifdef CONFIG_RSBAC. + You may have to adjust syscall numbers there and in + include/rsbac/unistd-i386.h. After that make sure you recompiled the + admin tools. + - Same for all other archs + - Check in rsbac/data_structures/aci_data_structures.c, if file opening and + closing are done correctly (rsbac_read_open, rsbac_write_open, + rsbac_read_close, rsbac_write_close). + - Check in rsbac/help/debug.c, whether the logging in rsbac_log() is + implemented correctly - see sys_syslog() in kernel/printk.c diff --git a/Documentation/rsbac/README-proc b/Documentation/rsbac/README-proc new file mode 100644 index 000000000000..f74cb7b47b08 --- /dev/null +++ b/Documentation/rsbac/README-proc @@ -0,0 +1,93 @@ +RSBAC README for the proc interface. +------------------------------------ + +Also see: + +If enabled in the kernel configuration, RSBAC adds one directory to the +main proc dir: rsbac-info. Since proc is treated as a normal read-only fs, +rsbac could not be used. + +All successful write accesses are logged via syslog at KERN_INFO level. +The rsbac-info dir contains the following entries: + + - stats: shows rsbac status, same contents as sys_rsbac_stats writes into + syslog + + - active: short summary of version, mode and module states, good for scripts + + - stats_pm (if PM is enabled): shows PM status, same contents as + sys_rsbac_stats_pm writes into syslog + + - stats_rc (if RC is enabled): shows RC status + + - stats_auth (if AUTH is enabled): shows AUTH status + + - stats_acl (if ACL is enabled): shows ACL status + + - xstats (if extended status is enabled): shows extended status, e.g. table + of call counts for requests and targets + + - devices: shows all rsbac-mounted devices in n:m notation and their + no_write status (no_write is set on fd-list read, if wrong version). + No_write status can be changed by calling + echo "devices no_write n:m k" >devices + with n:m is the device in major:minor notation, k is 0 or 1. + + - acl_devices, auth_devices: same for ACL and AUTH data structures + + - debug: shows all RSBAC debug settings, softmode and nosyslog. + Levels can be changed by calling + echo "debug name n" >debug + Valid names are ds, aef, no_write, ds_pm, aef_pm, adf_pm, adf_ms, ds_rc, + aef_rc, adf_rc, ds_acl, aef_acl, adf_acl, auto, softmode and + nosyslog, but only, if shown when reading this file. Valid levels are 0 + and 1. + Debug levels can be preset to 1 by kernel parameters with same name as + variable name shown, e.g. rsbac_debug_ds or rsbac_softmode. + Individual model softmode can be switched by calling + echo "debug ind_softmode n" >debug + Remote logging address and port can be changed with + echo "debug log_remote_addr a.b.c.d" >debug + echo "debug log_remote_port n" >debug + DAZ cache ttl is set via + echo "debug daz_ttl n" >debug + + - log_levels: shows adf log levels for all requests. Log levels can be + changed by calling + echo "log_levels request n" >log_levels + with request = request name, e.g. WRITE, n = level. + + - auto_write (if auto-write is enabled): shows auto write status, currently + auto interval in jiffies and auto debug level only. + Auto interval can be changed by calling + echo "auto interval n" >auto_write + with n = number of jiffies, debug level (0 or 1) by calling + echo "auto debug n" >auto_write + + - versions: shows aci versions for dev and user list and adf request array + version for log_level array and the no_write status of each (set on boot, + if wrong version is tried to be read). No_write status can be changed by + calling + echo "no_write listname n" >versions + with listname is one of dev, user, log_levels, n is 0 or 1. + + - rmsg (if own logging is enabled): similar to kmsg in main proc dir, logging + of RSBAC requests. This file can be used by programs like klogd. + + - auth_caplist (if AUTH is enabled): shows all AUTH capabilities currently + set. + + - reg_modules (if REG is enabled): shows currently registered additional + decision modules and syscalls. + + - acl_acllist (if ACL is enabled): Detailed listing of all ACL entries and + masks in the system. + + - backup subdir: It contains backups of what would be + current aci data files. You can use cp for backups of system independent aci + data structures, e.g. rc_roles, rc_types, and the admin backup tools for + system dependent ones, e.g. file/dir attributes or AUTH file capabilities. + Using the backup_all script or single lines from it is however strongly + recommended. + +Last updated: 01/Aug/2016 diff --git a/Documentation/rsbac/README-reg b/Documentation/rsbac/README-reg new file mode 100644 index 000000000000..10d6b8b84fb9 --- /dev/null +++ b/Documentation/rsbac/README-reg @@ -0,0 +1,37 @@ +RSBAC README for the REG facility. +---------------------------------- + +Also see: + +If enabled in the kernel configuration, RSBAC REG allows the registration +and unregistration of additional decision modules at runtime, usually from +a kernel module. + +These modules register with a name and a chosen magic handle, which can be +used for switching on/off and for unregistration. + +By registration, a request (the decision itself), a set_attr (called after +successful syscall completion) and a need_overwrite (called to determine, +whether a file needs to be securely deleted/truncated) function can be +installed. + +Apart from these decision functions some support routines can be registered. +Currently these are write (signal asynchronous attribute writing to disk, +called regularly by rsbacd), mount and umount (a device has been (u)mounted). + +However, each of these function pointers can be set to NULL, if +no call of this type is wanted. + +All functions are *additional* to the existing functions from builtin +modules, e.g. MAC or RC. This way, they can only further restrict access, +but not grant anything denied by other models. + +Also, you can now register system calls and generic lists. + +For examples of builtin real decision modules and their functions see +subdirs below rsbac/adf/. + +Working example modules with simple call counters and a proc pseudo file +for counter display can be found in the examples/reg/ directory of the +rsbac-admin tools. These are basically the same modules that are built if +you enabled building of sample modules in kernel config. diff --git a/MAINTAINERS b/MAINTAINERS index 44cb004c765d..23682540bc70 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11320,6 +11320,13 @@ T: git git://linuxtv.org/anttip/media_tree.git S: Maintained F: drivers/media/dvb-frontends/rtl2832_sdr* +RSBAC +P: Amon Ott +M: ao@rsbac.org +L: rsbac@rsbac.org +W: http://www.rsbac.org +S: Maintained + RTL8180 WIRELESS DRIVER L: linux-wireless@vger.kernel.org W: http://wireless.kernel.org/ diff --git a/Makefile b/Makefile index 6eba23bcb5ad..17df2baab936 100644 --- a/Makefile +++ b/Makefile @@ -865,6 +865,14 @@ export INSTALL_PATH ?= /boot export INSTALL_DTBS_PATH ?= $(INSTALL_PATH)/dtbs/$(KERNELRELEASE) # + +# Add RSBAC version +ifeq ($(CONFIG_RSBAC),y) +EXTRAVERSION:=$(EXTRAVERSION)-rsbac +core-y += rsbac/ +export CONFIG_RSBAC = true +endif + # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory # relocations required by build roots. This is not defined in the # makefile but the argument can be passed to make if needed. diff --git a/arch/alpha/include/uapi/asm/unistd.h b/arch/alpha/include/uapi/asm/unistd.h index aa33bf5aacb6..6a74a8594923 100644 --- a/arch/alpha/include/uapi/asm/unistd.h +++ b/arch/alpha/include/uapi/asm/unistd.h @@ -338,7 +338,11 @@ #define __NR_getdents64 377 #define __NR_gettid 378 #define __NR_readahead 379 +#ifdef CONFIG_RSBAC +#define __NR_rsbac 380 +#else /* 380 is unused */ +#endif #define __NR_tkill 381 #define __NR_setxattr 382 #define __NR_lsetxattr 383 diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c index 6ff8886e7e22..658ecc498570 100644 --- a/arch/alpha/kernel/asm-offsets.c +++ b/arch/alpha/kernel/asm-offsets.c @@ -35,6 +35,9 @@ void foo(void) DEFINE(PT_PTRACED, PT_PTRACED); DEFINE(CLONE_VM, CLONE_VM); DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); +#ifdef CONFIG_RSBAC + DEFINE(CLONE_KTHREAD, CLONE_KTHREAD); +#endif DEFINE(SIGCHLD, SIGCHLD); BLANK(); diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index 285a82d491ef..efafb33336a7 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -23,6 +23,8 @@ #include "proto.h" +#include + #define DEBUG DBG_MEM #undef DEBUG @@ -279,6 +281,26 @@ long arch_ptrace(struct task_struct *child, long request, unsigned long tmp; size_t copied; long ret; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + rsbac_pr_debug(aef, "calling ADF\n"); + rcu_read_lock(); + rsbac_target_id.process = task_pid(child); + rsbac_attribute_value.trace_request = request; + if (!rsbac_adf_request(R_TRACE, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_trace_request, + rsbac_attribute_value)) + { + rcu_read_unlock(); + return -EPERM; + } + rcu_read_unlock(); +#endif switch (request) { /* When I and D space are separate, these will need to be fixed. */ diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 96bee776e145..a693e6add41c 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -106,6 +106,7 @@ clock-latency = <244144>; /* 8 32k periods */ operating-points = < /* kHz uV */ + 1008000 1450000 960000 1400000 912000 1400000 864000 1300000 diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h index 28bd456494a3..867fab40aa5d 100644 --- a/arch/arm/include/uapi/asm/unistd.h +++ b/arch/arm/include/uapi/asm/unistd.h @@ -37,3 +37,11 @@ #define __ARM_NR_set_tls (__ARM_NR_BASE+5) #endif /* _UAPI__ASM_ARM_UNISTD_H */ + +/* RSBAC - we use 223, the old sys_security */ +#ifdef CONFIG_RSBAC +#define __NR_rsbac (__NR_SYSCALL_BASE+223) +#else + /* 223 is unused */ +#endif + diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index b5622521dad5..a942ea85aa55 100644 --- a/arch/cris/arch-v10/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S @@ -826,7 +826,11 @@ sys_call_table: .long sys_getdents64 /* 220 */ .long sys_fcntl64 .long sys_ni_syscall /* reserved for TUX */ - .long sys_ni_syscall +#ifdef CONFIG_RSBAC + .long sys_rsbac /* reserved for sys_security */ +#else + .long sys_ni_syscall /* reserved for sys_security */ +#endif .long sys_gettid .long sys_readahead /* 225 */ .long sys_setxattr diff --git a/arch/ia64/include/uapi/asm/unistd.h b/arch/ia64/include/uapi/asm/unistd.h index ea5363daa7bd..e32b7d12fc39 100644 --- a/arch/ia64/include/uapi/asm/unistd.h +++ b/arch/ia64/include/uapi/asm/unistd.h @@ -298,6 +298,9 @@ #define __NR_utimensat 1306 #define __NR_signalfd 1307 #define __NR_timerfd 1308 +#ifdef CONFIG_RSBAC +#define __NR_rsbac 1308 +#endif #define __NR_eventfd 1309 #define __NR_timerfd_create 1310 #define __NR_timerfd_settime 1311 diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c index 798bdb209d00..8187fa69ebcb 100644 --- a/arch/ia64/kernel/asm-offsets.c +++ b/arch/ia64/kernel/asm-offsets.c @@ -198,6 +198,9 @@ void foo(void) /* for assembly files which can't include sched.h: */ DEFINE(IA64_CLONE_VFORK, CLONE_VFORK); DEFINE(IA64_CLONE_VM, CLONE_VM); +#ifdef CONFIG_RSBAC + DEFINE(IA64_CLONE_KTHREAD, CLONE_KTHREAD); +#endif BLANK(); DEFINE(IA64_CPUINFO_NSEC_PER_CYC_OFFSET, diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index e7a716b09350..59844f353087 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1713,7 +1713,11 @@ sys_call_table: data8 sys_epoll_pwait // 1305 data8 sys_utimensat data8 sys_signalfd +#ifdef CONFIG_RSBAC + data8 sys_rsbac +#else data8 sys_ni_syscall +#endif data8 sys_eventfd data8 sys_timerfd_create // 1310 data8 sys_timerfd_settime diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c index 2d887400e30e..bf4e0ac8e321 100644 --- a/arch/m32r/kernel/ptrace.c +++ b/arch/m32r/kernel/ptrace.c @@ -33,6 +33,8 @@ #include #include +#include + /* * This routine will get a word off of the process kernel stack. */ @@ -630,6 +632,25 @@ arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { int ret; + +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = task_pid(child); + rsbac_attribute_value.trace_request = request; + if (!rsbac_adf_request(R_TRACE, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_trace_request, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + unsigned long __user *datap = (unsigned long __user *) data; switch (request) { diff --git a/arch/m68k/include/uapi/asm/unistd.h b/arch/m68k/include/uapi/asm/unistd.h index 25589f5b8669..dc1541a9663e 100644 --- a/arch/m68k/include/uapi/asm/unistd.h +++ b/arch/m68k/include/uapi/asm/unistd.h @@ -223,7 +223,9 @@ #define __NR_setfsuid32 215 #define __NR_setfsgid32 216 #define __NR_pivot_root 217 -/* 218*/ +#ifdef CONFIG_RSBAC +#define __NR_rsbac 218 +#endif /* 219*/ #define __NR_getdents64 220 #define __NR_gettid 221 diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S index 8c9fcfafe0dd..20c0af1791c5 100644 --- a/arch/m68k/kernel/syscalltable.S +++ b/arch/m68k/kernel/syscalltable.S @@ -400,3 +400,10 @@ ENTRY(sys_call_table) .long sys_preadv2 .long sys_pwritev2 .long sys_statx +#ifdef CONFIG_RSBAC + /* we use 400, until sys_security gets defined here */ + .rept 399-378 + .long sys_ni_syscall + .endr + .long sys_rsbac +#endif diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 27c2f90eeb21..ab931d6c6996 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -443,7 +443,11 @@ EXPORT(sys_call_table) PTR sys_madvise PTR sys_getdents64 PTR sys_fcntl64 /* 4220 */ +#ifdef CONFIG_RSBAC + PTR sys_rsbac +#else PTR sys_ni_syscall +#endif PTR sys_gettid PTR sys_readahead PTR sys_setxattr diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 65d5aeeb9bdb..7fc01e759c21 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -289,7 +289,11 @@ EXPORT(sys_call_table) PTR sys_ni_syscall /* res. for getpmsg */ PTR sys_ni_syscall /* 5175 for putpmsg */ PTR sys_ni_syscall /* res. for afs_syscall */ +#ifdef CONFIG_RSBAC + PTR sys_rsbac /* Security */ +#else PTR sys_ni_syscall /* res. for security */ +#endif PTR sys_gettid PTR sys_readahead PTR sys_setxattr /* 5180 */ diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index c30bc520885f..09eaa1e55e44 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -443,7 +443,11 @@ EXPORT(sys32_call_table) PTR sys_madvise PTR sys_getdents64 PTR compat_sys_fcntl64 /* 4220 */ +#ifdef CONFIG_RSBAC + PTR sys_rsbac /* Security */ +#else PTR sys_ni_syscall +#endif PTR sys_gettid PTR sys32_readahead PTR sys_setxattr diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 6308749359e4..defcfd980f25 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -404,6 +404,9 @@ ENTRY_SAME(timerfd_create) ENTRY_COMP(timerfd_settime) ENTRY_COMP(timerfd_gettime) +#ifdef CONFIG_RSBAC + ENTRY_SAME(rsbac) +#endif ENTRY_COMP(signalfd4) ENTRY_SAME(eventfd2) /* 310 */ ENTRY_SAME(epoll_create1) diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index 1c9470881c4a..5e58f0adc997 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -228,7 +228,11 @@ SYSCALL_SPU(fremovexattr) COMPAT_SYS_SPU(futex) COMPAT_SYS_SPU(sched_setaffinity) COMPAT_SYS_SPU(sched_getaffinity) +#ifdef CONFIG_RSBAC +SYSCALL(rsbac) +#else SYSCALL(ni_syscall) +#endif SYSCALL(ni_syscall) SYS32ONLY(sendfile64) COMPAT_SYS_SPU(io_setup) diff --git a/arch/powerpc/include/uapi/asm/unistd.h b/arch/powerpc/include/uapi/asm/unistd.h index b85f14228857..03fd57ff32b0 100644 --- a/arch/powerpc/include/uapi/asm/unistd.h +++ b/arch/powerpc/include/uapi/asm/unistd.h @@ -238,6 +238,10 @@ #define __NR_futex 221 #define __NR_sched_setaffinity 222 #define __NR_sched_getaffinity 223 +/* RSBAC - we use 224, the old sys_security */ +#ifdef CONFIG_RSBAC +#define __NR_rsbac 224 +#endif /* 224 currently unused */ #define __NR_tuxcall 225 #ifndef __powerpc64__ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 6e95c2c19a7e..e24fd26b2171 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -352,6 +352,10 @@ int main(void) OFFSET(pbe_orig_address, pbe, orig_address); OFFSET(pbe_next, pbe, next); +#ifdef CONFIG_RSBAC + DEFINE(CLONE_KTHREAD, CLONE_KTHREAD); +#endif + #ifndef CONFIG_PPC64 DEFINE(TASK_SIZE, TASK_SIZE); DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); diff --git a/arch/sh/include/uapi/asm/unistd_32.h b/arch/sh/include/uapi/asm/unistd_32.h index c801bde9e6f5..74c6df1580ff 100644 --- a/arch/sh/include/uapi/asm/unistd_32.h +++ b/arch/sh/include/uapi/asm/unistd_32.h @@ -232,7 +232,11 @@ #define __NR_getdents64 220 #define __NR_fcntl64 221 /* 222 is reserved for tux */ +#ifdef CONFIG_RSBAC +#define __NR_rsbac 223 +#else /* 223 is unused */ +#endif #define __NR_gettid 224 #define __NR_readahead 225 #define __NR_setxattr 226 diff --git a/arch/sh/include/uapi/asm/unistd_64.h b/arch/sh/include/uapi/asm/unistd_64.h index ce0cb3598b62..70337efec758 100644 --- a/arch/sh/include/uapi/asm/unistd_64.h +++ b/arch/sh/include/uapi/asm/unistd_64.h @@ -270,7 +270,11 @@ #define __NR_getdents64 248 #define __NR_fcntl64 249 /* 250 is reserved for tux */ +#ifdef CONFIG_RSBAC +#define __NR_rsbac 251 +#else /* 251 is unused */ +#endif #define __NR_gettid 252 #define __NR_readahead 253 #define __NR_setxattr 254 diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S index 254bc22ee57d..9190233df57c 100644 --- a/arch/sh/kernel/syscalls_32.S +++ b/arch/sh/kernel/syscalls_32.S @@ -239,7 +239,11 @@ ENTRY(sys_call_table) .long sys_getdents64 /* 220 */ .long sys_fcntl64 .long sys_ni_syscall /* reserved for TUX */ +#ifdef CONFIG_RSBAC + .long sys_rsbac +#else .long sys_ni_syscall /* Reserved for Security */ +#endif .long sys_gettid .long sys_readahead /* 225 */ .long sys_setxattr diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S index d6a27f7a4c54..704ee8c5ee8a 100644 --- a/arch/sh/kernel/syscalls_64.S +++ b/arch/sh/kernel/syscalls_64.S @@ -276,7 +276,11 @@ sys_call_table: .long sys_getdents64 .long sys_fcntl64 .long sys_ni_syscall /* 250 reserved for TUX */ +#ifdef CONFIG_RSBAC + .long sys_rsbac +#else .long sys_ni_syscall /* Reserved for Security */ +#endif .long sys_gettid .long sys_readahead .long sys_setxattr diff --git a/arch/sparc/include/uapi/asm/unistd.h b/arch/sparc/include/uapi/asm/unistd.h index ae77df75bffa..1f086e1e53e6 100644 --- a/arch/sparc/include/uapi/asm/unistd.h +++ b/arch/sparc/include/uapi/asm/unistd.h @@ -427,8 +427,14 @@ #define __NR_pwritev2 359 #define __NR_statx 360 -#define NR_syscalls 361 +#ifdef CONFIG_RSBAC +#define __NR_rsbac 400 +#define NR_SYSCALLS 401 +#else +#define NR_syscalls 361 +#endif + /* Bitmask values returned from kern_features system call. */ #define KERN_FEATURE_MIXED_MODE_STACK 0x00000001 diff --git a/arch/sparc/kernel/ptrace_32.c b/arch/sparc/kernel/ptrace_32.c index eca3dc76793c..a19b9373baf5 100644 --- a/arch/sparc/kernel/ptrace_32.c +++ b/arch/sparc/kernel/ptrace_32.c @@ -28,6 +28,8 @@ #include "kernel.h" +#include + /* #define ALLOW_INIT_TRACING */ /* @@ -215,6 +217,28 @@ static int fpregs32_get(struct task_struct *target, const unsigned long *fpregs = target->thread.float_regs; int ret = 0; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + rsbac_pr_debug(aef, "calling ADF\n"); + rcu_read_lock(); + rsbac_target_id.process = find_pid_ns(pid, &init_pid_ns); + rsbac_attribute_value.trace_request = request; + if (!rsbac_adf_request(R_TRACE, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_trace_request, + rsbac_attribute_value)) + { + rcu_read_unlock(); + return -EPERM; + } + rcu_read_unlock(); +#endif + + #if 0 if (target == current) save_and_clear_fpu(); diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c index e1d965e90e16..d06d1c5490d9 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c @@ -40,6 +40,8 @@ #include #include +#include + #define CREATE_TRACE_POINTS #include @@ -918,9 +920,32 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, unsigned long data = cdata; int ret; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + pregs = (struct pt_regs32 __user *) addr; fps = (struct compat_fps __user *) addr; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rcu_read_lock(); + rsbac_target_id.process = task_pid(child); + rsbac_attribute_value.trace_request = request; + if (!rsbac_adf_request(R_TRACE, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_trace_request, + rsbac_attribute_value)) + { + rcu_read_unlock(); + return -EPERM; + } + rcu_read_unlock(); +#endif + switch (request) { case PTRACE_PEEKUSR: ret = (addr != 0) ? -EIO : 0; diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 5253e895b81b..e2e2690527ce 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -48,7 +48,11 @@ sys_call_table: /*145*/ .long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write /*150*/ .long sys_getsockname, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64 /*155*/ .long sys_fcntl64, sys_inotify_rm_watch, sys_statfs, sys_fstatfs, sys_oldumount +#ifdef CONFIG_RSBAC /* we use 164, which seems to be unused */ +/*160*/ .long sys_sched_setaffinity, sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_rsbac +#else /*160*/ .long sys_sched_setaffinity, sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall +#endif /*165*/ .long sys_quotactl, sys_set_tid_address, sys_mount, sys_ustat, sys_setxattr /*170*/ .long sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents /*175*/ .long sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 82339f6be0b2..43772a523f1e 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -50,7 +50,11 @@ sys_call_table32: .word compat_sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write /*150*/ .word sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64 .word compat_sys_fcntl64, sys_inotify_rm_watch, compat_sys_statfs, compat_sys_fstatfs, sys_oldumount +#ifdef CONFIG_RSBAC /* we use 164, which seems to be unused */ +/*160*/ .word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_rsbac +#else /*160*/ .word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall +#endif .word sys_quotactl, sys_set_tid_address, compat_sys_mount, compat_sys_ustat, sys_setxattr /*170*/ .word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, compat_sys_getdents .word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 448ac2161112..7d7c59cd623d 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -229,7 +229,7 @@ 220 i386 getdents64 sys_getdents64 221 i386 fcntl64 sys_fcntl64 compat_sys_fcntl64 # 222 is unused -# 223 is unused +223 i386 rsbac sys_rsbac 224 i386 gettid sys_gettid 225 i386 readahead sys_readahead sys32_readahead 226 i386 setxattr sys_setxattr diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 5aef183e2f85..0bddbf9d300e 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -191,7 +191,7 @@ 182 common putpmsg 183 common afs_syscall 184 common tuxcall -185 common security +185 common rsbac sys_rsbac 186 common gettid sys_gettid 187 common readahead sys_readahead 188 common setxattr sys_setxattr diff --git a/arch/x86/entry/syscalls/syscalltbl.sh b/arch/x86/entry/syscalls/syscalltbl.sh index 751d1f992630..4a8ea8439098 100644 --- a/arch/x86/entry/syscalls/syscalltbl.sh +++ b/arch/x86/entry/syscalls/syscalltbl.sh @@ -25,6 +25,14 @@ emit() { entry="$3" compat="$4" + # -z string; True if the length of string is zero + if [ -z "$CONFIG_RSBAC" ]; then + # exclude rsbac syscall + if [ "$entry" = "sys_rsbac" ]; then + return + fi + fi + if [ "$abi" = "64" -a -n "$compat" ]; then echo "a compat entry for a 64-bit syscall makes no sense" >&2 exit 1 diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c index 9c3cf0944bce..b71d082debd4 100644 --- a/arch/x86/kernel/ioport.c +++ b/arch/x86/kernel/ioport.c @@ -19,6 +19,8 @@ #include #include +#include + /* * this changes the io permissions bitmap in the current task. */ @@ -28,11 +30,31 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) struct tss_struct *tss; unsigned int i, max_long, bytes, bytes_updated; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) return -EINVAL; if (turn_on && !capable(CAP_SYS_RAWIO)) return -EPERM; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_ioports; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_PERMISSIONS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + /* * If it's the first ioperm() call in this thread's lifetime, set the * IO bitmap up. ioperm() is much less timing critical than clone(), @@ -116,6 +138,11 @@ SYSCALL_DEFINE1(iopl, unsigned int, level) */ unsigned int old = t->iopl >> X86_EFLAGS_IOPL_BIT; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (level > 3) return -EINVAL; /* Trying to gain more privileges? */ @@ -123,6 +150,22 @@ SYSCALL_DEFINE1(iopl, unsigned int, level) if (!capable(CAP_SYS_RAWIO)) return -EPERM; } + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_ioports; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_PERMISSIONS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << X86_EFLAGS_IOPL_BIT); t->iopl = level << X86_EFLAGS_IOPL_BIT; diff --git a/block/ioctl.c b/block/ioctl.c index 0de02ee67eed..33d542e67d25 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -10,6 +10,11 @@ #include #include +#ifdef CONFIG_RSBAC +#include +#include +#endif + static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg) { struct block_device *bdevp; @@ -509,6 +514,61 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, loff_t size; unsigned int max_sectors; +#ifdef CONFIG_RSBAC + enum rsbac_adf_request_t rsbac_request; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + rsbac_pr_debug(aef, "blkdev_ioctl(): calling ADF\n"); + + /* values taken from include/linux/fs.h and hdreg.h */ + switch (cmd) { + case BLKGETSIZE: /* Return device size */ + case BLKGETSIZE64: + case BLKROGET: + case BLKRAGET: + case BLKFRAGET: + case BLKSECTGET: + case BLKSSZGET: + case BLKBSZGET: + case HDIO_GETGEO: + case HDIO_OBSOLETE_IDENTITY: + case HDIO_GET_UNMASKINTR: + case HDIO_GET_IDENTITY: + case HDIO_GET_NICE: + case HDIO_GET_BUSSTATE: + case HDIO_GET_QDMA: + case HDIO_GET_MULTCOUNT: + case HDIO_GET_KEEPSETTINGS: + case HDIO_GET_32BIT: + case HDIO_GET_NOWERR: + case HDIO_GET_DMA: + case HDIO_GET_WCACHE: + case HDIO_GET_ACOUSTIC: + case HDIO_GET_ADDRESS: + rsbac_request = R_GET_STATUS_DATA; + break; + + default: + rsbac_request = R_MODIFY_SYSTEM_DATA; + } + + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(bdev->bd_dev); + rsbac_target_id.dev.minor = RSBAC_MINOR(bdev->bd_dev); + + rsbac_attribute_value.ioctl_cmd = cmd; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_DEV, + rsbac_target_id, + A_ioctl_cmd, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + switch (cmd) { case BLKFLSBUF: return blkdev_flushbuf(bdev, mode, cmd, arg); diff --git a/block/ioprio.c b/block/ioprio.c index 6f5d0b6625e3..ba81e8a3e730 100644 --- a/block/ioprio.c +++ b/block/ioprio.c @@ -30,6 +30,7 @@ #include #include #include +#include #include int set_task_ioprio(struct task_struct *task, int ioprio) @@ -71,6 +72,26 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio) kuid_t uid; int ret; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_priority; + rsbac_attribute_value.priority = ioprio; + + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_priority, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + switch (class) { case IOPRIO_CLASS_RT: if (!capable(CAP_SYS_ADMIN)) @@ -150,6 +171,27 @@ static int get_task_ioprio(struct task_struct *p) { int ret; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_priority; + rsbac_attribute_value.dummy = 0; + + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + ret = -EPERM; + goto out; + } +#endif + ret = security_task_getioprio(p); if (ret) goto out; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index ef8334949b42..5ad400208773 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -80,6 +80,8 @@ #include +#include + static DEFINE_IDR(loop_index_idr); static DEFINE_MUTEX(loop_index_mutex); @@ -882,6 +884,12 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, int error; loff_t size; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + /* This is safe, since we have a reference from open(). */ __module_get(THIS_MODULE); @@ -932,6 +940,46 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, if (error) goto out_putf; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[lo_ioctl()]: calling ADF for FILE/DEV\n"); + if (S_ISREG(inode->i_mode)) { + rsbac_target = T_FILE; + rsbac_target_id.dir.device = file->f_path.dentry->d_sb->s_dev; + rsbac_target_id.dir.inode = inode->i_ino; + rsbac_target_id.dir.dentry_p = file->f_path.dentry; + } + else { /* must be block */ + rsbac_target = T_DEV; + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(inode->i_rdev); + rsbac_target_id.dev.minor = RSBAC_MINOR(inode->i_rdev); + } + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MOUNT, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + goto out_putf; + } + rsbac_pr_debug(aef, "[lo_ioctl()]: calling ADF for DEV\n"); + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(bdev->bd_dev); + rsbac_target_id.dev.minor = RSBAC_MINOR(bdev->bd_dev); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MOUNT, + task_pid(current), + T_DEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + goto out_putf; + } +#endif + error = 0; set_device_ro(bdev, (lo_flags & LO_FLAGS_READ_ONLY) != 0); @@ -1023,6 +1071,12 @@ static int loop_clr_fd(struct loop_device *lo) gfp_t gfp = lo->old_gfp_mask; struct block_device *bdev = lo->lo_device; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (lo->lo_state != Lo_bound) return -ENXIO; @@ -1048,6 +1102,44 @@ static int loop_clr_fd(struct loop_device *lo) /* freeze request queue during the transition */ blk_mq_freeze_queue(lo->lo_queue); +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[lo_ioctl()]: calling ADF for FILE/DEV\n"); + if (S_ISREG(filp->f_path.dentry->d_inode->i_mode)) { + rsbac_target = T_FILE; + rsbac_target_id.dir.device = filp->f_path.dentry->d_sb->s_dev; + rsbac_target_id.dir.inode = filp->f_path.dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = filp->f_path.dentry; + } + else { /* must be block dev */ + rsbac_target = T_DEV; + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(filp->f_path.dentry->d_inode->i_rdev); + rsbac_target_id.dev.minor = RSBAC_MINOR(filp->f_path.dentry->d_inode->i_rdev); + } + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_UMOUNT, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } + rsbac_pr_debug(aef, "[lo_ioctl()]: calling ADF for DEV\n"); + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = LOOP_MAJOR; + rsbac_target_id.dev.minor = lo->lo_number; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_UMOUNT, + task_pid(current), + T_DEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + spin_lock_irq(&lo->lo_lock); lo->lo_state = Lo_rundown; lo->lo_backing_file = NULL; diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 593a8818aca9..3289e0408e0b 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -37,6 +37,8 @@ #define DEVPORT_MINOR 4 +#include + static inline unsigned long size_inside_page(unsigned long start, unsigned long size) { @@ -107,6 +109,11 @@ static ssize_t read_mem(struct file *file, char __user *buf, ssize_t read, sz; void *ptr; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (p != *ppos) return 0; @@ -141,6 +148,25 @@ static ssize_t read_mem(struct file *file, char __user *buf, /* Show zeros for restricted memory. */ remaining = clear_user(buf, sz); } else { +#ifdef CONFIG_RSBAC + rsbac_attribute_value.pagenr = p >> PAGE_SHIFT; + if (rsbac_is_videomem(rsbac_attribute_value.pagenr, count)) + rsbac_target_id.scd = ST_videomem; + else + rsbac_target_id.scd = ST_kmem; + rsbac_pr_debug(aef, "calling ADF\n"); + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_pagenr, + rsbac_attribute_value)) { + rsbac_printk(KERN_INFO "read_mem(): RSBAC denied read access to kernel mem page %u, size %u\n", + rsbac_attribute_value.pagenr, count); + return -EPERM; + } +#endif + /* * On ia64 if a page has been mapped somewhere as * uncached, then it must also be accessed uncached @@ -176,6 +202,11 @@ static ssize_t write_mem(struct file *file, const char __user *buf, unsigned long copied; void *ptr; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (p != *ppos) return -EFBIG; @@ -207,6 +238,25 @@ static ssize_t write_mem(struct file *file, const char __user *buf, /* Skip actual writing when a page is marked as restricted. */ if (allowed == 1) { +#ifdef CONFIG_RSBAC + rsbac_attribute_value.pagenr = p >> PAGE_SHIFT; + if (rsbac_is_videomem(rsbac_attribute_value.pagenr, sz)) + rsbac_target_id.scd = ST_videomem; + else + rsbac_target_id.scd = ST_kmem; + rsbac_pr_debug(aef, "calling ADF\n"); + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_pagenr, + rsbac_attribute_value)) { + rsbac_printk(KERN_INFO "write_mem(): RSBAC denied write access to kernel mem page %u, size %u\n", + rsbac_attribute_value.pagenr, sz); + return -EPERM; + } +#endif + /* * On ia64 if a page has been mapped somewhere as * uncached, then it must also be accessed uncached @@ -342,6 +392,11 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma) size_t size = vma->vm_end - vma->vm_start; phys_addr_t offset = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + /* It's illegal to wrap around the end of the physical address space. */ if (offset + (phys_addr_t)size - 1 < offset) return -EINVAL; @@ -359,6 +414,25 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma) &vma->vm_page_prot)) return -EINVAL; +#ifdef CONFIG_RSBAC + rsbac_attribute_value.pagenr = vma->vm_pgoff; + if (rsbac_is_videomem(rsbac_attribute_value.pagenr, size)) + rsbac_target_id.scd = ST_videomem; + else + rsbac_target_id.scd = ST_kmem; + rsbac_pr_debug(aef, "calling ADF\n"); + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_pagenr, + rsbac_attribute_value)) { + rsbac_printk(KERN_INFO "mmap_mem(): RSBAC denied mmap access to kernel mem page %u, size %u\n", + rsbac_attribute_value.pagenr, size); + return -EPERM; + } +#endif + vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, size, vma->vm_page_prot); diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c index 3661abb16a5f..dfafa2fe5847 100644 --- a/drivers/ide/ide-ioctls.c +++ b/drivers/ide/ide-ioctls.c @@ -6,6 +6,7 @@ #include #include #include +#include static const struct ide_ioctl_devset ide_ioctl_settings[] = { { HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit }, @@ -237,6 +238,58 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev, { int err; +#ifdef CONFIG_RSBAC + enum rsbac_adf_request_t rsbac_request; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + rsbac_pr_debug(aef, "calling ADF\n"); + /* values taken from include/linux/fs.h and hdreg.h */ + switch (cmd) { + case BLKGETSIZE: /* Return device size */ + case BLKGETSIZE64: + case BLKROGET: + case BLKRAGET: + case BLKFRAGET: + case BLKSECTGET: + case BLKSSZGET: + case BLKBSZGET: + case HDIO_GETGEO: + case HDIO_OBSOLETE_IDENTITY: + case HDIO_GET_UNMASKINTR: + case HDIO_GET_IDENTITY: + case HDIO_GET_NICE: + case HDIO_GET_BUSSTATE: + case HDIO_GET_QDMA: + case HDIO_GET_MULTCOUNT: + case HDIO_GET_KEEPSETTINGS: + case HDIO_GET_32BIT: + case HDIO_GET_NOWERR: + case HDIO_GET_DMA: + case HDIO_GET_WCACHE: + case HDIO_GET_ACOUSTIC: + case HDIO_GET_ADDRESS: + rsbac_request = R_GET_STATUS_DATA; + break; + + default: + rsbac_request = R_MODIFY_SYSTEM_DATA; + } + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(bdev->bd_dev); + rsbac_target_id.dev.minor = RSBAC_MINOR(bdev->bd_dev); + rsbac_attribute_value.ioctl_cmd = cmd; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_DEV, + rsbac_target_id, + A_ioctl_cmd, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings); if (err != -EOPNOTSUPP) return err; diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 3ffc1ce29023..44469a54c511 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -53,6 +53,11 @@ #include #include +#ifdef CONFIG_RSBAC +#include +#include +#endif + /* Whether we react on sysrq keys or just ignore them */ static int __read_mostly sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE; static bool __read_mostly sysrq_always_enabled; @@ -198,6 +203,24 @@ static struct sysrq_key_op sysrq_mountro_op = { .enable_mask = SYSRQ_ENABLE_REMOUNT, }; +#ifdef CONFIG_RSBAC_SOFTMODE_SYSRQ +static void sysrq_handle_rsbac_softmode(int key) { + if (rsbac_softmode) { + rsbac_printk(KERN_WARNING "Soft mode disabled via SysRq!\n"); + rsbac_softmode = 0; + } + else { + rsbac_printk(KERN_WARNING "Soft mode enabled via SysRq!\n"); + rsbac_softmode = 1; + } +} +static struct sysrq_key_op sysrq_rsbac_softmode_op = { + handler: sysrq_handle_rsbac_softmode, + help_msg: "rsbac_toggle_softmode_X", + action_msg: "RSBAC toggle softmode\n", +}; +#endif + #ifdef CONFIG_LOCKDEP static void sysrq_handle_showlocks(int key) { @@ -481,7 +504,11 @@ static struct sysrq_key_op *sysrq_key_table[36] = { /* x: May be registered on mips for TLB dump */ /* x: May be registered on ppc/powerpc for xmon */ /* x: May be registered on sparc64 for global PMU dump */ +#ifdef CONFIG_RSBAC_SOFTMODE_SYSRQ + &sysrq_rsbac_softmode_op, /* x */ +#else NULL, /* x */ +#endif /* y: May be registered on sparc64 for global register dump */ NULL, /* y */ &sysrq_ftrace_dump_op, /* z */ diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 974b13d24401..9ff880f4b923 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -106,6 +106,8 @@ #include #include +#include + #undef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP # define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args) @@ -2044,10 +2046,33 @@ static int tiocsti(struct tty_struct *tty, char __user *p) char ch, mbz = 0; struct tty_ldisc *ld; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) return -EPERM; if (get_user(ch, p)) return -EFAULT; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.dev.type = D_char; + rsbac_target_id.dev.major = tty->driver->major; + rsbac_target_id.dev.minor = tty->driver->minor_start + tty->index; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEND, + task_pid(current), + T_DEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + tty_audit_tiocsti(tty, ch); ld = tty_ldisc_ref_wait(tty); if (!ld) diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index efa96e6c4c1b..f3e13d6c8638 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -24,6 +24,8 @@ #include #include +#include + #undef TTY_DEBUG_WAIT_UNTIL_SENT #ifdef TTY_DEBUG_WAIT_UNTIL_SENT @@ -712,14 +714,57 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, int ret = 0; struct ktermios kterm; - BUG_ON(file == NULL); +#ifdef CONFIG_RSBAC + enum rsbac_adf_request_t rsbac_request; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + BUG_ON(file == NULL); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) real_tty = tty->link; else real_tty = tty; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + switch (cmd) { +#ifdef TIOCGETP + case TIOCGETP: +#endif +#ifdef TIOCGETC + case TIOCGETC: +#endif +#ifdef TIOCGLTC + case TIOCGLTC: +#endif + case TCGETS: + case TCGETA: + case TIOCOUTQ: + case TIOCINQ: + case TIOCGLCKTRMIOS: + case TIOCGSOFTCAR: + rsbac_request = R_GET_PERMISSIONS_DATA; + break; + default: + rsbac_request = R_MODIFY_PERMISSIONS_DATA; + } + rsbac_target_id.dev.type = D_char; + rsbac_target_id.dev.major = tty->driver->major; + rsbac_target_id.dev.minor = tty->driver->minor_start + tty->index; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_DEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + switch (cmd) { #ifdef TIOCGETP case TIOCGETP: diff --git a/fs/dcache.c b/fs/dcache.c index f90141387f01..81dcd72cfd7d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1466,12 +1466,14 @@ static enum d_walk_ret umount_check(void *_data, struct dentry *dentry) if (dentry == _data && dentry->d_lockref.count == 1) return D_WALK_CONTINUE; - printk(KERN_ERR "BUG: Dentry %p{i=%lx,n=%pd} " + printk(KERN_CRIT "BUG: Dentry %p{i=%lx,n=%pd} name %s" " still in use (%d) [unmount of %s %s]\n", dentry, dentry->d_inode ? dentry->d_inode->i_ino : 0UL, dentry, + dentry->d_name.name ? + dentry->d_name.name : (const unsigned char *) "_unknown_", dentry->d_lockref.count, dentry->d_sb->s_type->name, dentry->d_sb->s_id); diff --git a/fs/exec.c b/fs/exec.c index 62175cbcc801..8836cf8ebe9c 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -72,6 +72,8 @@ #include +#include + int suid_dumpable = 0; static LIST_HEAD(formats); @@ -130,6 +132,11 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) .lookup_flags = LOOKUP_FOLLOW, }; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (IS_ERR(tmp)) goto out; @@ -147,6 +154,26 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) if (path_noexec(&file->f_path)) goto exit; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.file.device = file->f_path.dentry->d_inode->i_sb->s_dev; + rsbac_target_id.file.inode = file->f_path.dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = file->f_path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MAP_EXEC, + task_pid(current), + T_FILE, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + rsbac_pr_debug(aef, "request not granted, my PID: %i\n", + task_pid(current)); + error = -EPERM; + goto exit; + } +#endif + fsnotify_open(file); error = -ENOEXEC; @@ -166,6 +193,28 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) } read_unlock(&binfmt_lock); exit: + + /* RSBAC: notify ADF of mapped segment */ +#ifdef CONFIG_RSBAC + if (!error) { + union rsbac_target_id_t rsbac_new_target_id; + + rsbac_pr_debug(aef, "calling ADF_set_attr\n"); + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_MAP_EXEC, + task_pid(current), + T_FILE, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_uselib(): rsbac_adf_set_attr() returned error\n"); + } + } +#endif + fput(file); out: return error; @@ -1690,6 +1739,12 @@ static int do_execveat_common(int fd, struct filename *filename, struct files_struct *displaced; int retval; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (IS_ERR(filename)) return PTR_ERR(filename); @@ -1768,6 +1823,25 @@ static int do_execveat_common(int fd, struct filename *filename, if ((retval = bprm->envc) < 0) goto out; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_execve()]: calling ADF\n"); + rsbac_target_id.file.device = file->f_path.dentry->d_sb->s_dev; + rsbac_target_id.file.inode = file->f_path.dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = file->f_path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_EXECUTE, + task_pid(current), + T_FILE, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "[sys_execve()]: request not granted, my PID: %i\n", + task_pid(current)); + retval = -EPERM; + goto out; + } +#endif + retval = prepare_binprm(bprm); if (retval < 0) goto out; @@ -1791,6 +1865,25 @@ static int do_execveat_common(int fd, struct filename *filename, if (retval < 0) goto out; +/* RSBAC: notify ADF of changed program in this process + * Most structures are already filled + */ +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_execve()]: calling ADF_set_attr\n"); + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_EXECUTE, + task_pid(current), + T_FILE, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "do_execve() [sys_execve]: rsbac_adf_set_attr() returned error\n"); + } +#endif + /* execve succeeded */ current->fs->in_exec = 0; current->in_execve = 0; diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index 087f122cca42..65cb2ff3c485 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -16,6 +16,10 @@ #include #include +#ifdef CONFIG_RSBAC +#include +#include +#endif long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -25,6 +29,73 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) unsigned short rsv_window_size; int ret; +#ifdef CONFIG_RSBAC + enum rsbac_adf_request_t rsbac_request; + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + switch (cmd) { + case EXT2_IOC_GETFLAGS: + case EXT2_IOC_GETVERSION: + rsbac_request = R_GET_PERMISSIONS_DATA; + break; + case EXT2_IOC_SETFLAGS: + case EXT2_IOC_SETVERSION: + rsbac_request = R_MODIFY_PERMISSIONS_DATA; + break; + default: + rsbac_request = R_NONE; + } + if(S_ISSOCK(inode->i_mode)) { + if(SOCKET_I(inode)->ops + && (SOCKET_I(inode)->ops->family == AF_UNIX)) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = filp->f_path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = inode->i_ino; + rsbac_target_id.unixsock.dentry_p = filp->f_path.dentry; + } +#ifdef CONFIG_RSBAC_NET_OBJ + else { + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p + = SOCKET_I(inode); + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; + } +#endif + } + else { + if (S_ISDIR(inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(inode->i_mode)) + rsbac_target = T_SYMLINK; + else + rsbac_target = T_FILE; + rsbac_target_id.file.device = filp->f_path.dentry->d_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = filp->f_path.dentry; + } + rsbac_attribute_value.ioctl_cmd = cmd; + if( (rsbac_request != R_NONE) + && !rsbac_adf_request(rsbac_request, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_ioctl_cmd, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); switch (cmd) { diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 814e405a2da6..a29bff0a3f5b 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -36,6 +36,8 @@ #include "xattr.h" #include "acl.h" +#include + static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode) { int err = ext2_add_link(dentry, inode); @@ -304,6 +306,11 @@ static int ext2_unlink(struct inode * dir, struct dentry *dentry) if (err) goto out; +#ifdef CONFIG_RSBAC_SECDEL + if (inode->i_nlink == 1) + rsbac_sec_del(dentry, TRUE); +#endif + inode->i_ctime = dir->i_ctime; inode_dec_link_count(inode); err = 0; @@ -375,6 +382,12 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page); if (!new_de) goto out_dir; + +#ifdef CONFIG_RSBAC_SECDEL + if (new_inode->i_nlink == 1) + rsbac_sec_del(new_dentry, TRUE); +#endif + ext2_set_link(new_dir, new_de, new_page, old_inode, 1); new_inode->i_ctime = current_time(new_inode); if (dir_de) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index afb66d4ab5cf..e6eb5455b3f5 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -583,6 +583,11 @@ static int ext4_ioc_getfsmap(struct super_block *sb, return 0; } +#ifdef CONFIG_RSBAC +#include +#endif +#include + long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = file_inode(filp); @@ -590,6 +595,77 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct ext4_inode_info *ei = EXT4_I(inode); unsigned int flags; +#ifdef CONFIG_RSBAC + enum rsbac_adf_request_t rsbac_request; + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + rsbac_pr_debug(aef, "calling ADF\n"); + switch (cmd) { + case EXT4_IOC_GETFLAGS: + case EXT4_IOC_GETVERSION: + case EXT4_IOC_GETVERSION_OLD: + case EXT4_IOC_GETRSVSZ: + rsbac_request = R_GET_PERMISSIONS_DATA; + break; + case EXT4_IOC_SETFLAGS: + case EXT4_IOC_SETVERSION: + case EXT4_IOC_SETVERSION_OLD: + case EXT4_IOC_SETRSVSZ: + case EXT4_IOC_GROUP_EXTEND: + case EXT4_IOC_GROUP_ADD: + case EXT4_IOC_MIGRATE: + rsbac_request = R_MODIFY_PERMISSIONS_DATA; + break; + default: + rsbac_request = R_NONE; + } + if(S_ISSOCK(inode->i_mode)) { + if(SOCKET_I(inode)->ops + && (SOCKET_I(inode)->ops->family == AF_UNIX)) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = filp->f_path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = inode->i_ino; + rsbac_target_id.unixsock.dentry_p = filp->f_path.dentry; + } +#ifdef CONFIG_RSBAC_NET_OBJ + else { + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p + = SOCKET_I(inode); + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; + } +#endif + } + else { + if (S_ISDIR(inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(inode->i_mode)) + rsbac_target = T_SYMLINK; + else + rsbac_target = T_FILE; + rsbac_target_id.file.device = filp->f_path.dentry->d_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = filp->f_path.dentry; + } + rsbac_attribute_value.ioctl_cmd = cmd; + if( (rsbac_request != R_NONE) + && !rsbac_adf_request(rsbac_request, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_ioctl_cmd, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + ext4_debug("cmd = %u, arg = %lu\n", cmd, arg); switch (cmd) { diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index c1cf020d1889..fcb522d515fb 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -40,6 +40,9 @@ #include "acl.h" #include + +#include + /* * define how far ahead to read directories while searching them. */ @@ -2937,6 +2940,12 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry) inode = d_inode(dentry); +#ifdef CONFIG_RSBAC_SECDEL + if(inode->i_nlink == 1) { + rsbac_sec_del(dentry, TRUE); + } +#endif + retval = -EFSCORRUPTED; if (le32_to_cpu(de->inode) != inode->i_ino) goto end_rmdir; @@ -3634,6 +3643,19 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, if (retval) goto end_rename; } else { + +#ifdef CONFIG_RSBAC_SECDEL + if(new.inode->i_nlink == 1) { + ext4_journal_stop(handle); + rsbac_sec_del(new.dentry, TRUE); + handle = ext4_journal_start(old.dir, EXT4_HT_DIR, credits); + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) + ext4_handle_sync(handle); + } +#endif + retval = ext4_setent(handle, &new, old.inode->i_ino, old_file_type); if (retval) diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index 7d6a105d601b..e2cf3ace155d 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -7,6 +7,7 @@ */ #include +#include #include "fat.h" /* Characters that are undesirable in an MS-DOS file name */ @@ -418,6 +419,9 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry) clear_nlink(inode); inode->i_ctime = current_time(inode); fat_detach(inode); +#ifdef CONFIG_RSBAC_SECDEL + rsbac_sec_del(dentry, TRUE); +#endif out: mutex_unlock(&MSDOS_SB(sb)->s_lock); if (!err) @@ -510,6 +514,11 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, } new_dir->i_version++; +#ifdef CONFIG_RSBAC_SECDEL + if (new_inode && (new_inode->i_nlink == 1)) + rsbac_sec_del(new_dentry, TRUE); +#endif + fat_detach(old_inode); fat_attach(old_inode, new_i_pos); if (is_hid) diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 6a7152d0c250..b100ea7a4f63 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "fat.h" static inline unsigned long vfat_d_version(struct dentry *dentry) @@ -854,6 +855,10 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry) if (err) goto out; +#ifdef CONFIG_RSBAC_SECDEL + rsbac_sec_del(dentry, TRUE); +#endif + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ if (err) goto out; @@ -953,6 +958,11 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, if (err) goto out; } +#ifdef CONFIG_RSBAC_SECDEL + else + if(new_inode->i_nlink == 1) + rsbac_sec_del(new_dentry, TRUE); +#endif new_i_pos = MSDOS_I(new_inode)->i_pos; fat_detach(new_inode); } else { diff --git a/fs/ioctl.c b/fs/ioctl.c index 569db68d02b3..9cd2d284cdda 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -21,6 +21,11 @@ #include +#ifdef CONFIG_RSBAC_IOCTL +#include +#endif +#include + /* So that the fiemap access checks can't overflow on 32 bit machines. */ #define FIEMAP_MAX_EXTENTS (UINT_MAX / sizeof(struct fiemap_extent)) @@ -39,9 +44,78 @@ long vfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int error = -ENOTTY; +#ifdef CONFIG_RSBAC_IOCTL + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!filp->f_op->unlocked_ioctl) goto out; +#ifdef CONFIG_RSBAC_IOCTL + if (S_ISBLK(filp->f_path.dentry->d_inode->i_mode)) { + rsbac_target = T_DEV; + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(filp->f_path.dentry->d_inode->i_rdev); + rsbac_target_id.dev.minor = RSBAC_MINOR(filp->f_path.dentry->d_inode->i_rdev); + } + else + if (S_ISCHR(filp->f_path.dentry->d_inode->i_mode)) { + rsbac_target = T_DEV; + rsbac_target_id.dev.type = D_char; + rsbac_target_id.dev.major = RSBAC_MAJOR(filp->f_path.dentry->d_inode->i_rdev); + rsbac_target_id.dev.minor = RSBAC_MINOR(filp->f_path.dentry->d_inode->i_rdev); + } + else + if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode)) { + if ( SOCKET_I(filp->f_path.dentry->d_inode)->ops + && (SOCKET_I(filp->f_path.dentry->d_inode)->ops->family == AF_UNIX) + ) { + if (filp->f_path.dentry->d_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = filp->f_path.dentry->d_inode->i_ino; + } + else { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = filp->f_path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = filp->f_path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = filp->f_path.dentry; + } + } + else { +#ifdef CONFIG_RSBAC_NET_OBJ + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p + = SOCKET_I(filp->f_path.dentry->d_inode); + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; +#else + rsbac_target = T_NONE; +#endif + } + } + else + rsbac_target = T_NONE; + if (rsbac_target != T_NONE) { + rsbac_pr_debug(aef, "[sys_ioctl()]: calling ADF\n"); + rsbac_attribute_value.ioctl_cmd = cmd; + if (!rsbac_adf_request(R_IOCTL, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_ioctl_cmd, + rsbac_attribute_value)) + { + error = -EPERM; + goto out; + } + } +#endif + error = filp->f_op->unlocked_ioctl(filp, cmd, arg); if (error == -ENOIOCTLCMD) error = -ENOTTY; diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 8b08044b3120..cdfbf8511219 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -2494,6 +2494,11 @@ static int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode, return -EROFS; journal = transaction->t_journal; +#ifdef CONFIG_RSBAC + if (!jinode) + return 0; +#endif + jbd_debug(4, "Adding inode %lu, tid:%d\n", jinode->i_vfs_inode->i_ino, transaction->t_tid); diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index b41596d71858..4ef786eaf82c 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -33,6 +33,8 @@ #include "jfs_acl.h" #include "jfs_debug.h" +#include + /* * forward references */ @@ -501,6 +503,12 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) if ((rc = get_UCSname(&dname, dentry))) goto out; + /* RSBAC jfs_unlink */ +#ifdef CONFIG_RSBAC_SECDEL + if(dentry->d_inode->i_nlink == 1) + rsbac_sec_del(dentry, TRUE); +#endif + IWRITE_LOCK(ip, RDWRLOCK_NORMAL); tid = txBegin(dip->i_sb, 0); @@ -1153,6 +1161,10 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, } } } else if (new_ip) { +#ifdef CONFIG_RSBAC_SECDEL + if (new_ip->i_nlink == 1) + rsbac_sec_del(new_dentry, TRUE); +#endif IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL); /* Init inode for quota operations. */ rc = dquot_initialize(new_ip); diff --git a/fs/locks.c b/fs/locks.c index afefeb4ad6de..44ef2157c4cc 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -133,6 +133,8 @@ #include +#include + #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) #define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK) #define IS_LEASE(fl) (fl->fl_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT)) @@ -1990,6 +1992,12 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) int can_sleep, unlock; int error; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + error = -EBADF; if (!f.file) goto out; @@ -2015,6 +2023,38 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) if (error) goto out_free; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target = T_FILE; + rsbac_target_id.file.device = f.file->f_path.dentry->d_sb->s_dev; + rsbac_target_id.file.inode = f.file->f_path.dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = f.file->f_path.dentry; + if (S_ISDIR(f.file->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(f.file->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(f.file->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(f.file->f_path.dentry->d_inode->i_mode)) { + if(f.file->f_path.dentry->d_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = f.file->f_path.dentry->d_inode->i_ino; + } else + rsbac_target = T_UNIXSOCK; + } + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_LOCK, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + goto out_free; + } +#endif + if (f.file->f_op->flock && is_remote_lock(f.file)) error = f.file->f_op->flock(f.file, (can_sleep) ? F_SETLKW : F_SETLK, @@ -2089,6 +2129,12 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock) struct file_lock file_lock; int error; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + error = -EINVAL; if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK) goto out; @@ -2107,6 +2153,32 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock) file_lock.fl_owner = filp; } +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_fcntl()]: calling ADF\n"); + rsbac_target = T_FILE; + if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(filp->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(filp->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_UNIXSOCK; + rsbac_target_id.file.device = filp->f_path.dentry->d_sb->s_dev; + rsbac_target_id.file.inode = filp->f_path.dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = filp->f_path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + goto out; + } +#endif + error = vfs_test_lock(filp, &file_lock); if (error) goto out; @@ -2216,6 +2288,12 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, struct file *f; int error; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (file_lock == NULL) return -ENOLCK; @@ -2262,6 +2340,38 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, file_lock->fl_flags |= FL_SLEEP; } +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_fcntl()]: calling ADF\n"); + rsbac_target = T_FILE; + rsbac_target_id.file.device = filp->f_path.dentry->d_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = filp->f_path.dentry; + if (S_ISDIR(inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode)) { + if(filp->f_path.dentry->d_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = filp->f_path.dentry->d_inode->i_ino; + } else + rsbac_target = T_UNIXSOCK; + } + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_LOCK, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + goto out; + } +#endif + error = do_lock_file_wait(filp, cmd, file_lock); /* @@ -2301,6 +2411,12 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock) struct file_lock file_lock; int error; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + error = -EINVAL; if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK) goto out; @@ -2319,6 +2435,32 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock) file_lock.fl_owner = filp; } +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_fcntl()]: calling ADF\n"); + rsbac_target = T_FILE; + if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(filp->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(filp->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_UNIXSOCK; + rsbac_target_id.file.device = filp->f_path.dentry->d_sb->s_dev; + rsbac_target_id.file.inode = filp->f_path.dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = filp->f_path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + goto out; + } +#endif + error = vfs_test_lock(filp, &file_lock); if (error) goto out; @@ -2343,6 +2485,12 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, struct file *f; int error; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (file_lock == NULL) return -ENOLCK; @@ -2389,6 +2537,38 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, file_lock->fl_flags |= FL_SLEEP; } +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_fcntl()]: calling ADF\n"); + rsbac_target = T_FILE; + rsbac_target_id.file.device = filp->f_path.dentry->d_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = filp->f_path.dentry; + if (S_ISDIR(inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode)) { + if(filp->f_path.dentry->d_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = filp->f_path.dentry->d_inode->i_ino; + } else + rsbac_target = T_UNIXSOCK; + } + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_LOCK, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + goto out; + } +#endif + error = do_lock_file_wait(filp, cmd, file_lock); /* diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 1e0f11f5dac9..b0e3d5d6c6b7 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -6,6 +6,8 @@ #include "minix.h" +#include + static int add_nondir(struct dentry *dentry, struct inode *inode) { int err = minix_add_link(dentry, inode); @@ -163,6 +165,11 @@ static int minix_unlink(struct inode * dir, struct dentry *dentry) if (err) goto end_unlink; +#ifdef CONFIG_RSBAC_SECDEL + if (inode->i_nlink == 1) + rsbac_sec_del(dentry, TRUE); +#endif + inode->i_ctime = dir->i_ctime; inode_dec_link_count(inode); end_unlink: @@ -222,6 +229,12 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry, new_de = minix_find_entry(new_dentry, &new_page); if (!new_de) goto out_dir; + +#ifdef CONFIG_RSBAC_SECDEL + if (new_inode->i_nlink == 1) + rsbac_sec_del(new_dentry, TRUE); +#endif + minix_set_link(new_de, new_page, old_inode); new_inode->i_ctime = current_time(new_inode); if (dir_de) diff --git a/fs/namei.c b/fs/namei.c index ddb6a7c2b3d4..77aee6746e4f 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -38,6 +38,10 @@ #include #include #include +#ifdef CONFIG_RSBAC +#include +#include +#endif #include "internal.h" #include "mount.h" @@ -1024,6 +1028,14 @@ const char *get_link(struct nameidata *nd) int error; const char *res; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#ifdef CONFIG_RSBAC_SYM_REDIR + char * rsbac_name = NULL; +#endif +#endif + if (!(nd->flags & LOOKUP_RCU)) { touch_atime(&last->link); cond_resched(); @@ -1038,6 +1050,28 @@ const char *get_link(struct nameidata *nd) if (unlikely(error)) return ERR_PTR(error); +#ifdef CONFIG_RSBAC + if (dentry->d_sb && dentry->d_inode) { + rsbac_target_id.symlink.device = dentry->d_sb->s_dev; + rsbac_target_id.symlink.inode = dentry->d_inode->i_ino; + rsbac_target_id.symlink.dentry_p = dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + T_SYMLINK, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + error = -ENOENT; +#else + error = -EPERM; +#endif + return ERR_PTR(error); + } + } +#endif + nd->last_type = LAST_BIND; res = inode->i_link; if (!res) { @@ -1057,16 +1091,45 @@ const char *get_link(struct nameidata *nd) if (IS_ERR_OR_NULL(res)) return res; } + +#ifdef CONFIG_RSBAC_SYM_REDIR + if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) { + rsbac_name = rsbac_symlink_redirect(dentry->d_inode, res, PATH_MAX, FALSE); + if (rsbac_name) + res = rsbac_name; + } +#endif + if (*res == '/') { if (!nd->root.mnt) set_root(nd); - if (unlikely(nd_jump_root(nd))) + if (unlikely(nd_jump_root(nd))) { + +#ifdef CONFIG_RSBAC_SYM_REDIR + if (rsbac_name) + kfree(rsbac_name); +#endif + return ERR_PTR(-ECHILD); + } while (unlikely(*++res == '/')) ; } - if (!*res) + if (!*res) { + +#ifdef CONFIG_RSBAC_SYM_REDIR + if (rsbac_name) + kfree(rsbac_name); +#endif + res = NULL; + } + +#ifdef CONFIG_RSBAC_SYM_REDIR + else if (rsbac_name) + rsbac_delayed_kfree(rsbac_name, 120); +#endif + return res; } @@ -1543,6 +1606,11 @@ static int lookup_fast(struct nameidata *nd, int status = 1; int err; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + /* * Rename seqlock is not required here because in the off chance * of a false negative due to a concurrent rename, the caller is @@ -1615,6 +1683,32 @@ static int lookup_fast(struct nameidata *nd, path->mnt = mnt; path->dentry = dentry; + +#ifdef CONFIG_RSBAC + if ( dentry + && dentry->d_inode + && dentry->d_inode->i_sb + ) { + rsbac_target_id.dir.device = dentry->d_inode->i_sb->s_dev; + rsbac_target_id.dir.inode = dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + dput(dentry); +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + return -ENOENT; +#else + return -EPERM; +#endif + } + } +#endif + err = follow_managed(path, nd); if (likely(err > 0)) *inode = d_backing_inode(path->dentry); @@ -2043,6 +2137,11 @@ static int link_path_walk(const char *name, struct nameidata *nd) { int err; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + while (*name=='/') name++; if (!*name) @@ -2057,6 +2156,27 @@ static int link_path_walk(const char *name, struct nameidata *nd) if (err) return err; +#ifdef CONFIG_RSBAC + if (nd->inode->i_sb) { + rsbac_target_id.dir.device = nd->inode->i_sb->s_dev; + rsbac_target_id.dir.inode = nd->inode->i_ino; + rsbac_target_id.dir.dentry_p = nd->path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + return -ENOENT; +#else + return -EPERM; +#endif + } + } +#endif + hash_len = hash_name(nd->path.dentry, name); type = LAST_NORM; @@ -2137,6 +2257,22 @@ static int link_path_walk(const char *name, struct nameidata *nd) } return -ENOTDIR; } +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + if (nd->inode->i_sb) { + rsbac_target_id.dir.device = nd->inode->i_sb->s_dev; + rsbac_target_id.dir.inode = nd->inode->i_ino; + rsbac_target_id.dir.dentry_p = nd->path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -ENOENT; + } + } +#endif } } @@ -2584,6 +2720,51 @@ int path_pts(struct path *path) } #endif +/* RSBAC + * I hate to put new functions into this file, but even more I hate removing + * all statics from all the lookup helpers in here... + * Still, I need some form of RSBAC bypass for internal file access. + * Amon Ott + */ +#ifdef CONFIG_RSBAC +struct dentry *rsbac_lookup_one_len(const char *name, struct dentry *base, int len) +{ + struct qstr this; + unsigned int c; + + WARN_ON_ONCE(!inode_is_locked(base->d_inode)); + + this.name = name; + this.len = len; + this.hash = full_name_hash(base, name, len); + if (!len) + return ERR_PTR(-EACCES); + + if (unlikely(name[0] == '.')) { + if (len < 2 || (len == 2 && name[1] == '.')) + return ERR_PTR(-EACCES); + } + + while (len--) { + c = *(const unsigned char *)name++; + if (c == '/' || c == '\0') + return ERR_PTR(-EACCES); + } + /* + * See if the low-level filesystem might want + * to use its own hash.. + */ + if (base->d_flags & DCACHE_OP_HASH) { + int err = base->d_op->d_hash(base, &this); + if (err < 0) + return ERR_PTR(err); + } + + return __lookup_hash(&this, base, 0); +} +EXPORT_SYMBOL(rsbac_lookup_one_len); +#endif + int user_path_at_empty(int dfd, const char __user *name, unsigned flags, struct path *path, int *empty) { @@ -2881,6 +3062,15 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool want_excl) { int error = may_create(dir, dentry); + +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + enum rsbac_target_t rsbac_new_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (error) return error; @@ -2891,9 +3081,68 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, error = security_inode_create(dir, dentry, mode); if (error) return error; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "vfs_create() [open_namei() [filp_open() [do_open() [sys_open()]]]]: calling ADF\n"); + rsbac_target = T_DIR; + rsbac_target_id.dir.device = dir->i_sb->s_dev; + rsbac_target_id.dir.inode = dir->i_ino; + rsbac_target_id.dir.dentry_p = dentry->d_parent; + if (S_ISDIR(mode)) + rsbac_attribute_value.create_data.target = T_DIR; + else if (S_ISSOCK(mode)) + rsbac_attribute_value.create_data.target = T_UNIXSOCK; + else if (S_ISFIFO(mode)) + rsbac_attribute_value.create_data.target = T_FIFO; + else + rsbac_attribute_value.create_data.target = T_FILE; + rsbac_attribute_value.create_data.dentry_p = dentry; + rsbac_attribute_value.create_data.mode = mode; + rsbac_attribute_value.create_data.device = 0; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_create_data, + rsbac_attribute_value)) + return -EPERM; +#endif + error = dir->i_op->create(dir, dentry, mode, want_excl); - if (!error) + if (!error) { + /* RSBAC: notify ADF of new fs object */ +#ifdef CONFIG_RSBAC + if (dentry->d_inode) { + if (S_ISDIR(dentry->d_inode->i_mode)) + rsbac_new_target = T_DIR; + else if (S_ISSOCK(dentry->d_inode->i_mode)) + rsbac_new_target = T_UNIXSOCK; + else if (S_ISFIFO(dentry->d_inode->i_mode)) { + if (dentry->d_inode->i_sb->s_magic != PIPEFS_MAGIC) + rsbac_new_target = T_FIFO; + else + rsbac_new_target = T_NONE; + } else + rsbac_new_target = T_FILE; + rsbac_new_target_id.file.device = dentry->d_inode->i_sb->s_dev; + rsbac_new_target_id.file.inode = dentry->d_inode->i_ino; + rsbac_new_target_id.file.dentry_p = dentry; + if (unlikely(rsbac_adf_set_attr(R_CREATE, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_new_target, + rsbac_new_target_id, + A_create_data, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "vfs_create() [open_namei() [filp_open() [do_open() [sys_open()]]]]: rsbac_adf_set_attr() returned error"); + } + } +#endif + fsnotify_create(dir, dentry); + } return error; } EXPORT_SYMBOL(vfs_create); @@ -3023,12 +3272,41 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, struct inode *dir = nd->path.dentry->d_inode; int error; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + enum rsbac_target_t rsbac_new_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!(~open_flag & (O_EXCL | O_CREAT))) /* both O_EXCL and O_CREAT */ open_flag &= ~O_TRUNC; if (nd->flags & LOOKUP_DIRECTORY) open_flag |= O_DIRECTORY; +#ifdef CONFIG_RSBAC + if (open_flag & O_CREAT) { + rsbac_pr_debug(aef, "atomic_open() [lookup_open() [do_last() [path_openat() [do_filp_open()]]]]: calling ADF\n"); + rsbac_target = T_DIR; + rsbac_target_id.dir.device = dir->i_sb->s_dev; + rsbac_target_id.dir.inode = dir->i_ino; + rsbac_target_id.dir.dentry_p = dentry->d_parent; + rsbac_attribute_value.mode = mode; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_mode, + rsbac_attribute_value)) { + d_lookup_done(dentry); + dput(dentry); + return -EPERM; + } + } +#endif + file->f_path.dentry = DENTRY_NOT_SET; file->f_path.mnt = nd->path.mnt; error = dir->i_op->atomic_open(dir, dentry, file, @@ -3068,6 +3346,28 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, } } } + + /* RSBAC: notify ADF of new file */ +#ifdef CONFIG_RSBAC + if (!error && (rsbac_target != T_NONE)) { + rsbac_new_target = T_FILE; + rsbac_new_target_id.file.device = dentry->d_sb->s_dev; + rsbac_new_target_id.file.inode = dentry->d_inode->i_ino; + rsbac_new_target_id.file.dentry_p = dentry; + if (unlikely(rsbac_adf_set_attr(R_CREATE, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_new_target, + rsbac_new_target_id, + A_mode, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "atomic_open() [lookup_open() [do_last() [path_openat() [do_filp_open()]]]]: rsbac_adf_set_attr() returned error"); + } + } +#endif + dput(dentry); return error; } @@ -3103,6 +3403,14 @@ static int lookup_open(struct nameidata *nd, struct path *path, umode_t mode = op->mode; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + enum rsbac_target_t rsbac_new_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (unlikely(IS_DEADDIR(dir_inode))) return -ENOENT; @@ -3197,10 +3505,71 @@ static int lookup_open(struct nameidata *nd, struct path *path, error = -EACCES; goto out_dput; } + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "lookup_open [do_last() [path_openat() [do_filp_open() [sys_open()]]]]: calling ADF\n"); + rsbac_target = T_DIR; + rsbac_target_id.dir.device = dir_inode->i_sb->s_dev; + rsbac_target_id.dir.inode = dir_inode->i_ino; + rsbac_target_id.dir.dentry_p = dentry->d_parent; + if (S_ISDIR(mode)) + rsbac_attribute_value.create_data.target = T_DIR; + else if (S_ISSOCK(mode)) + rsbac_attribute_value.create_data.target = T_UNIXSOCK; + else if (S_ISFIFO(mode)) + rsbac_attribute_value.create_data.target = T_FIFO; + else + rsbac_attribute_value.create_data.target = T_FILE; + rsbac_attribute_value.create_data.dentry_p = dentry; + rsbac_attribute_value.create_data.mode = mode; + rsbac_attribute_value.create_data.device = 0; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_create_data, + rsbac_attribute_value)) { + error = -EPERM; + goto out_dput; + } +#endif + error = dir_inode->i_op->create(dir_inode, dentry, mode, open_flag & O_EXCL); if (error) goto out_dput; + + /* RSBAC: notify ADF of new fs object */ +#ifdef CONFIG_RSBAC + if (dentry->d_inode) { + if (S_ISDIR(dentry->d_inode->i_mode)) + rsbac_new_target = T_DIR; + else if (S_ISSOCK(dentry->d_inode->i_mode)) + rsbac_new_target = T_UNIXSOCK; + else if (S_ISFIFO(dentry->d_inode->i_mode)) { + if (dentry->d_inode->i_sb->s_magic != PIPEFS_MAGIC) + rsbac_new_target = T_FIFO; + else + rsbac_new_target = T_NONE; + } else + rsbac_new_target = T_FILE; + rsbac_new_target_id.file.device = dentry->d_inode->i_sb->s_dev; + rsbac_new_target_id.file.inode = dentry->d_inode->i_ino; + rsbac_new_target_id.file.dentry_p = dentry; + if (unlikely(rsbac_adf_set_attr(R_CREATE, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_new_target, + rsbac_new_target_id, + A_create_data, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "lookup_open [do_last() [path_openat() [do_filp_open() [sys_open()]]]]: rsbac_adf_set_attr() returned error"); + } + } +#endif + fsnotify_create(dir_inode, dentry); } if (unlikely(create_error) && !dentry->d_inode) { @@ -3234,6 +3603,14 @@ static int do_last(struct nameidata *nd, struct path path; int error; +#ifdef CONFIG_RSBAC + enum rsbac_adf_request_t rsbac_adf_req = R_NONE; + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + nd->flags &= ~LOOKUP_PARENT; nd->flags |= op->intent; @@ -3375,6 +3752,68 @@ static int do_last(struct nameidata *nd, error = may_open(&nd->path, acc_mode, open_flag); if (error) goto out; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "do_last() [sys_open()]: calling ADF\n"); + /* get target type and id clear */ + if (S_ISBLK(nd->path.dentry->d_inode->i_mode) || S_ISCHR(nd->path.dentry->d_inode->i_mode)){ + rsbac_target = T_DEV; + if (S_ISBLK(nd->path.dentry->d_inode->i_mode)) { + rsbac_target_id.dev.type = D_block; + } + else { + rsbac_target_id.dev.type = D_char; + } + rsbac_target_id.dev.major = RSBAC_MAJOR(nd->path.dentry->d_inode->i_rdev); + rsbac_target_id.dev.minor = RSBAC_MINOR(nd->path.dentry->d_inode->i_rdev); + } + else { /* must be file, dir or fifo */ + if (S_ISDIR(nd->path.dentry->d_inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISSOCK(nd->path.dentry->d_inode->i_mode)) + rsbac_target = T_UNIXSOCK; + else if (S_ISFIFO(nd->path.dentry->d_inode->i_mode)) { + if (nd->path.dentry->d_inode->i_sb->s_magic != PIPEFS_MAGIC) + rsbac_target = T_FIFO; + else + rsbac_target = T_NONE; + } + else + rsbac_target = T_FILE; + + rsbac_target_id.file.device = nd->path.dentry->d_inode->i_sb->s_dev; + rsbac_target_id.file.inode = nd->path.dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = nd->path.dentry; + } + /* determine request type */ + rsbac_adf_req = R_NONE; + if (open_flag & O_APPEND) + rsbac_adf_req = R_APPEND_OPEN; + else + if ((open_flag & O_RDWR) || ((open_flag & O_WRONLY) && (open_flag & O_RDONLY))) + rsbac_adf_req = R_READ_WRITE_OPEN; + else + if (open_flag & O_WRONLY) + rsbac_adf_req = R_WRITE_OPEN; + else + if (rsbac_target == T_DIR) + rsbac_adf_req = R_READ; + else + rsbac_adf_req = R_READ_OPEN; + if ((rsbac_adf_req != R_NONE) && (rsbac_target != T_NONE)) { + rsbac_attribute_value.open_flag = open_flag; + if (!rsbac_adf_request(rsbac_adf_req, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_open_flag, + rsbac_attribute_value)) { + error = -EPERM; + goto out; + } + } +#endif + BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ error = vfs_open(&nd->path, file, current_cred()); if (error) @@ -3395,6 +3834,24 @@ static int do_last(struct nameidata *nd, } if (got_write) mnt_drop_write(nd->path.mnt); + +#ifdef CONFIG_RSBAC + if (!error && (rsbac_adf_req != R_NONE) && (rsbac_target != T_NONE)) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(rsbac_adf_req, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_open_flag, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "do_last() [sys_open()]: rsbac_adf_set_attr() returned error\n"); + } + } +#endif + return error; } @@ -3493,6 +3950,11 @@ static struct file *path_openat(struct nameidata *nd, int opened = 0; int error; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + file = get_empty_filp(); if (IS_ERR(file)) return file; @@ -3519,6 +3981,25 @@ static struct file *path_openat(struct nameidata *nd, while (!(error = link_path_walk(s, nd)) && (error = do_last(nd, file, op, &opened)) > 0) { nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); + +#ifdef CONFIG_RSBAC + if (nd->path.dentry->d_sb) { + rsbac_target_id.symlink.device = nd->path.dentry->d_sb->s_dev; + rsbac_target_id.symlink.inode = nd->path.dentry->d_inode->i_ino; + rsbac_target_id.symlink.dentry_p = nd->path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + T_SYMLINK, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + break; + } + } +#endif + s = trailing_symlink(nd); if (IS_ERR(s)) { error = PTR_ERR(s); @@ -3688,6 +4169,13 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { int error = may_create(dir, dentry); +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + enum rsbac_target_t rsbac_new_target; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (error) return error; @@ -3705,9 +4193,57 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) if (error) return error; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "vfs_mknod()[sys_mknod()]: calling ADF\n"); + rsbac_target_id.dir.device = dir->i_sb->s_dev; + rsbac_target_id.dir.inode = dir->i_ino; + rsbac_target_id.dir.dentry_p = dentry->d_parent; + rsbac_attribute_value.create_data.target = T_FILE; + rsbac_attribute_value.create_data.dentry_p = dentry; + rsbac_attribute_value.create_data.mode = mode; + rsbac_attribute_value.create_data.device = dev; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_DIR, + rsbac_target_id, + A_create_data, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + error = dir->i_op->mknod(dir, dentry, mode, dev); - if (!error) + if (!error) { +#ifdef CONFIG_RSBAC + if (dentry->d_inode) { + if (S_ISFIFO(dentry->d_inode->i_mode)) + rsbac_new_target = T_FIFO; + else + if (S_ISLNK(dentry->d_inode->i_mode)) + rsbac_new_target = T_SYMLINK; + else + if (S_ISSOCK(dentry->d_inode->i_mode)) + rsbac_new_target = T_UNIXSOCK; + else + rsbac_new_target = T_FILE; + rsbac_new_target_id.dir.device = dentry->d_sb->s_dev; + rsbac_new_target_id.dir.inode = dentry->d_inode->i_ino; + rsbac_new_target_id.dir.dentry_p = dentry; + if (unlikely(rsbac_adf_set_attr(R_CREATE, + task_pid(current), + T_DIR, + rsbac_target_id, + rsbac_new_target, + rsbac_new_target_id, + A_create_data, + rsbac_attribute_value))) { + rsbac_pr_debug(aef, "vfs_mknod[sys_mknod(), sys_mknod()]: rsbac_adf_set_attr() returned error"); + } + } +#endif + fsnotify_create(dir, dentry); + } return error; } EXPORT_SYMBOL(vfs_mknod); @@ -3783,6 +4319,13 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) int error = may_create(dir, dentry); unsigned max_links = dir->i_sb->s_max_links; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_new_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (error) return error; @@ -3797,9 +4340,52 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) if (max_links && dir->i_nlink >= max_links) return -EMLINK; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "vfs_mkdir(): calling ADF\n"); + rsbac_target_id.dir.device = dir->i_sb->s_dev; + rsbac_target_id.dir.inode = dir->i_ino; + rsbac_target_id.dir.dentry_p = dentry->d_parent; + rsbac_attribute_value.create_data.target = T_DIR; + rsbac_attribute_value.create_data.dentry_p = dentry; + rsbac_attribute_value.create_data.mode = mode; + rsbac_attribute_value.create_data.device = 0; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_DIR, + rsbac_target_id, + A_create_data, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + error = dir->i_op->mkdir(dir, dentry, mode); - if (!error) + if (!error) { +#ifdef CONFIG_RSBAC + if (dentry->d_inode) { + rsbac_new_target = T_DIR; + if (dentry->d_sb) + rsbac_new_target_id.dir.device = dentry->d_sb->s_dev; + else + rsbac_new_target_id.dir.device = rsbac_target_id.dir.device; + rsbac_new_target_id.dir.inode = dentry->d_inode->i_ino; + rsbac_new_target_id.dir.dentry_p = dentry; + if (unlikely(rsbac_adf_set_attr(R_CREATE, + task_pid(current), + T_DIR, + rsbac_target_id, + rsbac_new_target, + rsbac_new_target_id, + A_create_data, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "vfs_mkdir() [sys_mkdir()]: rsbac_adf_set_attr() returned error"); + } + } +#endif + fsnotify_mkdir(dir, dentry); + } return error; } EXPORT_SYMBOL(vfs_mkdir); @@ -3838,6 +4424,12 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) { int error = may_delete(dir, dentry, 1); +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (error) return error; @@ -3845,6 +4437,24 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) return -EPERM; dget(dentry); + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "vfs_rmdir()[do_rmdir() [sys_rmdir()]]: calling ADF\n"); + rsbac_target_id.dir.device = dentry->d_sb->s_dev; + rsbac_target_id.dir.inode = dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_DELETE, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + dput(dentry); + return -EPERM; + } +#endif + inode_lock(dentry->d_inode); error = -EBUSY; @@ -3866,6 +4476,24 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) out: inode_unlock(dentry->d_inode); + +#ifdef CONFIG_RSBAC + if (!error) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_DELETE, + task_pid(current), + T_DIR, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "vfs_rmdir() [do_rmdir() [sys_rmdir()]]: rsbac_adf_set_attr() returned error"); + } + } +#endif + dput(dentry); if (!error) d_delete(dentry); @@ -3960,6 +4588,13 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate struct inode *target = dentry->d_inode; int error = may_delete(dir, dentry, 0); +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (error) return error; @@ -3972,6 +4607,37 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate else { error = security_inode_unlink(dir, dentry); if (!error) { + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "vfs_unlink()[do_unlink() [sys_unlink()]]: calling ADF\n"); + if (S_ISDIR(dentry->d_inode->i_mode)) + rsbac_target = T_DIR; + else + if (S_ISFIFO(dentry->d_inode->i_mode)) + rsbac_target = T_FIFO; + else + if (S_ISLNK(dentry->d_inode->i_mode)) + rsbac_target = T_SYMLINK; + else + if (S_ISSOCK(dentry->d_inode->i_mode)) + rsbac_target = T_UNIXSOCK; + else + rsbac_target = T_FILE; + rsbac_target_id.file.device = dentry->d_sb->s_dev; + rsbac_target_id.file.inode = dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = dentry; + rsbac_attribute_value.nlink = dentry->d_inode->i_nlink; + if (!rsbac_adf_request(R_DELETE, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_nlink, + rsbac_attribute_value)) { + error = -EPERM; + goto out; + } +#endif + error = try_break_deleg(target, delegated_inode); if (error) goto out; @@ -3985,6 +4651,23 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate out: inode_unlock(target); +#ifdef CONFIG_RSBAC + if (!error) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_DELETE, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_nlink, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "vfs_unlink() [do_unlink() [sys_unlink()]]: rsbac_adf_set_attr() returned error\n"); + } + } +#endif + /* We don't d_delete() NFS sillyrenamed files--they still exist. */ if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) { fsnotify_link_count(target); @@ -4094,6 +4777,12 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) { int error = may_create(dir, dentry); +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (error) return error; @@ -4104,9 +4793,46 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) if (error) return error; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "vfs_symlink()[do_symlink(), sys_symlink()]: calling ADF\n"); + rsbac_target_id.dir.device = dentry->d_sb->s_dev; + rsbac_target_id.dir.inode = dir->i_ino; + rsbac_target_id.dir.dentry_p = dentry->d_parent; + rsbac_attribute_value.create_data.target = T_SYMLINK; + rsbac_attribute_value.create_data.dentry_p = dentry; + rsbac_attribute_value.create_data.mode = 0; + rsbac_attribute_value.create_data.device = 0; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_DIR, + rsbac_target_id, + A_create_data, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + error = dir->i_op->symlink(dir, dentry, oldname); - if (!error) + if (!error) { +#ifdef CONFIG_RSBAC + rsbac_new_target_id.symlink.device = dentry->d_sb->s_dev; + rsbac_new_target_id.symlink.inode = dentry->d_inode->i_ino; + rsbac_new_target_id.symlink.dentry_p = dentry; + if (unlikely(rsbac_adf_set_attr(R_CREATE, + task_pid(current), + T_DIR, + rsbac_target_id, + T_SYMLINK, + rsbac_new_target_id, + A_create_data, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "vfs_symlink() [do_symlink(), sys_symlink()]: rsbac_adf_set_attr() returned error"); + } +#endif + fsnotify_create(dir, dentry); + } return error; } EXPORT_SYMBOL(vfs_symlink); @@ -4172,6 +4898,12 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de unsigned max_links = dir->i_sb->s_max_links; int error; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!inode) return -ENOENT; @@ -4203,6 +4935,31 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de if (error) return error; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "vfs_link() [do_link() [sys_link()]]: calling ADF\n"); + rsbac_target = T_FILE; + if (S_ISDIR (old_dentry->d_inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO (old_dentry->d_inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK (old_dentry->d_inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK (old_dentry->d_inode->i_mode)) + rsbac_target = T_UNIXSOCK; + rsbac_target_id.dir.device = old_dentry->d_sb->s_dev; + rsbac_target_id.dir.inode = old_dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = old_dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_LINK_HARD, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + inode_lock(inode); /* Make sure we don't allow creating hardlink to an unlinked file */ if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE)) @@ -4368,6 +5125,17 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, unsigned max_links = new_dir->i_sb->s_max_links; struct name_snapshot old_name; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + enum rsbac_target_t rsbac_target2 = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_target_id2; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + union rsbac_attribute_value_t rsbac_attribute_value2; + rsbac_boolean_t target_exists = FALSE; +#endif + if (source == target) return 0; @@ -4415,6 +5183,91 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, take_dentry_name_snapshot(&old_name, old_dentry); dget(new_dentry); + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "vfs_rename(): calling ADF\n"); + rsbac_target = T_FILE; + if (S_ISDIR(old_dentry->d_inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO (old_dentry->d_inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK (old_dentry->d_inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK (old_dentry->d_inode->i_mode)) + rsbac_target = T_UNIXSOCK; + rsbac_target_id.file.device = old_dentry->d_sb->s_dev; + rsbac_target_id.file.inode = old_dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = old_dentry; + rsbac_attribute_value.new_dir_dentry_p = new_dentry->d_parent; + if (!rsbac_adf_request(R_RENAME, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_new_dir_dentry_p, + rsbac_attribute_value)) { + dput(new_dentry); + release_dentry_name_snapshot(&old_name); + return -EPERM; + } + if (new_dir != old_dir) { +#ifdef CONFIG_RSBAC_MOVETO + rsbac_pr_debug(aef, "vfs_rename(): calling ADF for MOVETO on new_dir\n"); +#else + rsbac_pr_debug(aef, "vfs_rename(): calling ADF for WRITE on new_dir\n"); +#endif + rsbac_target_id2.dir.device = new_dentry->d_sb->s_dev; + rsbac_target_id2.dir.inode = new_dir->i_ino; + rsbac_target_id2.dir.dentry_p = new_dentry->d_parent; + rsbac_attribute_value2.dummy = 0; +#ifdef CONFIG_RSBAC_MOVETO + if (!rsbac_adf_request(R_MOVETO, +#else + if (!rsbac_adf_request(R_WRITE, +#endif + task_pid(current), + T_DIR, + rsbac_target_id2, + A_none, + rsbac_attribute_value2)) { + dput(new_dentry); + release_dentry_name_snapshot(&old_name); +#ifdef CONFIG_RSBAC_MOVETO_EXDEV + return -EXDEV; +#else + return -EPERM; +#endif + } + } + if(new_dentry->d_inode) + { + target_exists = TRUE; + rsbac_pr_debug(aef, "vfs_rename(): calling ADF for DELETE on existing target\n"); + rsbac_target2 = T_FILE; + if (S_ISDIR(new_dentry->d_inode->i_mode)) + rsbac_target2 = T_DIR; + else if (S_ISFIFO (new_dentry->d_inode->i_mode)) + rsbac_target2 = T_FIFO; + else if (S_ISLNK (new_dentry->d_inode->i_mode)) + rsbac_target2 = T_SYMLINK; + else if (S_ISSOCK (new_dentry->d_inode->i_mode)) + rsbac_target2 = T_UNIXSOCK; + rsbac_target_id2.file.device = new_dentry->d_sb->s_dev; + rsbac_target_id2.file.inode = new_dentry->d_inode->i_ino; + rsbac_target_id2.file.dentry_p = new_dentry; + rsbac_attribute_value2.nlink = new_dentry->d_inode->i_nlink; + if (!rsbac_adf_request(R_DELETE, + task_pid(current), + rsbac_target2, + rsbac_target_id2, + A_nlink, + rsbac_attribute_value2)) { + dput(new_dentry); + release_dentry_name_snapshot(&old_name); + return -EPERM; + } + } +#endif + if (!is_dir || (flags & RENAME_EXCHANGE)) lock_two_nondirectories(source, target); else if (target) @@ -4466,6 +5319,41 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, unlock_two_nondirectories(source, target); else if (target) inode_unlock(target); + +#ifdef CONFIG_RSBAC + if (!error && target_exists) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_DELETE, + task_pid(current), + rsbac_target2, + rsbac_target_id2, + T_NONE, + rsbac_new_target_id, + A_nlink, + rsbac_attribute_value2))) { + rsbac_printk(KERN_WARNING + "vfs_rename() [sys_rename()]: rsbac_adf_set_attr() for DELETE returned error\n"); + } + } +#endif +#ifdef CONFIG_RSBAC + if (!error) { + rsbac_new_target_id.dummy = 0; + rsbac_attribute_value.old_dir_inode_p = old_dir; + if (unlikely(rsbac_adf_set_attr(R_RENAME, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_old_dir_inode_p, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "vfs_rename() [sys_rename()]: rsbac_adf_set_attr() for RENAME returned error\n"); + } + } +#endif + dput(new_dentry); if (!error) { fsnotify_move(old_dir, new_dir, old_name.name, is_dir, @@ -4664,6 +5552,35 @@ int readlink_copy(char __user *buffer, int buflen, const char *link) return len; } +#ifdef CONFIG_RSBAC_SYM_REDIR +int rsbac_readlink_copy(char __user *buffer, int buflen, const char *link, struct inode *inode) +{ + int len = PTR_ERR(link); + char * rsbac_name; + + if (IS_ERR(link)) + goto out; + + len = strlen(link); + if (len > (unsigned) buflen) + len = buflen; + + rsbac_name = rsbac_symlink_redirect(inode, link, buflen, TRUE); + if (rsbac_name) { + len = strlen(rsbac_name); + if (copy_to_user(buffer, rsbac_name, len)) + len = -EFAULT; + kfree(rsbac_name); + } + else + if (copy_to_user(buffer, link, len)) + len = -EFAULT; +out: + return len; +} +EXPORT_SYMBOL(rsbac_readlink_copy); +#endif + /* * A helper for ->readlink(). This should be used *ONLY* for symlinks that * have ->get_link() not calling nd_jump_link(). Using (or not using) it @@ -4682,7 +5599,11 @@ static int generic_readlink(struct dentry *dentry, char __user *buffer, if (IS_ERR(link)) return PTR_ERR(link); } +#ifdef CONFIG_RSBAC_SYM_REDIR + res = rsbac_readlink_copy(buffer, buflen, link, inode); +#else res = readlink_copy(buffer, buflen, link); +#endif do_delayed_call(&done); return res; } @@ -4781,9 +5702,15 @@ EXPORT_SYMBOL(page_put_link); int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) { DEFINE_DELAYED_CALL(done); +#ifdef CONFIG_RSBAC_SYM_REDIR + int res = rsbac_readlink_copy(buffer, buflen, + page_get_link(dentry, d_inode(dentry), &done), + d_inode(dentry)); +#else int res = readlink_copy(buffer, buflen, page_get_link(dentry, d_inode(dentry), &done)); +#endif do_delayed_call(&done); return res; } diff --git a/fs/namespace.c b/fs/namespace.c index f8893dc6a989..9baa944c2a15 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -26,6 +26,9 @@ #include #include #include +#ifdef CONFIG_RSBAC +#include +#endif #include "pnode.h" #include "internal.h" @@ -273,6 +276,13 @@ static struct mount *alloc_vfsmnt(const char *name) */ int __mnt_is_readonly(struct vfsmount *mnt) { +#ifdef CONFIG_RSBAC + /* HACK - Remove me when switching to full 2.6, pass over the vfsmount + * in init_private_file() instead + */ + if(!mnt) + return 0; +#endif if (mnt->mnt_flags & MNT_READONLY) return 1; if (mnt->mnt_sb->s_flags & MS_RDONLY) @@ -345,6 +355,14 @@ int __mnt_want_write(struct vfsmount *m) struct mount *mnt = real_mount(m); int ret = 0; +#ifdef CONFIG_RSBAC + /* HACK - Remove me when switching to full 2.6, pass over the vfsmount + * in init_private_file() instead + */ + if(!mnt) + return 0; +#endif + preempt_disable(); mnt_inc_writers(mnt); /* @@ -459,6 +477,13 @@ EXPORT_SYMBOL_GPL(mnt_want_write_file); */ void __mnt_drop_write(struct vfsmount *mnt) { +#ifdef CONFIG_RSBAC + /* HACK - Remove me when switching to full 2.6, pass over the vfsmount + * in init_private_file() instead + */ + if(!mnt) + return; +#endif preempt_disable(); mnt_dec_writers(real_mount(mnt)); preempt_enable(); @@ -988,6 +1013,11 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void lock_mount_hash(); list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts); unlock_mount_hash(); + +#ifdef CONFIG_RSBAC + rsbac_mount(&mnt->mnt); +#endif + return &mnt->mnt; } EXPORT_SYMBOL_GPL(vfs_kern_mount); @@ -1473,6 +1503,11 @@ static int do_umount(struct mount *mnt, int flags) struct super_block *sb = mnt->mnt.mnt_sb; int retval; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + retval = security_sb_umount(&mnt->mnt, flags); if (retval) return retval; @@ -1503,6 +1538,44 @@ static int do_umount(struct mount *mnt, int flags) return -EAGAIN; } +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF for DIR\n"); + rsbac_target_id.dir.device = sb->s_root->d_sb->s_dev; + rsbac_target_id.dir.inode = sb->s_root->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = sb->s_root; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_UMOUNT, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } + rsbac_pr_debug(aef, "calling ADF for dev\n"); + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(sb->s_dev); + rsbac_target_id.dev.minor = RSBAC_MINOR(sb->s_dev); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_UMOUNT, + task_pid(current), + T_DEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + + /* RSBAC: removing data structures for this fs from memory (not /) */ +#ifdef CONFIG_RSBAC + if ((&mnt->mnt != current->fs->root.mnt) || (flags & MNT_DETACH)) { + rsbac_pr_debug(ds, "[sys_umount()]: calling rsbac_umount for Device %02u:%02u\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev)); + rsbac_umount(&mnt->mnt); + } +#endif + /* * If we may have to abort operations to get out of this * mount, and they will themselves hold resources we must @@ -1558,6 +1631,17 @@ static int do_umount(struct mount *mnt, int flags) } } unlock_mount_hash(); + +#ifdef CONFIG_RSBAC + /* RSBAC: umount failed, so reread data structures for this fs from disk */ + if(retval) { + rsbac_printk(KERN_WARNING + "do_umount() [sys_umount()]: umount failed -> calling rsbac_mount for Device %02u:%02u\n", + MAJOR(mnt->mnt.mnt_sb->s_dev),MINOR(mnt->mnt.mnt_sb->s_dev)); + rsbac_mount(&mnt->mnt); + } +#endif + namespace_unlock(); return retval; } @@ -2144,6 +2228,13 @@ static int do_loopback(struct path *path, const char *old_name, struct mount *mnt = NULL, *old, *parent; struct mountpoint *mp; int err; + +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!old_name || !*old_name) return -EINVAL; err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path); @@ -2162,6 +2253,57 @@ static int do_loopback(struct path *path, const char *old_name, old = real_mount(old_path.mnt); parent = real_mount(path->mnt); +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[do_loopback() [sys_mount()]]: calling ADF for DIR\n"); + rsbac_target_id.dir.device = old_path.dentry->d_sb->s_dev; + rsbac_target_id.dir.inode = old_path.dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = old_path.dentry; + rsbac_attribute_value.mode = recurse; + if (!rsbac_adf_request(R_MOUNT, + task_pid(current), + T_DIR, + rsbac_target_id, + A_mode, + rsbac_attribute_value)) + { + err = -EPERM; + goto out2; + } + rsbac_pr_debug(aef, "[do_mount() [sys_mount()]]: calling ADF for DEV\n"); + if(S_ISBLK(old_path.dentry->d_inode->i_mode)) + { + rsbac_target = T_DEV; + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(old_path.dentry->d_sb->s_dev); + rsbac_target_id.dev.minor = RSBAC_MINOR(old_path.dentry->d_sb->s_dev); + } + else + if(S_ISDIR(old_path.dentry->d_inode->i_mode)) + { + rsbac_target = T_DIR; + rsbac_target_id.dir.device = old_path.dentry->d_sb->s_dev; + rsbac_target_id.dir.inode = old_path.dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = old_path.dentry; + } + else + { + rsbac_target = T_FILE; + rsbac_target_id.file.device = old_path.dentry->d_sb->s_dev; + rsbac_target_id.file.inode = old_path.dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = old_path.dentry; + } + if (!rsbac_adf_request(R_MOUNT, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_mode, + rsbac_attribute_value)) + { + err = -EPERM; + goto out2; + } +#endif + err = -EINVAL; if (IS_MNT_UNBINDABLE(old)) goto out2; @@ -2197,6 +2339,12 @@ static int do_loopback(struct path *path, const char *old_name, unlock_mount(mp); out: path_put(&old_path); + +#ifdef CONFIG_RSBAC + if (!err) + rsbac_mount(&mnt->mnt); +#endif + return err; } @@ -2229,6 +2377,11 @@ static int do_remount(struct path *path, int flags, int mnt_flags, struct super_block *sb = path->mnt->mnt_sb; struct mount *mnt = real_mount(path->mnt); +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!check_mnt(mnt)) return -EINVAL; @@ -2266,6 +2419,34 @@ static int do_remount(struct path *path, int flags, int mnt_flags, if (err) return err; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[do_mount() [sys_mount()]]: calling ADF for DIR\n"); + rsbac_target_id.dir.device = path->dentry->d_sb->s_dev; + rsbac_target_id.dir.inode = path->dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = path->dentry; + rsbac_attribute_value.mode = flags; + if (!rsbac_adf_request(R_MOUNT, + task_pid(current), + T_DIR, + rsbac_target_id, + A_mode, + rsbac_attribute_value)) { + return -EPERM; + } + rsbac_pr_debug(aef, "[do_mount() [sys_mount()]]: calling ADF for DEV\n"); + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(sb->s_dev); + rsbac_target_id.dev.minor = RSBAC_MINOR(sb->s_dev); + if (!rsbac_adf_request(R_MOUNT, + task_pid(current), + T_DEV, + rsbac_target_id, + A_mode, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + down_write(&sb->s_umount); if (flags & MS_BIND) err = change_mount_flags(path->mnt, flags); @@ -2301,6 +2482,12 @@ static int do_move_mount(struct path *path, const char *old_name) struct mount *old; struct mountpoint *mp; int err; + +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!old_name || !*old_name) return -EINVAL; err = kern_path(old_name, LOOKUP_FOLLOW, &old_path); @@ -2315,6 +2502,61 @@ static int do_move_mount(struct path *path, const char *old_name) old = real_mount(old_path.mnt); p = real_mount(path->mnt); +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[do_mount() [sys_mount()]]: calling ADF for UMOUNT on old DIR\n"); + rsbac_target_id.dir.device = old_path.dentry->d_sb->s_dev; + rsbac_target_id.dir.inode = old_path.dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = old_path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_UMOUNT, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto out1; + } + rsbac_pr_debug(aef, "[do_mount() [sys_mount()]]: calling ADF for MOUNT on new DIR\n"); + rsbac_target_id.dir.device = path->dentry->d_sb->s_dev; + rsbac_target_id.dir.inode = path->dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = path->dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MOUNT, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto out1; + } + rsbac_pr_debug(aef, "[do_mount() [sys_mount()]]: calling ADF for UMOUNT on DEV\n"); + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(old_path.dentry->d_sb->s_dev); + rsbac_target_id.dev.minor = RSBAC_MINOR(old_path.dentry->d_sb->s_dev); + if (!rsbac_adf_request(R_UMOUNT, + task_pid(current), + T_DEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto out1; + } + rsbac_pr_debug(aef, "[do_mount() [sys_mount()]]: calling ADF for MOUNT on DEV\n"); + if (!rsbac_adf_request(R_MOUNT, + task_pid(current), + T_DEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto out1; + } +#endif + + err = -EINVAL; if (!check_mnt(p) || !check_mnt(old)) goto out1; @@ -2348,9 +2590,24 @@ static int do_move_mount(struct path *path, const char *old_name) if (p == old) goto out1; +#ifdef CONFIG_RSBAC + rsbac_umount(old_path.mnt); +#endif + err = attach_recursive_mnt(old, real_mount(path->mnt), mp, &parent_path); - if (err) + if (err) { +#ifdef CONFIG_RSBAC + rsbac_printk(KERN_WARNING + "do_move_mount() [sys_mount()]: attach_recursive_mnt() failed -> calling rsbac_mount() for old Device %02u:%02u\n", + MAJOR(old_path.mnt->mnt_sb->s_dev),MINOR(old_path.mnt->mnt_sb->s_dev)); + rsbac_mount(old_path.mnt); +#endif goto out1; + } + +#ifdef CONFIG_RSBAC + rsbac_mount(old_path.mnt); +#endif /* if the mount is moved, it should no longer be expire * automatically */ @@ -2396,6 +2653,11 @@ static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags) struct mount *parent; int err; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + mnt_flags &= ~MNT_INTERNAL_FLAGS; mp = lock_mount(path); @@ -2423,6 +2685,37 @@ static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags) if (d_is_symlink(newmnt->mnt.mnt_root)) goto unlock; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[do_add_mount() [sys_mount()]]: calling ADF for DIR\n"); + rsbac_target_id.dir.device = path->dentry->d_sb->s_dev; + rsbac_target_id.dir.inode = path->dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = path->dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MOUNT, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto unlock; + } + rsbac_pr_debug(aef, "[do_mount() [sys_mount()]]: calling ADF for DEV\n"); + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(newmnt->mnt.mnt_sb->s_dev); + rsbac_target_id.dev.minor = RSBAC_MINOR(newmnt->mnt.mnt_sb->s_dev); + rsbac_attribute_value.mode = mnt_flags; + if (!rsbac_adf_request(R_MOUNT, + task_pid(current), + T_DEV, + rsbac_target_id, + A_mode, + rsbac_attribute_value)) { + err = -EPERM; + goto unlock; + } +#endif + newmnt->mnt.mnt_flags = mnt_flags; err = graft_tree(newmnt, parent, mp); @@ -3058,6 +3351,11 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, struct mountpoint *old_mp, *root_mp; int error; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!may_mount()) return -EPERM; @@ -3079,6 +3377,42 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, if (IS_ERR(old_mp)) goto out3; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF for MOUNT on put_old\n"); + rsbac_target_id.dir.device = old.dentry->d_sb->s_dev; + rsbac_target_id.dir.inode = old.dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = old.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MOUNT, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + error = -EPERM; + goto out4; + } + rsbac_pr_debug(aef, "calling ADF for MOUNT on root DIR\n"); + rsbac_target_id.dir.device = current->fs->root.mnt->mnt_sb->s_dev; + rsbac_target_id.dir.inode = current->fs->root.dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = current->fs->root.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MOUNT, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + error = -EPERM; + goto out4; + } + + /* Make the new root's cached rsbac.dat dentry be put to free the old root's dcache */ + rsbac_free_dat_dentries(); +#endif + error = -EINVAL; new_mnt = real_mount(new.mnt); root_mnt = real_mount(root.mnt); diff --git a/fs/open.c b/fs/open.c index 35bb784763a4..791aa436d4ac 100644 --- a/fs/open.c +++ b/fs/open.c @@ -34,16 +34,51 @@ #include "internal.h" +#ifdef CONFIG_RSBAC +#include +#endif +#include + int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, struct file *filp) { int ret; struct iattr newattrs; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#ifdef CONFIG_RSBAC_SECDEL + loff_t old_len = dentry->d_inode->i_size; +#endif +#endif + /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ if (length < 0) return -EINVAL; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[open_namei(), do_sys_truncate() [sys_truncate()]]: calling ADF\n"); + rsbac_target_id.file.device = dentry->d_inode->i_sb->s_dev; + rsbac_target_id.file.inode = dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_TRUNCATE, + task_pid(current), + T_FILE, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + + /* RSBAC: Overwrite truncated part, if asked by flag */ +#ifdef CONFIG_RSBAC_SECDEL + rsbac_sec_trunc(dentry, length, old_len); +#endif + newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | time_attrs; if (filp) { @@ -62,6 +97,25 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, /* Note any delegations or leases have already been broken: */ ret = notify_change(dentry, &newattrs, NULL); inode_unlock(dentry->d_inode); + +#ifdef CONFIG_RSBAC + if (!ret) { + rsbac_pr_debug(aef, "[open_namei(), do_sys_truncate() [sys_truncate()]]: notifying ADF\n"); + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_TRUNCATE, + task_pid(current), + T_FILE, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "do_truncate() [open_namei(), do_sys_truncate() [sys_truncate()]]: rsbac_adf_set_attr() returned error\n"); + } + } +#endif + return ret; } @@ -240,6 +294,10 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) { struct inode *inode = file_inode(file); long ret; +#ifdef CONFIG_RSBAC_RW + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif if (offset < 0 || len <= 0) return -EINVAL; @@ -291,6 +349,21 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) if (IS_SWAPFILE(inode)) return -ETXTBSY; +#ifdef CONFIG_RSBAC_RW + rsbac_pr_debug(aef, "sys_fallocate(): calling ADF\n"); + rsbac_target_id.file.device = inode->i_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = file->f_path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_WRITE, + task_pid(current), + T_FILE, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + return -EPERM; +#endif + /* * Revalidate the write permissions, in case security policy has * changed since the files were opened. @@ -359,6 +432,12 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) int res; unsigned int lookup_flags = LOOKUP_FOLLOW; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ return -EINVAL; @@ -372,7 +451,11 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) if (!issecure(SECURE_NO_SETUID_FIXUP)) { /* Clear the capabilities if we switch to a non-root user */ kuid_t root_uid = make_kuid(override_cred->user_ns, 0); - if (!uid_eq(override_cred->uid, root_uid)) + if (!uid_eq(override_cred->uid, root_uid) +#ifdef CONFIG_RSBAC_FAKE_ROOT_UID + && !rsbac_uid_faked() +#endif + ) cap_clear(override_cred->cap_effective); else override_cred->cap_effective = @@ -385,6 +468,32 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) if (res) goto out; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target = T_FILE; + if (S_ISDIR(path.dentry->d_inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(path.dentry->d_inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(path.dentry->d_inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(path.dentry->d_inode->i_mode)) + rsbac_target = T_UNIXSOCK; + rsbac_target_id.file.device = path.dentry->d_inode->i_sb->s_dev; + rsbac_target_id.file.inode = path.dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_PERMISSIONS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + res = -EPERM; + goto out_path_release; + } +#endif + inode = d_backing_inode(path.dentry); if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { @@ -436,6 +545,12 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename) struct path path; int error; unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; + +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + retry: error = user_path_at(AT_FDCWD, filename, lookup_flags, &path); if (error) @@ -445,6 +560,23 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename) if (error) goto dput_and_out; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.dir.device = path.dentry->d_inode->i_sb->s_dev; + rsbac_target_id.dir.inode = path.dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_CHDIR, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + goto dput_and_out; + } +#endif + set_fs_pwd(current->fs, &path); dput_and_out: @@ -462,7 +594,14 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) struct fd f = fdget_raw(fd); int error; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + error = -EBADF; + + if (!f.file) goto out; @@ -471,6 +610,29 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) goto out_putf; error = inode_permission(file_inode(f.file), MAY_EXEC | MAY_CHDIR); + +#ifdef CONFIG_RSBAC + if (!error) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.dir.device = f.file->f_path.dentry->d_inode->i_sb->s_dev; + rsbac_target_id.dir.inode = f.file->f_path.dentry->d_inode->i_ino; + /* + rsbac_target_id.dir.device = inode->i_sb->s_dev; + rsbac_target_id.dir.inode = inode->i_ino; + */ + rsbac_target_id.dir.dentry_p = f.file->f_path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_CHDIR, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + } + } +#endif + if (!error) set_fs_pwd(current->fs, &f.file->f_path); out_putf: @@ -484,6 +646,12 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) struct path path; int error; unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; + +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + retry: error = user_path_at(AT_FDCWD, filename, lookup_flags, &path); if (error) @@ -500,6 +668,23 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) if (error) goto dput_and_out; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.dir.device = path.dentry->d_inode->i_sb->s_dev; + rsbac_target_id.dir.inode = path.dentry->d_inode->i_ino; + rsbac_target_id.dir.dentry_p = path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_CHDIR, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + goto dput_and_out; + } +#endif + set_fs_root(current->fs, &path); error = 0; dput_and_out: @@ -519,6 +704,12 @@ static int chmod_common(const struct path *path, umode_t mode) struct iattr newattrs; int error; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + error = mnt_want_write(path->mnt); if (error) return error; @@ -527,6 +718,42 @@ static int chmod_common(const struct path *path, umode_t mode) error = security_path_chmod(path, mode); if (error) goto out_unlock; + +#ifdef CONFIG_RSBAC + if ( (mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) ) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target = T_FILE; + rsbac_target_id.file.device = inode->i_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = path->dentry; + if (S_ISDIR(inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(inode->i_mode)) { + if(inode->i_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = inode->i_ino; + } else { + rsbac_target = T_UNIXSOCK; + } + } + rsbac_attribute_value.mode = mode; + if (!rsbac_adf_request(R_MODIFY_PERMISSIONS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_mode, + rsbac_attribute_value)) { + error = -EPERM; + goto out_unlock; + } + } +#endif + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; error = notify_change(path->dentry, &newattrs, &delegated_inode); @@ -586,9 +813,40 @@ static int chown_common(const struct path *path, uid_t user, gid_t group) kuid_t uid; kgid_t gid; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + uid = make_kuid(current_user_ns(), user); gid = make_kgid(current_user_ns(), group); +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_*chown]: calling ADF\n"); + rsbac_target = T_FILE; + if (S_ISDIR(inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(inode->i_mode)) + rsbac_target = T_UNIXSOCK; + rsbac_target_id.file.device = inode->i_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = path->dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_CHANGE_OWNER, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + retry_deleg: newattrs.ia_valid = ATTR_CTIME; if (user != (uid_t) -1) { @@ -1127,11 +1385,92 @@ int filp_close(struct file *filp, fl_owner_t id) { int retval = 0; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + enum rsbac_attribute_t rsbac_attribute = A_none; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!file_count(filp)) { printk(KERN_ERR "VFS: Close: file count is 0\n"); return 0; } +#ifdef CONFIG_RSBAC + if (current->files && filp && filp->f_path.dentry && filp->f_path.dentry->d_inode) { + rsbac_pr_debug(aef, "[sys_close]: calling ADF\n"); + rsbac_target = T_NONE; + if (S_ISBLK(filp->f_path.dentry->d_inode->i_mode) + || S_ISCHR(filp->f_path.dentry->d_inode->i_mode)) { + rsbac_target = T_DEV; + if (S_ISBLK(filp->f_path.dentry->d_inode->i_mode)) { + rsbac_target_id.dev.type = D_block; + } + else { + rsbac_target_id.dev.type = D_char; + } + rsbac_target_id.dev.major = RSBAC_MAJOR(filp->f_path.dentry->d_inode->i_sb->s_dev); + rsbac_target_id.dev.minor = RSBAC_MINOR(filp->f_path.dentry->d_inode->i_sb->s_dev); + rsbac_attribute = A_f_mode; + rsbac_attribute_value.f_mode = filp->f_mode; + } else + if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode)) { + if (SOCKET_I(filp->f_path.dentry->d_inode)->ops + && (SOCKET_I(filp->f_path.dentry->d_inode)->ops->family == AF_UNIX)) { + if (filp->f_path.dentry->d_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = filp->f_path.dentry->d_inode->i_ino; + rsbac_attribute = A_nlink; + rsbac_attribute_value.nlink = filp->f_path.dentry->d_inode->i_nlink; + } else { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = filp->f_path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = filp->f_path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = filp->f_path.dentry; + rsbac_attribute = A_f_mode; + rsbac_attribute_value.f_mode = filp->f_mode; + } + } else { + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p + = SOCKET_I(filp->f_path.dentry->d_inode); + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; + rsbac_attribute = A_f_mode; + rsbac_attribute_value.f_mode = filp->f_mode; + } + } else { /* must be file, fifo or dir */ + if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(filp->f_path.dentry->d_inode->i_mode)) + rsbac_target = T_FIFO; + else + rsbac_target = T_FILE; + rsbac_target_id.file.device = filp->f_path.dentry->d_inode->i_sb->s_dev; + rsbac_target_id.file.inode = filp->f_path.dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = filp->f_path.dentry; + rsbac_attribute = A_f_mode; + rsbac_attribute_value.f_mode = filp->f_mode; + } + if ((rsbac_target != T_NONE) && !rsbac_adf_request(R_CLOSE, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_attribute, + rsbac_attribute_value)) + { +#ifdef CONFIG_RSBAC_ENFORCE_CLOSE + return -EPERM; +#endif + } + } +#endif + if (filp->f_op->flush) retval = filp->f_op->flush(filp, id); @@ -1139,6 +1478,26 @@ int filp_close(struct file *filp, fl_owner_t id) dnotify_flush(filp, id); locks_remove_posix(filp, id); } + +#ifdef CONFIG_RSBAC + if (rsbac_target != T_NONE) { + rsbac_pr_debug(aef, "[sys_close]: notifying ADF\n"); + rsbac_new_target_id.dummy = 0; + rsbac_attribute_value.f_mode = filp->f_mode; + if (unlikely(rsbac_adf_set_attr(R_CLOSE, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + rsbac_attribute, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "filp_close() [sys_close]: rsbac_adf_set_attr() returned error\n"); + } + } +#endif + fput(filp); return retval; } diff --git a/fs/pipe.c b/fs/pipe.c index 97e5be897753..b6c68aacd656 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -28,6 +28,8 @@ #include "internal.h" +#include + /* * The max size that a non-root user is allowed to grow the pipe. Can * be set by root in /proc/sys/fs/pipe-max-size @@ -255,10 +257,32 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to) int do_wakeup; ssize_t ret; +#ifdef CONFIG_RSBAC_RW + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + /* Null read succeeds. */ if (unlikely(total_len == 0)) return 0; +#ifdef CONFIG_RSBAC_RW + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.ipc.type = I_anonpipe; + rsbac_target_id.ipc.id.id_nr = filp->f_inode->i_ino; + rsbac_attribute_value.dummy = 0; + + if (!rsbac_adf_request(R_READ, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + do_wakeup = 0; ret = 0; __pipe_lock(pipe); @@ -343,8 +367,26 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to) wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT | POLLWRNORM); kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); } - if (ret > 0) + if (ret > 0) { file_accessed(filp); + +#ifdef CONFIG_RSBAC_RW + rsbac_new_target_id.dummy = 0; + + if (unlikely(rsbac_adf_set_attr(R_READ, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "pipe_readv(): rsbac_adf_set_attr() returned error\n"); + } +#endif + + } return ret; } @@ -363,10 +405,32 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from) size_t total_len = iov_iter_count(from); ssize_t chars; +#ifdef CONFIG_RSBAC_RW + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + /* Null write succeeds. */ if (unlikely(total_len == 0)) return 0; +#ifdef CONFIG_RSBAC_RW + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.ipc.type = I_anonpipe; + rsbac_target_id.ipc.id.id_nr = filp->f_inode->i_ino; + rsbac_attribute_value.dummy = 0; + + if (!rsbac_adf_request(R_WRITE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + __pipe_lock(pipe); if (!pipe->readers) { @@ -486,6 +550,23 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from) if (err) ret = err; sb_end_write(file_inode(filp)->i_sb); + +#ifdef CONFIG_RSBAC_RW + rsbac_new_target_id.dummy = 0; + + if (unlikely(rsbac_adf_set_attr(R_WRITE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "pipe_writev(): rsbac_adf_set_attr() returned error\n"); + } +#endif + } return ret; } @@ -549,6 +630,10 @@ static void put_pipe_info(struct inode *inode, struct pipe_inode_info *pipe) { int kill = 0; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; +#endif + spin_lock(&inode->i_lock); if (!--pipe->files) { inode->i_pipe = NULL; @@ -556,8 +641,16 @@ static void put_pipe_info(struct inode *inode, struct pipe_inode_info *pipe) } spin_unlock(&inode->i_lock); - if (kill) + if (kill) { +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ACI remove_target()\n"); + rsbac_target_id.ipc.type = I_anonpipe; + rsbac_target_id.ipc.id.id_nr = inode->i_ino; + rsbac_remove_target(T_IPC, rsbac_target_id); +#endif + free_pipe_info(pipe); + } } static int @@ -588,14 +681,87 @@ pipe_fasync(int fd, struct file *filp, int on) struct pipe_inode_info *pipe = filp->private_data; int retval = 0; +#ifdef CONFIG_RSBAC_RW + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + __pipe_lock(pipe); - if (filp->f_mode & FMODE_READ) + if (filp->f_mode & FMODE_READ) { +#ifdef CONFIG_RSBAC_RW + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.ipc.type = I_anonpipe; + rsbac_target_id.ipc.id.id_nr = filp->f_inode->i_ino; + rsbac_attribute_value.dummy = 0; + + if (!rsbac_adf_request(R_READ, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + __pipe_unlock(pipe); + return -EPERM; + } +#endif + retval = fasync_helper(fd, filp, on, &pipe->fasync_readers); + +#ifdef CONFIG_RSBAC_RW + rsbac_new_target_id.dummy = 0; + + if (unlikely((retval >= 0) && rsbac_adf_set_attr(R_READ, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING "pipe_fasync(): rsbac_adf_set_attr() for READ returned error\n"); + } +#endif + + } if ((filp->f_mode & FMODE_WRITE) && retval >= 0) { +#ifdef CONFIG_RSBAC_RW + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.ipc.type = I_anonpipe; + rsbac_target_id.ipc.id.id_nr = filp->f_inode->i_ino; + rsbac_attribute_value.dummy = 0; + + if (!rsbac_adf_request(R_WRITE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + __pipe_unlock(pipe); + return -EPERM; + } +#endif + retval = fasync_helper(fd, filp, on, &pipe->fasync_writers); if (retval < 0 && (filp->f_mode & FMODE_READ)) /* this can happen only if on == T */ fasync_helper(-1, filp, 0, &pipe->fasync_readers); + +#ifdef CONFIG_RSBAC_RW + rsbac_new_target_id.dummy = 0; + + if (unlikely((retval >= 0) && rsbac_adf_set_attr(R_WRITE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING "pipe_fasync(): rsbac_adf_set_attr() for WRITE returned error\n"); + } +#endif + } __pipe_unlock(pipe); return retval; @@ -736,10 +902,31 @@ static struct inode * get_pipe_inode(void) int create_pipe_files(struct file **res, int flags) { int err; - struct inode *inode = get_pipe_inode(); + /* assign get_pipe_inode() after rsbac did his check */ + struct inode *inode; struct file *f; struct path path; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + rsbac_pr_debug(aef, "create_pipe_files() [sys_pipe()]: calling ADF\n"); + rsbac_target_id.ipc.type = I_anonpipe; + rsbac_target_id.ipc.id.id_nr = 0; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + + inode = get_pipe_inode(); if (!inode) return -ENFILE; @@ -766,6 +953,24 @@ int create_pipe_files(struct file **res, int flags) goto err_file; } +#ifdef CONFIG_RSBAC + rsbac_target_id.ipc.type = I_anonpipe; + rsbac_target_id.ipc.id.id_nr = inode->i_ino; + rsbac_new_target_id.dummy = 0; + rsbac_attribute_value.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_CREATE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "do_pipe() [sys_pipe()]: rsbac_adf_set_attr() returned error"); + } +#endif + path_get(&path); res[0]->private_data = inode->i_pipe; res[0]->f_flags = O_RDONLY | (flags & O_NONBLOCK); @@ -885,8 +1090,47 @@ static int fifo_open(struct inode *inode, struct file *filp) bool is_pipe = inode->i_sb->s_magic == PIPEFS_MAGIC; int ret; +#ifdef CONFIG_RSBAC + enum rsbac_adf_request_t rsbac_request = R_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + filp->f_version = 0; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + switch (filp->f_mode & (FMODE_READ | FMODE_WRITE)) { + case FMODE_READ: + rsbac_request = R_READ_OPEN; + break; + + case FMODE_WRITE: + rsbac_request = R_WRITE_OPEN; + break; + + case FMODE_READ | FMODE_WRITE: + rsbac_request = R_READ_WRITE_OPEN; + break; + + default: + return -EINVAL; + } + rsbac_target_id.ipc.type = I_anonpipe; + rsbac_target_id.ipc.id.id_nr = inode->i_ino; + rsbac_attribute_value.dummy = 0; + + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + spin_lock(&inode->i_lock); if (inode->i_pipe) { pipe = inode->i_pipe; @@ -981,6 +1225,21 @@ static int fifo_open(struct inode *inode, struct file *filp) goto err; } +#ifdef CONFIG_RSBAC + rsbac_new_target_id.dummy = 0; + + if (unlikely(!ret && rsbac_adf_set_attr(rsbac_request, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING "pipe_read_open(): rsbac_adf_set_attr() returned error\n"); + } +#endif + /* Ok! */ __pipe_unlock(pipe); return 0; diff --git a/fs/proc/array.c b/fs/proc/array.c index 88c355574aa0..5fbf338bb155 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -92,6 +92,7 @@ #include #include #include "internal.h" +#include static inline void task_name(struct seq_file *m, struct task_struct *p) { @@ -372,7 +373,30 @@ static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) { - struct mm_struct *mm = get_task_mm(task); + struct mm_struct *mm; + +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + + mm = get_task_mm(task); task_name(m, task); task_state(m, ns, pid, task); @@ -411,6 +435,27 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, char tcomm[sizeof(task->comm)]; unsigned long flags; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + state = *get_task_state(task); vsize = eip = esp = 0; permitted = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS | PTRACE_MODE_NOAUDIT); @@ -587,8 +632,30 @@ int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) { unsigned long size = 0, resident = 0, shared = 0, text = 0, data = 0; - struct mm_struct *mm = get_task_mm(task); + struct mm_struct *mm; + +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + + mm = get_task_mm(task); if (mm) { size = task_statm(mm, &shared, &text, &data, &resident); mmput(mm); diff --git a/fs/proc/base.c b/fs/proc/base.c index 719c2e943ea1..8b68bc1c57dc 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -99,6 +99,8 @@ #include "internal.h" #include "fd.h" +#include + /* NOTE: * Implementing inode permission operations in /proc is almost * certainly an error. Permission checks need to happen during @@ -180,6 +182,28 @@ static int proc_cwd_link(struct dentry *dentry, struct path *path) struct task_struct *task = get_proc_task(d_inode(dentry)); int result = -ENOENT; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(!task) + return result; + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + put_task_struct(task); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + if (task) { task_lock(task); if (task->fs) { @@ -197,6 +221,30 @@ static int proc_root_link(struct dentry *dentry, struct path *path) struct task_struct *task = get_proc_task(d_inode(dentry)); int result = -ENOENT; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + if(!task) + return result; + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + put_task_struct(task); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + if (task) { result = get_task_root(task, path); put_task_struct(task); @@ -217,11 +265,34 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, char c; ssize_t rv; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + BUG_ON(*pos < 0); tsk = get_proc_task(file_inode(file)); if (!tsk) return -ESRCH; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(tsk, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + put_task_struct(tsk); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + mm = get_task_mm(tsk); put_task_struct(tsk); if (!mm) @@ -387,6 +458,27 @@ static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns, unsigned long wchan; char symname[KSYM_NAME_LEN]; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + wchan = get_wchan(task); if (wchan && ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS) @@ -428,6 +520,27 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, int err; int i; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); if (!entries) return -ENOMEM; @@ -460,6 +573,27 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, static int proc_pid_schedstat(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) { +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + if (unlikely(!sched_info_on())) seq_printf(m, "0 0 0\n"); else @@ -479,8 +613,31 @@ static int lstats_show_proc(struct seq_file *m, void *v) struct inode *inode = m->private; struct task_struct *task = get_proc_task(inode); +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!task) return -ESRCH; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + put_task_struct(task); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + seq_puts(m, "Latency Top version : v0.1\n"); for (i = 0; i < 32; i++) { struct latency_record *lr = &task->latency_record[i]; @@ -538,6 +695,25 @@ static int proc_oom_score(struct seq_file *m, struct pid_namespace *ns, unsigned long totalpages = totalram_pages + total_swap_pages; unsigned long points = 0; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if(!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + points = oom_badness(task, NULL, NULL, totalpages) * 1000 / totalpages; seq_printf(m, "%lu\n", points); @@ -765,7 +941,34 @@ struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode) struct task_struct *task = get_proc_task(inode); struct mm_struct *mm = ERR_PTR(-ESRCH); +#ifdef CONFIG_RSBAC + enum rsbac_adf_request_t rsbac_adf_req; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (task) { +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + if (mode & PTRACE_MODE_ATTACH) + rsbac_adf_req = R_TRACE; + else + rsbac_adf_req = R_GET_STATUS_DATA; + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(rsbac_adf_req, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + put_task_struct(task); + return ERR_PTR(-EPERM); + } + put_pid(rsbac_target_id.process); +#endif + mm = mm_access(task, mode | PTRACE_MODE_FSCREDS); put_task_struct(task); @@ -810,9 +1013,33 @@ static ssize_t mem_rw(struct file *file, char __user *buf, char *page; unsigned int flags; +#ifdef CONFIG_RSBAC + enum rsbac_adf_request_t rsbac_adf_req = R_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!mm) return 0; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + if (write) + rsbac_adf_req = R_MODIFY_SYSTEM_DATA; + else + rsbac_adf_req = R_GET_STATUS_DATA; + rsbac_target_id.process = proc_pid(file->f_path.dentry->d_inode); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(rsbac_adf_req, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + page = (char *)__get_free_page(GFP_TEMPORARY); if (!page) return -ENOMEM; @@ -914,10 +1141,37 @@ static ssize_t environ_read(struct file *file, char __user *buf, struct mm_struct *mm = file->private_data; unsigned long env_start, env_end; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + struct task_struct *rsbac_task; +#endif + /* Ensure the process spawned far enough to have an environment. */ if (!mm || !mm->env_end) return 0; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_task = get_proc_task(file->f_path.dentry->d_inode); + if (!rsbac_task) + return -ESRCH; + rsbac_target_id.process = get_task_pid(rsbac_task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + put_task_struct(rsbac_task); + return -EPERM; + } + put_pid(rsbac_target_id.process); + put_task_struct(rsbac_task); +#endif + page = (char *)__get_free_page(GFP_TEMPORARY); if (!page) return -ENOMEM; @@ -986,8 +1240,28 @@ static ssize_t auxv_read(struct file *file, char __user *buf, struct mm_struct *mm = file->private_data; unsigned int nwords = 0; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!mm) return 0; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = proc_pid(file->f_path.dentry->d_inode); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + do { nwords += 2; } while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */ @@ -1010,8 +1284,31 @@ static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count, int oom_adj = OOM_ADJUST_MIN; size_t len; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!task) return -ESRCH; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + put_task_struct(task); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX) oom_adj = OOM_ADJUST_MAX; else @@ -1127,6 +1424,27 @@ static ssize_t oom_adj_write(struct file *file, const char __user *buf, int oom_adj; int err; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = proc_pid(file->f_path.dentry->d_inode); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto out; + } + put_pid(rsbac_target_id.process); +#endif + memset(buffer, 0, sizeof(buffer)); if (count > sizeof(buffer) - 1) count = sizeof(buffer) - 1; @@ -1225,8 +1543,31 @@ static ssize_t proc_loginuid_read(struct file * file, char __user * buf, ssize_t length; char tmpbuf[TMPBUFLEN]; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!task) return -ESRCH; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + put_task_struct(task); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + length = scnprintf(tmpbuf, TMPBUFLEN, "%u", from_kuid(file->f_cred->user_ns, audit_get_loginuid(task))); @@ -1242,6 +1583,11 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, kuid_t kloginuid; int rv; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + rcu_read_lock(); if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) { rcu_read_unlock(); @@ -1254,6 +1600,21 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, return -EINVAL; } + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = proc_pid(inode); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + rv = kstrtou32_from_user(buf, count, 10, &loginuid); if (rv < 0) return rv; @@ -1589,9 +1950,32 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path) struct task_struct *task; struct file *exe_file; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + task = get_proc_task(d_inode(dentry)); if (!task) return -ENOENT; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + put_task_struct(task); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + exe_file = get_task_exe_file(task); put_task_struct(task); if (exe_file) { @@ -1776,6 +2160,11 @@ int pid_getattr(const struct path *path, struct kstat *stat, struct task_struct *task; struct pid_namespace *pid = path->dentry->d_sb->s_fs_info; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + generic_fillattr(inode, stat); rcu_read_lock(); @@ -1783,6 +2172,22 @@ int pid_getattr(const struct path *path, struct kstat *stat, stat->gid = GLOBAL_ROOT_GID; task = pid_task(proc_pid(inode), PIDTYPE_PID); if (task) { + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = proc_pid(inode); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + rcu_read_unlock(); + return -EPERM; + } +#endif + if (!has_pid_permissions(pid, task, HIDEPID_INVISIBLE)) { rcu_read_unlock(); /* @@ -1921,6 +2326,11 @@ static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags) struct inode *inode; int status = 0; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (flags & LOOKUP_RCU) return -ECHILD; @@ -1929,6 +2339,23 @@ static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags) if (!task) goto out_notask; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + status = -EPERM; + goto out; + } + put_pid(rsbac_target_id.process); +#endif + mm = mm_access(task, PTRACE_MODE_READ_FSCREDS); if (IS_ERR_OR_NULL(mm)) goto out; @@ -3132,6 +3559,11 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsign unsigned tgid; struct pid_namespace *ns; +#ifdef CONFIG_RSBAC_PROC_HIDE + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + tgid = name_to_int(&dentry->d_name); if (tgid == ~0U) goto out; @@ -3145,6 +3577,23 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsign if (!task) goto out; +#ifdef CONFIG_RSBAC_PROC_HIDE + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + result = -ENOENT; + put_pid(rsbac_target_id.process); + put_task_struct(task); + goto out; + } + put_pid(rsbac_target_id.process); +#endif + result = proc_pid_instantiate(dir, dentry, task, NULL); put_task_struct(task); out: @@ -3203,6 +3652,11 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx) struct pid_namespace *ns = file_inode(file)->i_sb->s_fs_info; loff_t pos = ctx->pos; +#ifdef CONFIG_RSBAC_PROC_HIDE + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (pos >= PID_MAX_LIMIT + TGID_OFFSET) return 0; @@ -3230,6 +3684,21 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx) if (!has_pid_permissions(ns, iter.task, HIDEPID_INVISIBLE)) continue; +#ifdef CONFIG_RSBAC_PROC_HIDE + rsbac_target_id.process = get_task_pid(iter.task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + continue; + } + put_pid(rsbac_target_id.process); +#endif + len = snprintf(name, sizeof(name), "%d", iter.tgid); ctx->pos = iter.tgid + TGID_OFFSET; if (!proc_fill_cache(file, ctx, name, len, @@ -3430,6 +3899,11 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry unsigned tid; struct pid_namespace *ns; +#ifdef CONFIG_RSBAC_PROC_HIDE + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!leader) goto out_no_task; @@ -3448,6 +3922,21 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry if (!same_thread_group(leader, task)) goto out_drop_task; +#ifdef CONFIG_RSBAC_PROC_HIDE + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + goto out_drop_task; + } + put_pid(rsbac_target_id.process); +#endif + result = proc_task_instantiate(dir, dentry, task, NULL); out_drop_task: put_task_struct(task); diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index 45629f4b5402..050e5d9f993e 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -32,6 +32,8 @@ #include #include "internal.h" +#include + #define CORE_STR "CORE" #ifndef ELF_CORE_EFLAGS @@ -441,6 +443,24 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos) int nphdr; unsigned long start; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_target_id.scd = ST_kmem; + rsbac_attribute_value.dummy = 0; + rsbac_pr_debug(aef, "calling ADF\n"); + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + return -EPERM; +#endif + read_lock(&kclist_lock); size = get_kcore_size(&nphdr, &elf_buflen); diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 8f479229b349..7c48db33cbdb 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -12,6 +12,9 @@ #include #include #include + +#include + #include "internal.h" static const struct dentry_operations proc_sys_dentry_operations; @@ -446,11 +449,32 @@ static int sysctl_perm(struct ctl_table_header *head, struct ctl_table *table, i struct ctl_table_root *root = head->root; int mode; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (root->permissions) mode = root->permissions(head, table); else mode = table->mode; +#ifdef CONFIG_RSBAC + if (op & 002) { /* write access */ + rsbac_target_id.scd = ST_sysctl; + rsbac_attribute_value.mode = mode; + rsbac_pr_debug(aef, "[sysctl() etc.]: calling ADF\n"); + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_mode, + rsbac_attribute_value)) { + return -EPERM; + } + } +#endif + return test_perm(mode, op); } diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c index b5713fefb4c1..a198c6e9956c 100644 --- a/fs/proc_namespace.c +++ b/fs/proc_namespace.c @@ -12,6 +12,10 @@ #include #include +#ifdef CONFIG_RSBAC +#include +#endif + #include "proc/internal.h" /* only for get_proc_task() in ->open() */ #include "pnode.h" @@ -245,9 +249,32 @@ static int mounts_open_common(struct inode *inode, struct file *file, struct seq_file *m; int ret = -EINVAL; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!task) goto err; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(task, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + put_pid(rsbac_target_id.process); + put_task_struct(task); + ret = -EPERM; + goto err; + } + put_pid(rsbac_target_id.process); +#endif + task_lock(task); nsp = task->nsproxy; if (!nsp || !nsp->mnt_ns) { diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 07e08c7d05ca..d86538e4c9cf 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -15,12 +15,18 @@ #include #include #include +#include #include #include static int check_quotactl_permission(struct super_block *sb, int type, int cmd, qid_t id) { +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + switch (cmd) { /* these commands do not require any special privilegues */ case Q_GETFMT: @@ -29,17 +35,59 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd, case Q_XGETQSTAT: case Q_XGETQSTATV: case Q_XQUOTASYNC: +#ifdef CONFIG_RSBAC + rsbac_target_id.scd = ST_quota; + rsbac_attribute_value.dummy = 0; + rsbac_pr_debug(aef, "[sys_quotactl()]: calling ADF\n"); + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif break; /* allow to query information for dquots we "own" */ case Q_GETQUOTA: case Q_XGETQUOTA: if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) || - (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id)))) + (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id)))) { +#ifdef CONFIG_RSBAC + rsbac_target_id.scd = ST_quota; + rsbac_attribute_value.dummy = 0; + rsbac_pr_debug(aef, "[sys_quotactl()]: calling ADF\n"); + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif break; + } /*FALLTHROUGH*/ default: if (!capable(CAP_SYS_ADMIN)) return -EPERM; + +#ifdef CONFIG_RSBAC + rsbac_target_id.scd = ST_quota; + rsbac_attribute_value.dummy = 0; + rsbac_pr_debug(aef, "[sys_quotactl()]: calling ADF\n"); + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif } return security_quotactl(cmd, type, id, sb); diff --git a/fs/read_write.c b/fs/read_write.c index 0cc7033aa413..2f778aad0446 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -20,6 +20,13 @@ #include #include #include "internal.h" +#ifdef CONFIG_RSBAC +#ifdef CONFIG_RSBAC_RW +#include +#include +#endif +#include +#endif #include #include @@ -419,6 +426,10 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t ret; +#ifdef CONFIG_RSBAC_RW + struct rsbac_rw_req rsbac_rw_req_obj; +#endif + if (!(file->f_mode & FMODE_READ)) return -EBADF; if (!(file->f_mode & FMODE_CAN_READ)) @@ -428,10 +439,22 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) ret = rw_verify_area(READ, file, pos, count); if (!ret) { + +#ifdef CONFIG_RSBAC_RW + rsbac_rw_req_obj.rsbac_target = T_NONE; + rsbac_rw_req_obj.rsbac_request = R_READ; + if (!rsbac_handle_rw_req(file, &rsbac_rw_req_obj)) + return -EPERM; +#endif + if (count > MAX_RW_COUNT) count = MAX_RW_COUNT; ret = __vfs_read(file, buf, count, pos); if (ret > 0) { +#ifdef CONFIG_RSBAC_RW + rsbac_handle_rw_up(&rsbac_rw_req_obj); +#endif + fsnotify_access(file); add_rchar(current, ret); } @@ -503,6 +526,10 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ { ssize_t ret; +#ifdef CONFIG_RSBAC_RW + struct rsbac_rw_req rsbac_rw_req_obj; +#endif + if (!(file->f_mode & FMODE_WRITE)) return -EBADF; if (!(file->f_mode & FMODE_CAN_WRITE)) @@ -512,11 +539,23 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ ret = rw_verify_area(WRITE, file, pos, count); if (!ret) { + +#ifdef CONFIG_RSBAC_RW + rsbac_rw_req_obj.rsbac_target = T_NONE; + rsbac_rw_req_obj.rsbac_request = R_WRITE; + if (!rsbac_handle_rw_req(file, &rsbac_rw_req_obj)) + return -EPERM; +#endif + if (count > MAX_RW_COUNT) count = MAX_RW_COUNT; file_start_write(file); ret = __vfs_write(file, buf, count, pos); if (ret > 0) { +#ifdef CONFIG_RSBAC_RW + rsbac_handle_rw_up(&rsbac_rw_req_obj); +#endif + fsnotify_modify(file); add_wchar(current, ret); } @@ -1347,6 +1386,15 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, ssize_t retval; int fl; +#ifdef CONFIG_RSBAC_RW + struct rsbac_rw_req rsbac_rw_req_obj1; + struct rsbac_rw_req rsbac_rw_req_obj2; + struct socket * sock1; + struct socket * sock2; + rsbac_rw_req_obj1.rsbac_target = T_NONE; + rsbac_rw_req_obj2.rsbac_target = T_NONE; +#endif + /* * Get input file, and verify that it is ok.. */ @@ -1370,6 +1418,29 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, if (count > MAX_RW_COUNT) count = MAX_RW_COUNT; +#ifdef CONFIG_RSBAC_RW +/* i could have done it in few lines of code, but that's way it is MUCH faster and sendfile is mostly beeing used with network sockets */ + if (S_ISSOCK(in.file->f_path.dentry->d_inode->i_mode)) { + sock1 = SOCKET_I(in.file->f_path.dentry->d_inode); + if ((sock1->ops) && (sock1->ops->family != AF_UNIX)) { + rsbac_rw_req_obj1.rsbac_target = T_NETOBJ; + rsbac_rw_req_obj1.rsbac_target_id.netobj.sock_p = sock1; + rsbac_rw_req_obj1.rsbac_target_id.netobj.local_addr = NULL; + rsbac_rw_req_obj1.rsbac_target_id.netobj.local_len = 0; + rsbac_rw_req_obj1.rsbac_target_id.netobj.remote_addr = NULL; + rsbac_rw_req_obj1.rsbac_target_id.netobj.remote_len = 0; + rsbac_rw_req_obj1.rsbac_attribute = A_sock_type; + rsbac_rw_req_obj1.rsbac_attribute_value.sock_type = sock1->type; + } + } + rsbac_rw_req_obj1.rsbac_request = R_READ; + if(!rsbac_handle_rw_req(in.file, &rsbac_rw_req_obj1)) + { + retval = -EPERM; + goto fput_in; + } +#endif + /* * Get output file, and verify that it is ok.. */ @@ -1387,6 +1458,28 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, if (retval < 0) goto fput_out; +#ifdef CONFIG_RSBAC_RW + if (S_ISSOCK(out.file->f_path.dentry->d_inode->i_mode)) { + sock2 = SOCKET_I(out.file->f_path.dentry->d_inode); + if ((sock2->ops) && (sock2->ops->family != AF_UNIX)) { + rsbac_rw_req_obj2.rsbac_target = T_NETOBJ; + rsbac_rw_req_obj2.rsbac_target_id.netobj.sock_p = sock2; + rsbac_rw_req_obj2.rsbac_target_id.netobj.local_addr = NULL; + rsbac_rw_req_obj2.rsbac_target_id.netobj.local_len = 0; + rsbac_rw_req_obj2.rsbac_target_id.netobj.remote_addr = NULL; + rsbac_rw_req_obj2.rsbac_target_id.netobj.remote_len = 0; + rsbac_rw_req_obj2.rsbac_attribute = A_sock_type; + rsbac_rw_req_obj2.rsbac_attribute_value.sock_type = sock2->type; + } + } + rsbac_rw_req_obj2.rsbac_request = R_WRITE; + if(!rsbac_handle_rw_req(out.file, &rsbac_rw_req_obj2)) + { + retval = -EPERM; + goto fput_out; + } +#endif + if (!max) max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); @@ -1429,6 +1522,11 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, if (pos > max) retval = -EOVERFLOW; +#ifdef CONFIG_RSBAC_RW + rsbac_handle_rw_up(&rsbac_rw_req_obj1); + rsbac_handle_rw_up(&rsbac_rw_req_obj2); +#endif + fput_out: fdput(out); fput_in: diff --git a/fs/readdir.c b/fs/readdir.c index 89659549c09d..7c5470cd0a76 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -22,11 +22,28 @@ #include +#ifdef CONFIG_RSBAC +#include +#ifdef CONFIG_RSBAC_FSOBJ_HIDE +#include "hfsplus/hfsplus_fs.h" +#include "hfsplus/hfsplus_raw.h" +#endif +#endif + +#include +#include + int iterate_dir(struct file *file, struct dir_context *ctx) { struct inode *inode = file_inode(file); bool shared = false; int res = -ENOTDIR; + +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (file->f_op->iterate_shared) shared = true; else if (!file->f_op->iterate) @@ -36,6 +53,23 @@ int iterate_dir(struct file *file, struct dir_context *ctx) if (res) goto out; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[old_readdir(), sys_getdents()]: calling ADF\n"); + rsbac_target_id.dir.device = inode->i_sb->s_dev; + rsbac_target_id.dir.inode = inode->i_ino; + rsbac_target_id.dir.dentry_p = file->f_path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_READ, + task_pid(current), + T_DIR, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + res = -EPERM; + goto out; + } +#endif + if (shared) { inode_lock_shared(inode); } else { @@ -85,6 +119,9 @@ struct old_linux_dirent { struct readdir_callback { struct dir_context ctx; struct old_linux_dirent __user * dirent; +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + struct file * file; +#endif int result; }; @@ -98,6 +135,11 @@ static int fillonedir(struct dir_context *ctx, const char *name, int namlen, if (buf->result) return -EINVAL; +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + if (!rsbac_handle_filldir(buf->file, name, namlen, ino)) + return 0; +#endif + d_ino = ino; if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { buf->result = -EOVERFLOW; @@ -134,6 +176,10 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd, if (!f.file) return -EBADF; +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + buf.file = f.file; +#endif + error = iterate_dir(f.file, &buf.ctx); if (buf.result) error = buf.result; @@ -159,6 +205,9 @@ struct getdents_callback { struct dir_context ctx; struct linux_dirent __user * current_dir; struct linux_dirent __user * previous; +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + struct file * file; +#endif int count; int error; }; @@ -176,6 +225,10 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen, buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + if (!rsbac_handle_filldir(buf->file, name, namlen, ino)) + return 0; +#endif d_ino = ino; if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { buf->error = -EOVERFLOW; @@ -228,6 +281,10 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, if (!f.file) return -EBADF; +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + buf.file = f.file; +#endif + error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; @@ -248,6 +305,9 @@ struct getdents_callback64 { struct linux_dirent64 __user * previous; int count; int error; +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + struct file * file; +#endif }; static int filldir64(struct dir_context *ctx, const char *name, int namlen, @@ -262,6 +322,12 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen, buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + if (!rsbac_handle_filldir(buf->file, name, namlen, ino)) + return 0; +#endif + dirent = buf->previous; if (dirent) { if (signal_pending(current)) @@ -311,6 +377,10 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, if (!f.file) return -EBADF; +#ifdef CONFIG_RSBAC_FSOBJ_HIDE + buf.file = f.file; +#endif + error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index bd39a998843d..b13e02621101 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -18,6 +18,7 @@ #include "acl.h" #include "xattr.h" #include +#include #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { inc_nlink(i); if (i->i_nlink >= REISERFS_LINK_MAX) set_nlink(i, 1); } #define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) drop_nlink(i); @@ -1060,6 +1061,11 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry) */ savelink = inode->i_nlink; +#ifdef CONFIG_RSBAC_SECDEL + if (inode->i_nlink == 1) + rsbac_sec_del(dentry, TRUE); +#endif + retval = reiserfs_cut_from_item(&th, &path, &de.de_entry_key, dir, NULL, 0); @@ -1451,6 +1457,11 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, journal_end(&th); reiserfs_write_unlock(old_dir->i_sb); return -EIO; +#ifdef CONFIG_RSBAC_SECDEL + } else { + if (new_dentry_inode && (new_dentry_inode->i_nlink == 1)) + rsbac_sec_del(new_dentry, TRUE); +#endif } copy_item_head(&old_entry_ih, tp_item_head(&old_entry_path)); diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index e87aa21c30de..551caa79ff23 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -935,6 +935,10 @@ static const struct dentry_operations xattr_lookup_poison_ops = { .d_revalidate = xattr_hide_revalidate, }; +#ifdef CONFIG_RSBAC +struct dentry * rsbac_lookup_one_len(const char * name, struct dentry * base, int len); +#endif + int reiserfs_lookup_privroot(struct super_block *s) { struct dentry *dentry; @@ -982,8 +986,13 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags) if (!REISERFS_SB(s)->xattr_root) { struct dentry *dentry; +#ifdef CONFIG_RSBAC + dentry = rsbac_lookup_one_len(XAROOT_NAME, s->s_root, + strlen(XAROOT_NAME)); +#else dentry = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME)); +#endif if (!IS_ERR(dentry)) REISERFS_SB(s)->xattr_root = dentry; else diff --git a/fs/stat.c b/fs/stat.c index c35610845ab1..74fa7113ebf9 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -20,6 +20,12 @@ #include #include +#ifdef CONFIG_RSBAC +#include +#include +#endif + + /** * generic_fillattr - Fill in the basic attributes from the inode struct * @inode: Inode to use as the source @@ -31,6 +37,12 @@ */ void generic_fillattr(struct inode *inode, struct kstat *stat) { + +#ifdef CONFIG_RSBAC_SYM_REDIR + char *rsbac_name; + int len = 0; +#endif + stat->dev = inode->i_sb->s_dev; stat->ino = inode->i_ino; stat->mode = inode->i_mode; @@ -38,6 +50,19 @@ void generic_fillattr(struct inode *inode, struct kstat *stat) stat->uid = inode->i_uid; stat->gid = inode->i_gid; stat->rdev = inode->i_rdev; + +#ifdef CONFIG_RSBAC_SYM_REDIR + if (S_ISLNK(inode->i_mode)) { + rsbac_name = rsbac_symlink_redirect(inode, "", 0, TRUE); + if (rsbac_name) { + len = strlen(rsbac_name); + kfree(rsbac_name); + } + stat->size = i_size_read(inode) + len; + } + else +#endif + stat->size = i_size_read(inode); stat->atime = inode->i_atime; stat->mtime = inode->i_mtime; @@ -109,9 +134,51 @@ int vfs_getattr(const struct path *path, struct kstat *stat, { int retval; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + retval = security_inode_getattr(path); if (retval) return retval; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_stat() etc.]: calling ADF\n"); + rsbac_target_id.file.device = path->dentry->d_inode->i_sb->s_dev; + rsbac_target_id.file.inode = path->dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = path->dentry; + if (S_ISDIR(path->dentry->d_inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(path->dentry->d_inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(path->dentry->d_inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(path->dentry->d_inode->i_mode)) { + if (path->dentry->d_inode->i_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = path->dentry->d_inode->i_ino; + } else { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = path->dentry->d_inode->i_sb->s_dev; + rsbac_target_id.unixsock.inode = path->dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = path->dentry; + } + } else + rsbac_target = T_FILE; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + return vfs_getattr_nosec(path, stat, request_mask, query_flags); } EXPORT_SYMBOL(vfs_getattr); @@ -386,6 +453,11 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, int empty = 0; unsigned int lookup_flags = LOOKUP_EMPTY; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (bufsiz <= 0) return -EINVAL; @@ -401,6 +473,24 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, if (d_is_symlink(path.dentry) || inode->i_op->readlink) { error = security_inode_readlink(path.dentry); if (!error) { + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.file.device = path.dentry->d_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = path.dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SYMLINK, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + path_put(&path); + return -EPERM; + } +#endif + touch_atime(&path); error = vfs_readlink(path.dentry, buf, bufsiz); } diff --git a/fs/statfs.c b/fs/statfs.c index fab9b6a3c116..dccf95f2a047 100644 --- a/fs/statfs.c +++ b/fs/statfs.c @@ -10,6 +10,8 @@ #include #include "internal.h" +#include + static int flags_by_mnt(int mnt_flags) { int flags = 0; @@ -53,9 +55,30 @@ static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf) { int retval; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!dentry->d_sb->s_op->statfs) return -ENOSYS; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(dentry->d_sb->s_dev); + rsbac_target_id.dev.minor = RSBAC_MINOR(dentry->d_sb->s_dev); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_DEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + memset(buf, 0, sizeof(*buf)); retval = security_sb_statfs(dentry); if (retval) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 39c75a86c67f..4c619208a37f 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -21,6 +21,8 @@ #include "sysfs.h" #include "../kernfs/kernfs-internal.h" +#include + /* * Determine ktype->sysfs_ops for the given kernfs_node. This function * must be called while holding an active reference. @@ -47,6 +49,25 @@ static int sysfs_kf_seq_show(struct seq_file *sf, void *v) ssize_t count; char *buf; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sysfs_kf_seq_show()]: calling ADF\n"); + rsbac_target_id.scd = ST_sysfs; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + /* acquire buffer and ensure that it's >= PAGE_SIZE and clear */ count = seq_get_buf(sf, &buf); if (count < PAGE_SIZE) { @@ -86,6 +107,11 @@ static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf, struct kobject *kobj = of->kn->parent->priv; loff_t size = file_inode(of->file)->i_size; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!count) return 0; @@ -99,6 +125,20 @@ static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf, if (!battr->read) return -EIO; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sysfs_kf_bin_read()]: calling ADF\n"); + rsbac_target_id.scd = ST_sysfs; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + return battr->read(of->file, kobj, battr, buf, pos, count); } @@ -135,9 +175,28 @@ static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf, const struct sysfs_ops *ops = sysfs_file_ops(of->kn); struct kobject *kobj = of->kn->parent->priv; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!count) return 0; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sysfs_kf_write()]: calling ADF\n"); + rsbac_target_id.scd = ST_sysfs; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + return ops->store(kobj, of->kn->priv, buf, count); } @@ -149,6 +208,11 @@ static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf, struct kobject *kobj = of->kn->parent->priv; loff_t size = file_inode(of->file)->i_size; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (size) { if (size <= pos) return -EFBIG; @@ -160,6 +224,20 @@ static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf, if (!battr->write) return -EIO; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sysfs_kf_bin_write()]: calling ADF\n"); + rsbac_target_id.scd = ST_sysfs; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + return battr->write(of->file, kobj, battr, buf, pos, count); } @@ -169,6 +247,25 @@ static int sysfs_kf_bin_mmap(struct kernfs_open_file *of, struct bin_attribute *battr = of->kn->priv; struct kobject *kobj = of->kn->parent->priv; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sysfs_kf_bin_write()]: calling ADF\n"); + rsbac_target_id.scd = ST_sysfs; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + return battr->mmap(of->file, kobj, battr, vma); } diff --git a/fs/utimes.c b/fs/utimes.c index 6571d8c848a0..f17b069c2fc4 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef __ARCH_WANT_SYS_UTIME @@ -51,6 +52,12 @@ static int utimes_common(const struct path *path, struct timespec *times) struct inode *inode = path->dentry->d_inode; struct inode *delegated_inode = NULL; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + error = mnt_want_write(path->mnt); if (error) goto out; @@ -85,6 +92,34 @@ static int utimes_common(const struct path *path, struct timespec *times) } else { newattrs.ia_valid |= ATTR_TOUCH; } + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target = T_FILE; + if (S_ISDIR(inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(inode->i_mode)) + rsbac_target = T_UNIXSOCK; + rsbac_target_id.file.device = inode->i_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = path->dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_ACCESS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + mnt_drop_write(path->mnt); + goto out; + } +#endif + retry_deleg: inode_lock(inode); error = notify_change(path->dentry, &newattrs, &delegated_inode); diff --git a/fs/xattr.c b/fs/xattr.c index 464c94bf65f9..ec114c4be9d4 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -34,6 +34,8 @@ strcmp_prefix(const char *a, const char *a_prefix) return *a_prefix ? NULL : a; } +#include + /* * In order to implement different sets of xattr operations for each xattr * prefix, a filesystem should create a null-terminated array of struct @@ -211,10 +213,41 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value, struct inode *inode = dentry->d_inode; int error; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + error = xattr_permission(inode, name, MAY_WRITE); if (error) return error; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_*setxattr()]: calling ADF\n"); + rsbac_target = T_FILE; + if (S_ISDIR(inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(inode->i_mode)) + rsbac_target = T_UNIXSOCK; + rsbac_target_id.file.device = dentry->d_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_PERMISSIONS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + inode_lock(inode); error = security_inode_setxattr(dentry, name, value, size, flags); if (error) @@ -318,6 +351,12 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) struct inode *inode = dentry->d_inode; int error; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + error = xattr_permission(inode, name, MAY_READ); if (error) return error; @@ -326,6 +365,31 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) if (error) return error; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_*getxattr()]: calling ADF\n"); + rsbac_target = T_FILE; + if (S_ISDIR(inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(inode->i_mode)) + rsbac_target = T_UNIXSOCK; + rsbac_target_id.file.device = dentry->d_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_PERMISSIONS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; @@ -349,9 +413,41 @@ vfs_listxattr(struct dentry *dentry, char *list, size_t size) struct inode *inode = d_inode(dentry); ssize_t error; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + error = security_inode_listxattr(dentry); if (error) return error; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_*listxattr()]: calling ADF\n"); + rsbac_target = T_FILE; + if (S_ISDIR(inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(inode->i_mode)) + rsbac_target = T_UNIXSOCK; + rsbac_target_id.file.device = dentry->d_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_PERMISSIONS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + if (inode->i_op->listxattr && (inode->i_opflags & IOP_XATTR)) { error = -EOPNOTSUPP; error = inode->i_op->listxattr(dentry, list, size); @@ -385,6 +481,12 @@ vfs_removexattr(struct dentry *dentry, const char *name) struct inode *inode = dentry->d_inode; int error; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + error = xattr_permission(inode, name, MAY_WRITE); if (error) return error; @@ -394,6 +496,32 @@ vfs_removexattr(struct dentry *dentry, const char *name) if (error) goto out; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_*removexattr()]: calling ADF\n"); + rsbac_target = T_FILE; + if (S_ISDIR(inode->i_mode)) + rsbac_target = T_DIR; + else if (S_ISFIFO(inode->i_mode)) + rsbac_target = T_FIFO; + else if (S_ISLNK(inode->i_mode)) + rsbac_target = T_SYMLINK; + else if (S_ISSOCK(inode->i_mode)) + rsbac_target = T_UNIXSOCK; + rsbac_target_id.file.device = dentry->d_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = dentry; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_PERMISSIONS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + goto out; + } +#endif + error = __vfs_removexattr(dentry, name); if (!error) { diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 469c9fa4c178..30e6feb759ef 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -78,6 +78,8 @@ xfs_initxattrs( return error; } +#include + /* * Hook in SELinux. This is not quite correct yet, what we really need * here (as we do for default ACLs) is a mechanism by which creation of @@ -350,6 +352,11 @@ xfs_vn_unlink( struct xfs_name name; int error; +#ifdef CONFIG_RSBAC_SECDEL + if (dentry->d_inode->i_nlink == 1) + rsbac_sec_del(dentry, FALSE); +#endif + xfs_dentry_to_name(&name, dentry); error = xfs_remove(XFS_I(dir), &name, XFS_I(d_inode(dentry))); @@ -422,6 +429,10 @@ xfs_vn_rename( struct xfs_name oname; struct xfs_name nname; +#ifdef CONFIG_RSBAC_SECDEL + struct xfs_inode *cip; +#endif + if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) return -EINVAL; @@ -438,6 +449,27 @@ xfs_vn_rename( if (unlikely(error)) return error; +#ifdef CONFIG_RSBAC_SECDEL + /* RSBAC secure delete code. in the event of overwritting existing + * file with sec_del flag set, its blocks will be deallocated so we + * have to overwrite their content. since XFS does all the necessary + * checks on the layer below linux VFS, operating on vnodes + * i decided to implement my own set of checks here, so we can see + * if the existing file is being overwritten. + * inspired by ext2/3/4 and jfs code. michal@rsbac.org + */ + + if (new_inode) { + if (new_inode->i_nlink == 1) { + if (!xfs_lookup(XFS_I(ndir), &nname, &cip, NULL)) { + IRELE(cip); + if(!S_ISDIR(new_inode->i_mode)) + rsbac_sec_del(ndentry, TRUE); + } + } + } +#endif + return xfs_rename(XFS_I(odir), &oname, XFS_I(d_inode(odentry)), XFS_I(ndir), &nname, new_inode ? XFS_I(new_inode) : NULL, flags); diff --git a/include/linux/fs.h b/include/linux/fs.h index 6e1fd5d21248..739fab53e69e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2982,6 +2982,9 @@ extern const struct file_operations generic_ro_fops; #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) extern int readlink_copy(char __user *, int, const char *); +#ifdef CONFIG_RSBAC_SYM_REDIR +extern int rsbac_readlink_copy(char __user *, int, const char *, struct inode *); +#endif extern int page_readlink(struct dentry *, char __user *, int); extern const char *page_get_link(struct dentry *, struct inode *, struct delayed_call *); diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 7f384bb62d8e..25b95ac56495 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -342,6 +342,11 @@ struct vm_area_struct { struct mempolicy *vm_policy; /* NUMA policy for the VMA */ #endif struct vm_userfaultfd_ctx vm_userfaultfd_ctx; + +#ifdef CONFIG_RSBAC_MPROTECT + __u8 rsbac_mprotect_once; +#endif + } __randomize_layout; struct core_thread { diff --git a/include/linux/sched.h b/include/linux/sched.h index 8337e2db0bb2..5d887205cbee 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -27,6 +27,10 @@ #include #include +#if defined(CONFIG_RSBAC_CAP_LOG_MISSING) || defined(CONFIG_RSBAC_JAIL_LOG_MISSING) +#include +#endif + /* task_struct member predeclarations (sorted alphabetically): */ struct audit_context; struct backing_dev_info; diff --git a/include/linux/sched/task.h b/include/linux/sched/task.h index c97e5f096927..c84c1112c49f 100644 --- a/include/linux/sched/task.h +++ b/include/linux/sched/task.h @@ -71,8 +71,8 @@ extern void do_group_exit(int); extern void exit_files(struct task_struct *); extern void exit_itimers(struct signal_struct *); -extern long _do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *, unsigned long); -extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *); +extern long _do_fork(unsigned long long, unsigned long, unsigned long, int __user *, int __user *, unsigned long); +extern long do_fork(unsigned long long, unsigned long, unsigned long, int __user *, int __user *); struct task_struct *fork_idle(int); extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); extern long kernel_wait4(pid_t, int *, int, struct rusage *); diff --git a/include/rsbac/aci.h b/include/rsbac/aci.h new file mode 100644 index 000000000000..895eeb7af831 --- /dev/null +++ b/include/rsbac/aci.h @@ -0,0 +1,154 @@ +/******************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: */ +/* Amon Ott */ +/* API: Data structures */ +/* and functions for Access */ +/* Control Information */ +/* Last modified: 21/Jun/2016 */ +/******************************* */ + +#ifndef __RSBAC_ACI_H +#define __RSBAC_ACI_H + +#include +#include +#include +#include + +/***************************************************/ +/* Prototypes */ +/***************************************************/ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac_error.h. */ + +/****************************************************************************/ +/* Initialization, including ACI restoration for all mounted devices from */ +/* disk. After this call, all ACI is kept in memory for performance reasons,*/ +/* but user and file/dir object ACI are written to disk on every change. */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +extern int rsbac_init(kdev_t root_dev); +#else +extern int rsbac_init(kdev_t root_dev) __init; +#endif + +/* Notify RSBAC of new kernel thread */ +int rsbac_kthread_notify(rsbac_pid_t pid); + +/* To turn RSBAC off on umount of root device */ +void rsbac_off(void); + +/* For other kernel parts to check, whether RSBAC was initialized correctly */ +extern rsbac_boolean_t rsbac_initialized; + +static inline rsbac_boolean_t rsbac_is_initialized(void) +{ + return rsbac_initialized; +} + +/* Check if the device exists */ +int rsbac_check_device(kdev_t kdev); + +/* Is device writable? */ +rsbac_boolean_t rsbac_writable(struct super_block * sb_p); + +/* When mounting a device, its ACI must be read and added to the ACI lists. */ +int rsbac_mount(struct vfsmount * vfsmount_p); + +/* When umounting a device, its ACI must be removed from the ACI lists. */ +int rsbac_umount(struct vfsmount * vfsmount_p); + +/* On pivot_root, we must unblock the dentry tree of the old root */ +/* by putting all cached rsbac.dat dentries */ +int rsbac_free_dat_dentries(void); + +/* Some information about the current status is also available */ +int rsbac_stats(void); + +/* Trigger internal consistency check (int: if != 0: correct errors) */ +int rsbac_check(int correct, int check_inode); + +/* RSBAC attribute saving to disk can be triggered from outside + * param: call lock_kernel() before disk access? + */ +#if defined(CONFIG_RSBAC_AUTO_WRITE) +int rsbac_write(void); +#endif + +/* get the parent of a target + * returns -RSBAC_EINVALIDTARGET for non-fs targets + * and -RSBAC_ENOTFOUND, if no parent available + * In kernels >= 2.4.0, device_p->d_covers is used and the item is properly + * locked for reading, so never call with a write lock held on device_p! + */ +int rsbac_get_parent(enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t * parent_target_p, + union rsbac_target_id_t * parent_tid_p); + +/* Invalidate cached attribute values for one or all filesystem objects */ + +#ifdef CONFIG_RSBAC_FD_CACHE +int rsbac_fd_cache_invalidate(struct rsbac_fs_file_t * file_p); + +int rsbac_fd_cache_invalidate_device(kdev_t kdev); + +int rsbac_fd_cache_invalidate_all(void); +#endif + +/****************************************************************************/ +/* For objects, users and processes all manipulation is encapsulated by the */ +/* function calls rsbac_set_attr, rsbac_get_attr and rsbac_remove_target. */ + +int rsbac_ta_get_attr( + rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t * value, + rsbac_boolean_t inherit); + +#define rsbac_get_attr(module, target, tid, attr, value, inherit) \ + rsbac_ta_get_attr(0, module, target, tid, attr, value, inherit) + +int rsbac_ta_set_attr( + rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t value); + +#define rsbac_set_attr(module, target, tid, attr, value) \ + rsbac_ta_set_attr(0, module, target, tid, attr, value) + +/* All RSBAC targets should be removed, if no longer needed, to prevent */ +/* memory wasting. */ + +int rsbac_ta_remove_target( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid); + +#define rsbac_remove_target(target, tid) \ + rsbac_ta_remove_target(0, target, tid) + +int rsbac_ta_list_all_dev(rsbac_list_ta_number_t ta_number, + struct rsbac_dev_desc_t ** id_pp); + +int rsbac_ta_list_all_user(rsbac_list_ta_number_t ta_number, + rsbac_uid_t ** id_pp); + +int rsbac_ta_list_all_ipc(rsbac_list_ta_number_t ta_number, + struct rsbac_ipc_t ** id_pp); + +int rsbac_ta_list_all_group(rsbac_list_ta_number_t ta_number, + rsbac_gid_t ** id_pp); + +int rsbac_mark_kthread(rsbac_pid_t pid); +int rsbac_kthreads_init(void); +void rsbac_delayed_kfree(void * data, rsbac_time_t ttl); +#endif diff --git a/include/rsbac/aci_data_structures.h b/include/rsbac/aci_data_structures.h new file mode 100644 index 000000000000..7c48a802d4a3 --- /dev/null +++ b/include/rsbac/aci_data_structures.h @@ -0,0 +1,1728 @@ +/**************************************/ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2017: Amon Ott */ +/* Data structures */ +/* Last modified: 21/Mar/2017 */ +/**************************************/ + +#ifndef __RSBAC_DATA_STRUC_H +#define __RSBAC_DATA_STRUC_H + +#ifdef __KERNEL__ /* only include in kernel code */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* __KERNEL__ */ + +#ifdef __KERNEL__ + +/* List to keep mounts before init, so that we can rsbac_mount them at init */ + +struct rsbac_mount_list_t { + struct vfsmount * vfsmount_p; + struct rsbac_mount_list_t * next; +}; + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +struct rsbac_delayed_kfree_list_t { + void * data; + struct rsbac_delayed_kfree_list_t * next; + rsbac_time_t max_age; +}; +#endif + +/* First of all we define dirname and filenames for saving the ACIs to disk. */ +/* The path must be a valid single dir name! Each mounted device gets its */ +/* own file set, residing in 'DEVICE_ROOT/RSBAC_ACI_PATH/'. */ +/* The dynamic data structures for RC and ACL are kept in their own files. */ +/* All user access to these files will be denied. */ +/* Backups are kept in FILENAMEb. */ + +#define RSBAC_LOG_BUF_LEN (16384) + +#define RSBAC_ACI_PATH "rsbac.dat" + +#define RSBAC_GEN_FD_NAME "fd_gen" +#define RSBAC_GEN_OLD_FD_NAME "fd_gen." +#define RSBAC_MAC_FD_NAME "fd_mac" +#define RSBAC_MAC_OLD_FD_NAME "fd_mac." +#define RSBAC_DAZ_FD_NAME "fd_dazt" +#define RSBAC_DAZ_OLD_FD_NAME "fd_dazt." +#define RSBAC_DAZ_SCANNED_FD_NAME "fd_dazs" +#define RSBAC_DAZ_SCANNED_OLD_FD_NAME "fd_dazs." +#define RSBAC_FF_FD_NAME "fd_ff" +#define RSBAC_FF_OLD_FD_NAME "fd_ff." +#define RSBAC_RC_FD_NAME "fd_rc" +#define RSBAC_RC_OLD_FD_NAME "fd_rc." +#define RSBAC_AUTH_FD_NAME "fd_auth" +#define RSBAC_AUTH_OLD_FD_NAME "fd_auth." +#define RSBAC_CAP_FD_NAME "fd_cap" +#define RSBAC_CAP_OLD_FD_NAME "fd_cap." +#define RSBAC_PAX_FD_NAME "fd_pax" +#define RSBAC_PAX_OLD_FD_NAME "fd_pax." +#define RSBAC_RES_FD_NAME "fd_res" +#define RSBAC_RES_OLD_FD_NAME "fd_res." +#define RSBAC_UDF_FD_NAME "fd_udft" +#define RSBAC_UDF_CHECKED_FD_NAME "fd_udfc" + +#define RSBAC_ACI_USER_NAME "useraci" +/* dir creation mode for discretionary access control: no rights*/ +#define RSBAC_ACI_DIR_MODE (S_IFDIR) +/* file creation mode for discretionary access control: rw for user only*/ +#define RSBAC_ACI_FILE_MODE (S_IFREG | S_IRUSR | S_IWUSR) +/* minimal mem chunk size available to try write_partial_fd_list, else defer */ +#define RSBAC_MIN_WRITE_FD_BUF_LEN 32768 +/* max size for write_chunks */ +#define RSBAC_MAX_WRITE_CHUNK ((1 << 15) - 1) + +#define RSBAC_GEN_NR_FD_LIST_HASH_BITS 1 +#define RSBAC_MAC_NR_FD_LIST_HASH_BITS 2 +#define RSBAC_DAZ_NR_FD_LIST_HASH_BITS 1 +#define RSBAC_DAZ_SCANNED_NR_FD_LIST_HASH_BITS 2 +#define RSBAC_FF_NR_FD_LIST_HASH_BITS 2 +#define RSBAC_RC_NR_FD_LIST_HASH_BITS 2 +#define RSBAC_AUTH_NR_FD_LIST_HASH_BITS 1 +#define RSBAC_CAP_NR_FD_LIST_HASH_BITS 1 +#define RSBAC_PAX_NR_FD_LIST_HASH_BITS 1 +#define RSBAC_RES_NR_FD_LIST_HASH_BITS 1 +#define RSBAC_UDF_NR_FD_LIST_HASH_BITS 1 +#define RSBAC_UDF_CHECKED_NR_FD_LIST_HASH_BITS 2 + +#define RSBAC_P_LIST_HASH_BITS 4 + +#ifdef CONFIG_RSBAC_INIT_THREAD +/* Check and set init timeout */ +#if CONFIG_RSBAC_MAX_INIT_TIME >= 5 +#define RSBAC_MAX_INIT_TIME CONFIG_RSBAC_MAX_INIT_TIME +#else +#define RSBAC_MAX_INIT_TIME 5 +#endif +#endif /* INIT_THREAD */ + +#endif /* __KERNEL__ */ + +/* The following structures privide attributes for all possible targets. */ +/* The data structures are kept in double linked lists, and are optimized */ +/* by hash functions. */ + +/* Only ATTRIBUTES are saved in those structures, that are saved to disk, */ +/* because saving sublists means breaking up the structures for every */ +/* single list. */ +/* If a list of policy dependant items is to be stored, this is done in */ +/* the policy dependant data structures. Here only an ID as a handle is */ +/* supported. */ + +/* OK, first we define the file/dir ACI, holding all file/dir information */ +/* the ADF needs for decisions. */ + +/* Caution: whenever ACI changes, version and old_version should be increased! */ + +// #define CONFIG_RSBAC_FD_CACHE 1 + +#ifdef CONFIG_RSBAC_FD_CACHE +#define RSBAC_FD_CACHE_NAME "fd_cache." +#define RSBAC_FD_CACHE_VERSION 1 +#define RSBAC_FD_CACHE_KEY 3626114 +#endif + +#define RSBAC_GEN_FD_ACI_VERSION 8 +#define RSBAC_GEN_FD_ACI_KEY 1001 +struct rsbac_gen_fd_aci_t { + rsbac_log_array_t log_array_low; /* file/dir based logging, */ + rsbac_log_array_t log_array_high; /* high and low bits */ + rsbac_request_vector_t log_program_based; /* Program based logging */ + rsbac_enum_t symlink_add_remote_ip; + rsbac_enum_t symlink_add_uid; + rsbac_enum_t symlink_add_mac_level; + rsbac_enum_t symlink_add_rc_role; + rsbac_enum_t allow_write_exec; + rsbac_fake_root_uid_int_t fake_root_uid; + rsbac_uid_t auid_exempt; + rsbac_um_set_t vset; +}; +#define DEFAULT_GEN_FD_ACI \ + { \ + .log_array_low = -1, \ + .log_array_high = -1, \ + .log_program_based = 0, \ + .symlink_add_uid = FALSE, \ + .symlink_add_mac_level = FALSE, \ + .symlink_add_rc_role = FALSE, \ + .allow_write_exec = AWX_inherit, \ + .fake_root_uid = FR_off, \ + .auid_exempt = RSBAC_NO_USER, \ + .vset = RSBAC_UM_VIRTUAL_KEEP, \ + } + +#define DEFAULT_GEN_ROOT_DIR_ACI \ + { \ + .log_array_low = -1, \ + .log_array_high = -1, \ + .log_program_based = 0, \ + .symlink_add_uid = FALSE, \ + .symlink_add_mac_level = FALSE, \ + .symlink_add_rc_role = FALSE, \ + .allow_write_exec = AWX_relocate, \ + .fake_root_uid = FR_off, \ + .auid_exempt = RSBAC_NO_USER, \ + .vset = RSBAC_UM_VIRTUAL_KEEP, \ + } + +#define RSBAC_GEN_FD_OLD_ACI_VERSION 7 +struct rsbac_gen_fd_old_aci_t { + rsbac_log_array_t log_array_low; /* file/dir based logging, */ + rsbac_log_array_t log_array_high; /* high and low bits */ + rsbac_request_vector_t log_program_based; /* Program based logging */ + rsbac_enum_t symlink_add_remote_ip; + rsbac_enum_t symlink_add_uid; + rsbac_enum_t symlink_add_mac_level; + rsbac_enum_t symlink_add_rc_role; + rsbac_enum_t allow_write_exec; + rsbac_fake_root_uid_int_t fake_root_uid; + rsbac_old_uid_t auid_exempt; +}; +#define RSBAC_GEN_FD_OLD_OLD_ACI_VERSION 6 +struct rsbac_gen_fd_old_old_aci_t { + rsbac_log_array_t log_array_low; /* file/dir based logging, */ + rsbac_log_array_t log_array_high; /* high and low bits */ + rsbac_request_vector_t log_program_based; /* Program based logging */ + rsbac_enum_t symlink_add_uid; + rsbac_enum_t symlink_add_mac_level; + rsbac_enum_t symlink_add_rc_role; + rsbac_enum_t allow_write_exec; + rsbac_fake_root_uid_int_t fake_root_uid; + rsbac_old_uid_t auid_exempt; +}; + +#define RSBAC_GEN_FD_OLD_OLD_OLD_ACI_VERSION 5 +struct rsbac_gen_fd_old_old_old_aci_t { + rsbac_log_array_t log_array_low; /* file/dir based logging, */ + rsbac_log_array_t log_array_high; /* high and low bits */ + rsbac_request_vector_t log_program_based; /* Program based logging */ + rsbac_enum_t symlink_add_uid; + rsbac_enum_t symlink_add_mac_level; + rsbac_enum_t symlink_add_rc_role; + rsbac_enum_t allow_write_exec; + rsbac_fake_root_uid_int_t fake_root_uid; +}; + +#if defined(CONFIG_RSBAC_MAC) +#define RSBAC_MAC_FD_ACI_VERSION 5 +#define RSBAC_MAC_FD_ACI_KEY 1001 +struct rsbac_mac_fd_aci_t { + rsbac_security_level_t sec_level; /* MAC */ + rsbac_mac_category_vector_t mac_categories; /* MAC category set */ + rsbac_mac_auto_int_t mac_auto; /* auto-adjust current level */ + rsbac_boolean_int_t mac_prop_trusted; /* Keep trusted flag when executing this file */ + rsbac_mac_file_flags_t mac_file_flags; /* allow write_up, read_up etc. to it */ +}; + +#define RSBAC_MAC_FD_OLD_ACI_VERSION 4 +struct rsbac_mac_fd_old_aci_t { + rsbac_security_level_t sec_level; /* MAC */ + rsbac_uid_t mac_trusted_for_user; /* MAC (for FILE only) */ + rsbac_mac_category_vector_t mac_categories; /* MAC category set */ + rsbac_mac_auto_int_t mac_auto; /* auto-adjust current level */ + rsbac_boolean_int_t mac_prop_trusted; /* Keep trusted flag when executing this file */ + rsbac_mac_file_flags_t mac_file_flags; /* allow write_up, read_up etc. to it */ +}; + +#define RSBAC_MAC_FD_OLD_OLD_ACI_VERSION 3 +struct rsbac_mac_fd_old_old_aci_t { + rsbac_security_level_t sec_level; /* MAC */ + rsbac_uid_t mac_trusted_for_user; /* MAC (for FILE only) */ + rsbac_mac_category_vector_t mac_categories; /* MAC category set */ + rsbac_mac_auto_int_t mac_auto; /* auto-adjust current level */ + rsbac_boolean_int_t mac_prop_trusted; /* Keep trusted flag when executing this file */ + rsbac_boolean_int_t mac_shared; /* Shared dir, i.e., allow write_up to it */ +}; + +#define RSBAC_MAC_FD_OLD_OLD_OLD_ACI_VERSION 2 +struct rsbac_mac_fd_old_old_old_aci_t { + rsbac_security_level_t sec_level; /* MAC */ + rsbac_uid_t mac_trusted_for_user; /* MAC (for FILE only) */ + rsbac_mac_category_vector_t mac_categories; /* MAC category set */ + rsbac_mac_auto_int_t mac_auto; /* auto-adjust current level */ +}; + +#define DEFAULT_MAC_FD_ACI_INH \ + { \ + .sec_level = SL_inherit, \ + .mac_categories = RSBAC_MAC_INHERIT_CAT_VECTOR, \ + .mac_auto = MA_inherit, \ + .mac_prop_trusted = FALSE, \ + .mac_file_flags = 0, \ + } +#define DEFAULT_MAC_FD_ACI_NO_INH \ + { \ + .sec_level = SL_unclassified, \ + .mac_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_auto = MA_yes, \ + .mac_prop_trusted = FALSE, \ + .mac_file_flags = 0, \ + } + +#ifdef CONFIG_RSBAC_MAC_DEF_INHERIT +#define DEFAULT_MAC_FD_ACI DEFAULT_MAC_FD_ACI_INH +#else +#define DEFAULT_MAC_FD_ACI DEFAULT_MAC_FD_ACI_NO_INH +#endif /* MAC_DEF_INHERIT */ + +#define DEFAULT_MAC_ROOT_DIR_ACI \ + { \ + .sec_level = SL_unclassified, \ + .mac_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_auto = MA_yes, \ + .mac_prop_trusted = FALSE, \ + .mac_file_flags = 0, \ + } +#endif + +#if defined(CONFIG_RSBAC_DAZ) +#define RSBAC_DAZ_FD_ACI_VERSION 2 +#define RSBAC_DAZ_FD_OLD_ACI_VERSION 1 +#define RSBAC_DAZ_FD_ACI_KEY 10535 +#define RSBAC_DAZ_CACHE_CLEANUP_INTERVAL 86400 +#define RSBAC_DAZ_SCANNED_FD_ACI_VERSION 1 +struct rsbac_daz_fd_aci_t + { + rsbac_daz_scanner_t daz_scanner; /* DAZ (for FILE only) */ + rsbac_daz_do_scan_t daz_do_scan; + }; + +struct rsbac_daz_fd_old_aci_t + { + rsbac_daz_scanner_t daz_scanner; /* DAZ (for FILE only) (boolean) */ + }; + +#define DEFAULT_DAZ_FD_ACI \ + { \ + .daz_scanner = FALSE, \ + .daz_do_scan = DEFAULT_DAZ_FD_DO_SCAN \ + } + +#define DEFAULT_DAZ_ROOT_DIR_ACI \ + { \ + .daz_scanner = FALSE, \ + .daz_do_scan = DEFAULT_DAZ_FD_ROOT_DO_SCAN \ + } +#endif + +#if defined(CONFIG_RSBAC_FF) +#define RSBAC_FF_FD_ACI_VERSION 1 +#define RSBAC_FF_FD_ACI_KEY 1001 +#endif + +#if defined(CONFIG_RSBAC_RC) +#define RSBAC_RC_FD_ACI_VERSION 1 +#define RSBAC_RC_FD_ACI_KEY 1001 +struct rsbac_rc_fd_aci_t { + rsbac_rc_type_id_t rc_type_fd; /* RC */ + rsbac_rc_role_id_t rc_force_role; /* RC */ + rsbac_rc_role_id_t rc_initial_role; /* RC */ +}; + +#define DEFAULT_RC_FD_ACI \ + { \ + .rc_type_fd = RC_type_inherit_parent, \ + .rc_force_role = RC_default_force_role, \ + .rc_initial_role = RC_default_initial_role, \ + } +#define DEFAULT_RC_ROOT_DIR_ACI \ + { \ + .rc_type_fd = RSBAC_RC_GENERAL_TYPE, \ + .rc_force_role = RC_default_root_dir_force_role, \ + .rc_initial_role = RC_default_root_dir_initial_role, \ + } +#endif + +#if defined(CONFIG_RSBAC_AUTH) +#define RSBAC_AUTH_FD_ACI_VERSION 2 +#define RSBAC_AUTH_FD_OLD_ACI_VERSION 1 +#define RSBAC_AUTH_FD_ACI_KEY 1001 +struct rsbac_auth_fd_aci_t { + __u8 auth_may_setuid; /* AUTH (enum) */ + __u8 auth_may_set_cap; /* AUTH (boolean) */ + __u8 auth_learn; /* AUTH (boolean) */ +}; + +struct rsbac_auth_fd_old_aci_t { + __u8 auth_may_setuid; /* AUTH (boolean) */ + __u8 auth_may_set_cap; /* AUTH (boolean) */ +}; + +#define DEFAULT_AUTH_FD_ACI \ + { \ + .auth_may_setuid = FALSE, \ + .auth_may_set_cap = FALSE, \ + .auth_learn = FALSE, \ + } +#endif + +#if defined(CONFIG_RSBAC_CAP) +#define RSBAC_CAP_FD_ACI_VERSION 3 +#define RSBAC_CAP_FD_OLD_ACI_VERSION 2 +#define RSBAC_CAP_FD_OLD_OLD_ACI_VERSION 1 +#define RSBAC_CAP_FD_ACI_KEY 1001 +struct rsbac_cap_fd_aci_t { + rsbac_cap_vector_t min_caps; /* Program forced minimum Linux capabilities */ + rsbac_cap_vector_t max_caps; /* Program max Linux capabilities */ + rsbac_cap_ld_env_int_t cap_ld_env; +}; + +struct rsbac_cap_fd_old_aci_t { + rsbac_cap_old_vector_t min_caps; /* Program forced minimum Linux capabilities */ + rsbac_cap_old_vector_t max_caps; /* Program max Linux capabilities */ + rsbac_cap_ld_env_int_t cap_ld_env; +}; + +struct rsbac_cap_fd_old_old_aci_t { + rsbac_cap_old_vector_t min_caps; + rsbac_cap_old_vector_t max_caps; +}; + +#define DEFAULT_CAP_FD_ACI \ + { \ + .min_caps.cap[0] = RSBAC_CAP_DEFAULT_MIN, \ + .max_caps.cap[0] = RSBAC_CAP_DEFAULT_MAX, \ + .min_caps.cap[1] = RSBAC_CAP_DEFAULT_MIN, \ + .max_caps.cap[1] = RSBAC_CAP_DEFAULT_MAX, \ + .cap_ld_env = LD_keep, \ + } +#endif + +#if defined(CONFIG_RSBAC_PAX) +#define RSBAC_PAX_FD_ACI_VERSION 1 +#define RSBAC_PAX_FD_ACI_KEY 100112 +#endif + +#if defined(CONFIG_RSBAC_RES) +#define RSBAC_RES_FD_ACI_VERSION 1 +#define RSBAC_RES_FD_ACI_KEY 1002 +struct rsbac_res_fd_aci_t { + rsbac_res_array_t res_min; + rsbac_res_array_t res_max; +}; +#define DEFAULT_RES_FD_ACI \ + { \ + .res_min = { \ + RSBAC_RES_UNSET, /* cpu time */ \ + RSBAC_RES_UNSET, /* file size */ \ + RSBAC_RES_UNSET, /* process data segment size */ \ + RSBAC_RES_UNSET, /* stack size */ \ + RSBAC_RES_UNSET, /* core dump size */ \ + RSBAC_RES_UNSET, /* resident memory set size */ \ + RSBAC_RES_UNSET, /* number of processes for this user */ \ + RSBAC_RES_UNSET, /* number of files */ \ + RSBAC_RES_UNSET, /* locked-in-memory address space */ \ + RSBAC_RES_UNSET, /* address space (virtual memory) limit */ \ + RSBAC_RES_UNSET /* maximum file locks */ \ + }, \ + .res_max = { \ + RSBAC_RES_UNSET, /* cpu time */ \ + RSBAC_RES_UNSET, /* file size */ \ + RSBAC_RES_UNSET, /* process data segment size */ \ + RSBAC_RES_UNSET, /* stack size */ \ + RSBAC_RES_UNSET, /* core dump size */ \ + RSBAC_RES_UNSET, /* resident memory set size */ \ + RSBAC_RES_UNSET, /* number of processes for this user */ \ + RSBAC_RES_UNSET, /* number of files */ \ + RSBAC_RES_UNSET, /* locked-in-memory address space */ \ + RSBAC_RES_UNSET, /* address space (virtual memory) limit */ \ + RSBAC_RES_UNSET /* maximum file locks */ \ + } \ + } +#endif +#if defined(CONFIG_RSBAC_UDF) +#define RSBAC_UDF_FD_ACI_VERSION 1 +#define RSBAC_UDF_FD_ACI_KEY 764209 +#define RSBAC_UDF_CACHE_CLEANUP_INTERVAL 86400 +#define RSBAC_UDF_CHECKED_FD_ACI_VERSION 1 +struct rsbac_udf_fd_aci_t + { + rsbac_udf_checker_t udf_checker; /* UDF (for FILE only) */ + rsbac_udf_do_check_t udf_do_check; + }; + +#define DEFAULT_UDF_FD_ACI \ + { \ + .udf_checker = FALSE, \ + .udf_do_check = DEFAULT_UDF_FD_DO_CHECK \ + } + +#define DEFAULT_UDF_ROOT_DIR_ACI \ + { \ + .udf_checker = FALSE, \ + .udf_do_check = DEFAULT_UDF_FD_ROOT_DO_CHECK \ + } +#endif + + +#define RSBAC_FD_NR_ATTRIBUTES 33 +#define RSBAC_FD_ATTR_LIST { \ + A_security_level, \ + A_mac_categories, \ + A_mac_auto, \ + A_mac_prop_trusted, \ + A_mac_file_flags, \ + A_daz_scanner, \ + A_ff_flags, \ + A_rc_type_fd, \ + A_rc_force_role, \ + A_rc_initial_role, \ + A_auth_may_setuid, \ + A_auth_may_set_cap, \ + A_auth_learn, \ + A_log_array_low, \ + A_log_array_high, \ + A_log_program_based, \ + A_symlink_add_remote_ip, \ + A_symlink_add_uid, \ + A_symlink_add_mac_level, \ + A_symlink_add_rc_role, \ + A_allow_write_exec, \ + A_min_caps, \ + A_max_caps, \ + A_cap_ld_env, \ + A_res_min, \ + A_res_max, \ + A_pax_flags, \ + A_fake_root_uid, \ + A_auid_exempt, \ + A_daz_do_scan, \ + A_vset, \ + A_udf_checker, \ + A_udf_do_check \ + } + +#ifdef __KERNEL__ +struct rsbac_fd_list_handles_t { + rsbac_list_handle_t gen; +#if defined(CONFIG_RSBAC_MAC) + rsbac_list_handle_t mac; +#endif +#if defined(CONFIG_RSBAC_DAZ) + rsbac_list_handle_t daz; +#if defined(CONFIG_RSBAC_DAZ_CACHE) + rsbac_list_handle_t dazs; +#endif +#endif +#if defined(CONFIG_RSBAC_FF) + rsbac_list_handle_t ff; +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_list_handle_t rc; +#endif +#if defined(CONFIG_RSBAC_AUTH) + rsbac_list_handle_t auth; +#endif +#if defined(CONFIG_RSBAC_CAP) + rsbac_list_handle_t cap; +#endif +#if defined(CONFIG_RSBAC_PAX) + rsbac_list_handle_t pax; +#endif +#if defined(CONFIG_RSBAC_RES) + rsbac_list_handle_t res; +#endif +#if defined(CONFIG_RSBAC_UDF) + rsbac_list_handle_t udf; +#if defined(CONFIG_RSBAC_UDF_CACHE) + rsbac_list_handle_t udfc; +#endif +#endif +}; + +/* The list of devices is also a double linked list, so we define list */ +/* items and a list head. */ + +/* Hash size. Must be power of 2. */ + +#define RSBAC_NR_DEVICE_LISTS 8 + +struct rsbac_device_list_item_t { + kdev_t id; + u_int mount_count; + struct rsbac_fd_list_handles_t handles; + struct dentry *rsbac_dir_dentry_p; + struct vfsmount *vfsmount_p; + rsbac_inode_nr_t rsbac_dir_inode; + struct rsbac_device_list_item_t *prev; + struct rsbac_device_list_item_t *next; +#ifdef CONFIG_RSBAC_FD_CACHE + rsbac_list_handle_t fd_cache_handle[SW_NONE]; +#ifdef CONFIG_RSBAC_XSTATS + __u64 fd_cache_hits[SW_NONE]; + __u64 fd_cache_misses[SW_NONE]; + u_int fd_cache_invalidates; + u_int fd_cache_invalidate_alls; +#endif +#endif + rsbac_boolean_t persist; +}; + +/* To provide consistency we use spinlocks for all list accesses. The */ +/* 'curr' entry is used to avoid repeated lookups for the same item. */ + +struct rsbac_device_list_head_t { + struct rsbac_device_list_item_t *head; + struct rsbac_device_list_item_t *tail; + struct rsbac_device_list_item_t *curr; + u_int count; +}; + +#endif /* __KERNEL__ */ + +/******************************/ +/* OK, now we define the block/char device ACI, holding all dev information */ +/* the ADF needs for decisions. */ + +#define RSBAC_GEN_ACI_DEV_NAME "dev_gen" +#define RSBAC_MAC_ACI_DEV_NAME "dev_mac" +#define RSBAC_RC_ACI_DEV_MAJOR_NAME "devm_rc" +#define RSBAC_RC_ACI_DEV_NAME "dev_rc" + +/* Caution: whenever ACI changes, version should be increased! */ + +#define RSBAC_GEN_DEV_ACI_VERSION 2 +#define RSBAC_GEN_DEV_OLD_ACI_VERSION 1 +#define RSBAC_GEN_DEV_ACI_KEY 1001 + +struct rsbac_gen_dev_aci_t { + rsbac_log_array_t log_array_low; /* dev based logging, */ + rsbac_log_array_t log_array_high; /* high and low bits */ +}; +#define DEFAULT_GEN_DEV_ACI \ + { \ + .log_array_low = -1, \ + .log_array_high = -1, \ + } + +#if defined(CONFIG_RSBAC_MAC) +#define RSBAC_MAC_DEV_ACI_VERSION 2 +#define RSBAC_MAC_DEV_OLD_ACI_VERSION 1 +#define RSBAC_MAC_DEV_ACI_KEY 1001 +struct rsbac_mac_dev_aci_t { + rsbac_security_level_t sec_level; /* MAC */ + rsbac_mac_category_vector_t mac_categories; /* MAC category set */ + __u8 mac_check; /* MAC (boolean) */ +}; +#define DEFAULT_MAC_DEV_ACI \ + { \ + .sec_level = SL_unclassified, \ + .mac_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_check = FALSE, \ + } +#endif + +#if defined(CONFIG_RSBAC_RC) +#define RSBAC_RC_DEV_ACI_VERSION 2 +#define RSBAC_RC_DEV_OLD_ACI_VERSION 1 +#define RSBAC_RC_DEV_ACI_KEY 1001 +#endif + +#define RSBAC_DEV_NR_ATTRIBUTES 6 +#define RSBAC_DEV_ATTR_LIST { \ + A_security_level, \ + A_mac_categories, \ + A_mac_check, \ + A_rc_type, \ + A_log_array_low, \ + A_log_array_high \ + } + +#ifdef __KERNEL__ +struct rsbac_dev_handles_t { + rsbac_list_handle_t gen; +#if defined(CONFIG_RSBAC_MAC) + rsbac_list_handle_t mac; +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_list_handle_t rc; +#endif +}; +#endif /* __KERNEL__ */ + +/**************************************************************************/ +/* Next we define the ipc ACI, holding all ipc information */ +/* the ADF needs for decisions. */ + +#define RSBAC_MAC_ACI_IPC_NAME "ipc_mac" +#define RSBAC_RC_ACI_IPC_NAME "ipc_rc" +#define RSBAC_JAIL_ACI_IPC_NAME "ipc_jai" + +#if defined(CONFIG_RSBAC_MAC) +#define RSBAC_MAC_IPC_ACI_VERSION 1 +#define RSBAC_MAC_IPC_ACI_KEY 1001 +struct rsbac_mac_ipc_aci_t { + rsbac_security_level_t sec_level; /* enum old_rsbac_security_level_t / __u8 */ + rsbac_mac_category_vector_t mac_categories; /* MAC category set */ +}; +#define DEFAULT_MAC_IPC_ACI \ + { \ + .sec_level = SL_unclassified, \ + .mac_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + } +#endif + +#if defined(CONFIG_RSBAC_RC) +#define RSBAC_RC_IPC_ACI_VERSION 1 +#define RSBAC_RC_IPC_ACI_KEY 1001 +#endif + +#if defined(CONFIG_RSBAC_JAIL) +#define RSBAC_JAIL_IPC_ACI_VERSION 1 +#define RSBAC_JAIL_IPC_ACI_KEY 1001 +#endif + +#define RSBAC_IPC_NR_ATTRIBUTES 4 +#define RSBAC_IPC_ATTR_LIST { \ + A_security_level, \ + A_mac_categories, \ + A_rc_type, \ + A_jail_id \ + } + +#ifdef __KERNEL__ +struct rsbac_ipc_handles_t { +#if defined(CONFIG_RSBAC_MAC) + rsbac_list_handle_t mac; +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_list_handle_t rc; +#endif +#if defined(CONFIG_RSBAC_JAIL) + rsbac_list_handle_t jail; +#endif +}; +#endif /* __KERNEL__ */ + +/*************************************/ +/* The user ACI holds all user information the ADF needs. */ + +#define RSBAC_GEN_ACI_USER_NAME "u_gen" +#define RSBAC_MAC_ACI_USER_NAME "u_mac" +#define RSBAC_DAZ_ACI_USER_NAME "u_daz" +#define RSBAC_FF_ACI_USER_NAME "u_ff" +#define RSBAC_RC_ACI_USER_NAME "u_rc" +#define RSBAC_AUTH_ACI_USER_NAME "u_auth" +#define RSBAC_CAP_ACI_USER_NAME "u_cap" +#define RSBAC_JAIL_ACI_USER_NAME "u_jail" +#define RSBAC_PAX_ACI_USER_NAME "u_pax" +#define RSBAC_RES_ACI_USER_NAME "u_res" +#define RSBAC_UDF_ACI_USER_NAME "u_udf" + +#define RSBAC_GEN_USER_ACI_VERSION 2 +#define RSBAC_GEN_USER_OLD_ACI_VERSION 1 +#define RSBAC_GEN_USER_ACI_KEY 1001 +struct rsbac_gen_user_aci_t { + rsbac_pseudo_t pseudo; + rsbac_request_vector_t log_user_based; /* User based logging */ +}; +#define DEFAULT_GEN_U_ACI \ + { \ + .pseudo = (rsbac_pseudo_t) 0, \ + .log_user_based = 0, \ + } + +#if defined(CONFIG_RSBAC_MAC) +#define RSBAC_MAC_USER_ACI_VERSION 5 +#define RSBAC_MAC_USER_OLD_ACI_VERSION 4 +#define RSBAC_MAC_USER_OLD_OLD_ACI_VERSION 3 +#define RSBAC_MAC_USER_OLD_OLD_OLD_ACI_VERSION 2 +#define RSBAC_MAC_USER_OLD_OLD_OLD_OLD_ACI_VERSION 1 +#define RSBAC_MAC_USER_ACI_KEY 1001 +struct rsbac_mac_user_aci_t { + rsbac_security_level_t security_level; /* maximum level */ + rsbac_security_level_t initial_security_level; /* maximum level */ + rsbac_security_level_t min_security_level; /* minimum level / __u8 */ + rsbac_mac_category_vector_t mac_categories; /* MAC max category set */ + rsbac_mac_category_vector_t mac_initial_categories; /* MAC max category set */ + rsbac_mac_category_vector_t mac_min_categories; /* MAC min category set */ + rsbac_system_role_int_t system_role; /* enum rsbac_system_role_t */ + rsbac_mac_user_flags_t mac_user_flags; /* flags (override, trusted, allow_auto etc.) */ +}; +struct rsbac_mac_user_old_aci_t { + rsbac_security_level_t access_appr; /* maximum level */ + rsbac_security_level_t min_access_appr; /* minimum level / __u8 */ + rsbac_mac_category_vector_t mac_categories; /* MAC max category set */ + rsbac_mac_category_vector_t mac_min_categories; /* MAC min category set */ + rsbac_system_role_int_t system_role; /* enum rsbac_system_role_t */ + rsbac_boolean_int_t mac_allow_auto; /* allow to auto-adjust current level */ +}; +struct rsbac_mac_user_old_old_aci_t { + rsbac_security_level_t access_appr; /* maximum level */ + rsbac_security_level_t min_access_appr; /* minimum level / __u8 */ + rsbac_mac_category_vector_t mac_categories; /* MAC max category set */ + rsbac_mac_category_vector_t mac_min_categories; /* MAC min category set */ + rsbac_system_role_int_t system_role; /* enum rsbac_system_role_t */ +}; +struct rsbac_mac_user_old_old_old_aci_t { + rsbac_security_level_t access_appr; /* enum old_rsbac_security_level_t / __u8 */ + rsbac_mac_category_vector_t mac_categories; /* MAC category set */ + rsbac_system_role_int_t system_role; /* enum rsbac_system_role_t */ +}; +#define DEFAULT_MAC_U_ACI \ + { \ + .security_level = SL_unclassified, \ + .initial_security_level = SL_unclassified, \ + .min_security_level = SL_unclassified, \ + .mac_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_initial_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_min_categories = RSBAC_MAC_MIN_CAT_VECTOR, \ + .system_role = SR_user, \ + .mac_user_flags = RSBAC_MAC_DEF_U_FLAGS, \ + } +#define DEFAULT_MAC_U_SYSADM_ACI \ + { \ + .security_level = SL_unclassified, \ + .initial_security_level = SL_unclassified, \ + .min_security_level = SL_unclassified, \ + .mac_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_initial_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_min_categories = RSBAC_MAC_MIN_CAT_VECTOR, \ + .system_role = SR_administrator, \ + .mac_user_flags = RSBAC_MAC_DEF_SYSADM_U_FLAGS, \ + } +#define DEFAULT_MAC_U_SECOFF_ACI \ + { \ + .security_level = SL_unclassified, \ + .initial_security_level = SL_unclassified, \ + .min_security_level = SL_unclassified, \ + .mac_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_initial_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_min_categories = RSBAC_MAC_MIN_CAT_VECTOR, \ + .system_role = SR_security_officer, \ + .mac_user_flags = RSBAC_MAC_DEF_SECOFF_U_FLAGS, \ + } +#define DEFAULT_MAC_U_AUDITOR_ACI \ + { \ + .security_level = SL_unclassified, \ + .initial_security_level = SL_unclassified, \ + .min_security_level = SL_unclassified, \ + .mac_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_initial_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_min_categories = RSBAC_MAC_MIN_CAT_VECTOR, \ + .system_role = SR_auditor, \ + .mac_user_flags = RSBAC_MAC_DEF_U_FLAGS, \ + } +#endif + +#if defined(CONFIG_RSBAC_DAZ) +#define RSBAC_DAZ_USER_ACI_VERSION 2 +#define RSBAC_DAZ_USER_OLD_ACI_VERSION 1 +#define RSBAC_DAZ_USER_ACI_KEY 1001 +#endif + +#if defined(CONFIG_RSBAC_FF) +#define RSBAC_FF_USER_ACI_VERSION 2 +#define RSBAC_FF_USER_OLD_ACI_VERSION 1 +#define RSBAC_FF_USER_ACI_KEY 1001 +#endif + +#if defined(CONFIG_RSBAC_RC) +#define RSBAC_RC_USER_ACI_VERSION 3 +#define RSBAC_RC_USER_OLD_ACI_VERSION 2 +#define RSBAC_RC_USER_OLD_OLD_ACI_VERSION 1 +#define RSBAC_RC_USER_ACI_KEY 1001 +struct rsbac_rc_user_aci_t { + rsbac_rc_role_id_t rc_role; + rsbac_rc_type_id_t rc_type; +}; +#define DEFAULT_RC_U_ACI \ + { \ + .rc_role = RSBAC_RC_GENERAL_ROLE, \ + .rc_type = RSBAC_RC_GENERAL_TYPE, \ + } +#define DEFAULT_RC_U_SYSADM_ACI \ + { \ + .rc_role = RSBAC_RC_SYSTEM_ADMIN_ROLE, /* rc_role (RC) */ \ + .rc_type = RSBAC_RC_SYS_TYPE, \ + } +#define DEFAULT_RC_U_SECOFF_ACI \ + { \ + .rc_role = RSBAC_RC_ROLE_ADMIN_ROLE, /* rc_role (RC) */ \ + .rc_type = RSBAC_RC_SEC_TYPE, \ + } +#define DEFAULT_RC_U_AUDITOR_ACI \ + { \ + .rc_role = RSBAC_RC_AUDITOR_ROLE, /* rc_role (RC) */ \ + .rc_type = RSBAC_RC_SEC_TYPE, \ + } +#endif + +#if defined(CONFIG_RSBAC_AUTH) +#define RSBAC_AUTH_USER_ACI_VERSION 2 +#define RSBAC_AUTH_USER_OLD_ACI_VERSION 1 +#define RSBAC_AUTH_USER_ACI_KEY 1001 + +#endif /* AUTH */ + +#if defined(CONFIG_RSBAC_CAP) +#define RSBAC_CAP_USER_ACI_VERSION 4 +#define RSBAC_CAP_USER_OLD_ACI_VERSION 3 +#define RSBAC_CAP_USER_OLD_OLD_ACI_VERSION 2 +#define RSBAC_CAP_USER_OLD_OLD_OLD_ACI_VERSION 1 +#define RSBAC_CAP_USER_ACI_KEY 1001 +struct rsbac_cap_user_aci_t { + rsbac_system_role_int_t cap_role; /* System role for CAP administration */ + rsbac_cap_vector_t min_caps; /* User forced minimum Linux capabilities */ + rsbac_cap_vector_t max_caps; /* User max Linux capabilities */ + rsbac_cap_ld_env_int_t cap_ld_env; +}; + +struct rsbac_cap_user_old_aci_t { + rsbac_system_role_int_t cap_role; /* System role for CAP administration */ + rsbac_cap_old_vector_t min_caps; /* User forced minimum Linux capabilities */ + rsbac_cap_old_vector_t max_caps; /* User max Linux capabilities */ + rsbac_cap_ld_env_int_t cap_ld_env; +}; + +struct rsbac_cap_user_old_old_aci_t { + rsbac_system_role_int_t cap_role; /* System role for CAP administration */ + rsbac_cap_old_vector_t min_caps; /* User forced minimum Linux capabilities */ + rsbac_cap_old_vector_t max_caps; /* User max Linux capabilities */ + rsbac_cap_ld_env_int_t cap_ld_env; +}; + +struct rsbac_cap_user_old_old_old_aci_t { + rsbac_system_role_int_t cap_role; /* System role for CAP administration */ + rsbac_cap_old_vector_t min_caps; /* User forced minimum Linux capabilities */ + rsbac_cap_old_vector_t max_caps; /* User max Linux capabilities */ +}; + +#define DEFAULT_CAP_U_ACI \ + { \ + .cap_role = SR_user, \ + .min_caps.cap[0] = RSBAC_CAP_DEFAULT_MIN, \ + .max_caps.cap[0] = RSBAC_CAP_DEFAULT_MAX, \ + .min_caps.cap[1] = RSBAC_CAP_DEFAULT_MIN, \ + .max_caps.cap[1] = RSBAC_CAP_DEFAULT_MAX, \ + .cap_ld_env = LD_keep, \ + } +#define DEFAULT_CAP_U_SYSADM_ACI \ + { \ + .cap_role = SR_administrator, \ + .min_caps.cap[0] = RSBAC_CAP_DEFAULT_MIN, \ + .max_caps.cap[0] = RSBAC_CAP_DEFAULT_MAX, \ + .min_caps.cap[1] = RSBAC_CAP_DEFAULT_MIN, \ + .max_caps.cap[1] = RSBAC_CAP_DEFAULT_MAX, \ + .cap_ld_env = LD_keep, \ + } +#define DEFAULT_CAP_U_SECOFF_ACI \ + { \ + .cap_role = SR_security_officer, \ + .min_caps.cap[0] = RSBAC_CAP_DEFAULT_MIN, \ + .max_caps.cap[0] = RSBAC_CAP_DEFAULT_MAX, \ + .min_caps.cap[1] = RSBAC_CAP_DEFAULT_MIN, \ + .max_caps.cap[1] = RSBAC_CAP_DEFAULT_MAX, \ + .cap_ld_env = LD_keep, \ + } +#define DEFAULT_CAP_U_AUDITOR_ACI \ + { \ + .cap_role = SR_auditor, \ + .min_caps.cap[0] = RSBAC_CAP_DEFAULT_MIN, \ + .max_caps.cap[0] = RSBAC_CAP_DEFAULT_MAX, \ + .min_caps.cap[1] = RSBAC_CAP_DEFAULT_MIN, \ + .max_caps.cap[1] = RSBAC_CAP_DEFAULT_MAX, \ + .cap_ld_env = LD_keep, \ + } +#endif + +#if defined(CONFIG_RSBAC_JAIL) +#define RSBAC_JAIL_USER_ACI_VERSION 2 +#define RSBAC_JAIL_USER_OLD_ACI_VERSION 1 +#define RSBAC_JAIL_USER_ACI_KEY 1001 +#endif + +#if defined(CONFIG_RSBAC_PAX) +#define RSBAC_PAX_USER_ACI_VERSION 2 +#define RSBAC_PAX_USER_OLD_ACI_VERSION 1 +#define RSBAC_PAX_USER_ACI_KEY 1001221 +#endif + +#if defined(CONFIG_RSBAC_RES) +#define RSBAC_RES_USER_ACI_VERSION 2 +#define RSBAC_RES_USER_OLD_ACI_VERSION 1 +#define RSBAC_RES_USER_ACI_KEY 1002 +struct rsbac_res_user_aci_t { + rsbac_system_role_int_t res_role; /* System role for RES administration */ + rsbac_res_array_t res_min; + rsbac_res_array_t res_max; +}; +#define DEFAULT_RES_U_ACI \ + { \ + .res_role = SR_user, \ + .res_min = { \ + RSBAC_RES_UNSET, /* cpu time */ \ + RSBAC_RES_UNSET, /* file size */ \ + RSBAC_RES_UNSET, /* process data segment size */ \ + RSBAC_RES_UNSET, /* stack size */ \ + RSBAC_RES_UNSET, /* core dump size */ \ + RSBAC_RES_UNSET, /* resident memory set size */ \ + RSBAC_RES_UNSET, /* number of processes for this user */ \ + RSBAC_RES_UNSET, /* number of files */ \ + RSBAC_RES_UNSET, /* locked-in-memory address space */ \ + RSBAC_RES_UNSET, /* address space (virtual memory) limit */ \ + RSBAC_RES_UNSET /* maximum file locks */ \ + }, \ + .res_max = { \ + RSBAC_RES_UNSET, /* cpu time */ \ + RSBAC_RES_UNSET, /* file size */ \ + RSBAC_RES_UNSET, /* process data segment size */ \ + RSBAC_RES_UNSET, /* stack size */ \ + RSBAC_RES_UNSET, /* core dump size */ \ + RSBAC_RES_UNSET, /* resident memory set size */ \ + RSBAC_RES_UNSET, /* number of processes for this user */ \ + RSBAC_RES_UNSET, /* number of files */ \ + RSBAC_RES_UNSET, /* locked-in-memory address space */ \ + RSBAC_RES_UNSET, /* address space (virtual memory) limit */ \ + RSBAC_RES_UNSET /* maximum file locks */ \ + }, \ + } +#define DEFAULT_RES_U_SYSADM_ACI \ + { \ + .res_role = SR_administrator, \ + .res_min = { \ + RSBAC_RES_UNSET, /* cpu time */ \ + RSBAC_RES_UNSET, /* file size */ \ + RSBAC_RES_UNSET, /* process data segment size */ \ + RSBAC_RES_UNSET, /* stack size */ \ + RSBAC_RES_UNSET, /* core dump size */ \ + RSBAC_RES_UNSET, /* resident memory set size */ \ + RSBAC_RES_UNSET, /* number of processes for this user */ \ + RSBAC_RES_UNSET, /* number of files */ \ + RSBAC_RES_UNSET, /* locked-in-memory address space */ \ + RSBAC_RES_UNSET, /* address space (virtual memory) limit */ \ + RSBAC_RES_UNSET /* maximum file locks */ \ + }, \ + .res_max = { \ + RSBAC_RES_UNSET, /* cpu time */ \ + RSBAC_RES_UNSET, /* file size */ \ + RSBAC_RES_UNSET, /* process data segment size */ \ + RSBAC_RES_UNSET, /* stack size */ \ + RSBAC_RES_UNSET, /* core dump size */ \ + RSBAC_RES_UNSET, /* resident memory set size */ \ + RSBAC_RES_UNSET, /* number of processes for this user */ \ + RSBAC_RES_UNSET, /* number of files */ \ + RSBAC_RES_UNSET, /* locked-in-memory address space */ \ + RSBAC_RES_UNSET, /* address space (virtual memory) limit */ \ + RSBAC_RES_UNSET /* maximum file locks */ \ + } \ + } +#define DEFAULT_RES_U_SECOFF_ACI \ + { \ + .res_role = SR_security_officer, \ + .res_min = { \ + RSBAC_RES_UNSET, /* cpu time */ \ + RSBAC_RES_UNSET, /* file size */ \ + RSBAC_RES_UNSET, /* process data segment size */ \ + RSBAC_RES_UNSET, /* stack size */ \ + RSBAC_RES_UNSET, /* core dump size */ \ + RSBAC_RES_UNSET, /* resident memory set size */ \ + RSBAC_RES_UNSET, /* number of processes for this user */ \ + RSBAC_RES_UNSET, /* number of files */ \ + RSBAC_RES_UNSET, /* locked-in-memory address space */ \ + RSBAC_RES_UNSET, /* address space (virtual memory) limit */ \ + RSBAC_RES_UNSET /* maximum file locks */ \ + }, \ + .res_max = { \ + RSBAC_RES_UNSET, /* cpu time */ \ + RSBAC_RES_UNSET, /* file size */ \ + RSBAC_RES_UNSET, /* process data segment size */ \ + RSBAC_RES_UNSET, /* stack size */ \ + RSBAC_RES_UNSET, /* core dump size */ \ + RSBAC_RES_UNSET, /* resident memory set size */ \ + RSBAC_RES_UNSET, /* number of processes for this user */ \ + RSBAC_RES_UNSET, /* number of files */ \ + RSBAC_RES_UNSET, /* locked-in-memory address space */ \ + RSBAC_RES_UNSET, /* address space (virtual memory) limit */ \ + RSBAC_RES_UNSET /* maximum file locks */ \ + } \ + } +#define DEFAULT_RES_U_AUDITOR_ACI \ + { \ + .res_role = SR_auditor, \ + .res_min = { \ + RSBAC_RES_UNSET, /* cpu time */ \ + RSBAC_RES_UNSET, /* file size */ \ + RSBAC_RES_UNSET, /* process data segment size */ \ + RSBAC_RES_UNSET, /* stack size */ \ + RSBAC_RES_UNSET, /* core dump size */ \ + RSBAC_RES_UNSET, /* resident memory set size */ \ + RSBAC_RES_UNSET, /* number of processes for this user */ \ + RSBAC_RES_UNSET, /* number of files */ \ + RSBAC_RES_UNSET, /* locked-in-memory address space */ \ + RSBAC_RES_UNSET, /* address space (virtual memory) limit */ \ + RSBAC_RES_UNSET /* maximum file locks */ \ + }, \ + .res_max = { \ + RSBAC_RES_UNSET, /* cpu time */ \ + RSBAC_RES_UNSET, /* file size */ \ + RSBAC_RES_UNSET, /* process data segment size */ \ + RSBAC_RES_UNSET, /* stack size */ \ + RSBAC_RES_UNSET, /* core dump size */ \ + RSBAC_RES_UNSET, /* resident memory set size */ \ + RSBAC_RES_UNSET, /* number of processes for this user */ \ + RSBAC_RES_UNSET, /* number of files */ \ + RSBAC_RES_UNSET, /* locked-in-memory address space */ \ + RSBAC_RES_UNSET, /* address space (virtual memory) limit */ \ + RSBAC_RES_UNSET /* maximum file locks */ \ + } \ + } +#endif + +#if defined(CONFIG_RSBAC_UDF) +#define RSBAC_UDF_USER_ACI_VERSION 1 +#define RSBAC_UDF_USER_ACI_KEY 429822 +#endif + +#define RSBAC_USER_NR_ATTRIBUTES 23 +#define RSBAC_USER_ATTR_LIST { \ + A_pseudo, \ + A_log_user_based, \ + A_security_level, \ + A_initial_security_level, \ + A_min_security_level, \ + A_mac_categories, \ + A_mac_initial_categories, \ + A_mac_min_categories, \ + A_mac_role, \ + A_mac_user_flags, \ + A_daz_role, \ + A_ff_role, \ + A_auth_role, \ + A_rc_def_role, \ + A_rc_type, \ + A_min_caps, \ + A_max_caps, \ + A_cap_role, \ + A_cap_ld_env, \ + A_jail_role, \ + A_res_role, \ + A_pax_role, \ + A_udf_role \ + } + +#ifdef __KERNEL__ +struct rsbac_user_handles_t { + rsbac_list_handle_t gen; +#if defined(CONFIG_RSBAC_MAC) + rsbac_list_handle_t mac; +#endif +#if defined(CONFIG_RSBAC_DAZ) + rsbac_list_handle_t daz; +#endif +#if defined(CONFIG_RSBAC_FF) + rsbac_list_handle_t ff; +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_list_handle_t rc; +#endif +#if defined(CONFIG_RSBAC_AUTH) + rsbac_list_handle_t auth; +#endif +#if defined(CONFIG_RSBAC_CAP) + rsbac_list_handle_t cap; +#endif +#if defined(CONFIG_RSBAC_JAIL) + rsbac_list_handle_t jail; +#endif +#if defined(CONFIG_RSBAC_PAX) + rsbac_list_handle_t pax; +#endif +#if defined(CONFIG_RSBAC_RES) + rsbac_list_handle_t res; +#endif +#if defined(CONFIG_RSBAC_UDF) + rsbac_list_handle_t udf; +#endif +}; +#endif + +/********************************/ +/* Process ACI. */ + +#define RSBAC_GEN_ACI_PROCESS_NAME "process_gen" +#define RSBAC_MAC_ACI_PROCESS_NAME "process_mac" +#define RSBAC_DAZ_ACI_PROCESS_NAME "process_daz" +#define RSBAC_RC_ACI_PROCESS_NAME "process_rc" +#define RSBAC_AUTH_ACI_PROCESS_NAME "process_auth" +#define RSBAC_CAP_ACI_PROCESS_NAME "process_cap" +#define RSBAC_JAIL_ACI_PROCESS_NAME "process_jail" +#define RSBAC_UDF_ACI_PROCESS_NAME "process_udf" + +#define RSBAC_GEN_PROCESS_ACI_VERSION 3 +#define RSBAC_GEN_PROCESS_ACI_KEY 1001 +struct rsbac_gen_process_aci_t { + rsbac_request_vector_t log_program_based; + rsbac_fake_root_uid_int_t fake_root_uid; + rsbac_uid_t audit_uid; + rsbac_uid_t auid_exempt; + __u32 remote_ip; + rsbac_boolean_t kernel_thread; + rsbac_um_set_t vset; + rsbac_enum_t allow_write_exec; +}; +#if defined(CONFIG_RSBAC_LOG_PROGRAM_FILE) || defined(CONFIG_RSBAC_AUTH_LEARN) || defined(CONFIG_RSBAC_CAP_LEARN) +#define DEFAULT_GEN_P_ACI \ + { \ + .log_program_based = 0, \ + .fake_root_uid = FR_off, \ + .audit_uid = RSBAC_NO_USER, \ + .auid_exempt = RSBAC_NO_USER, \ + .remote_ip = 0, \ + .kernel_thread = 0, \ + .vset = 0, \ + .allow_write_exec = AWX_relocate, \ + } +#else +#define DEFAULT_GEN_P_ACI \ + { \ + .log_program_based = 0, \ + .fake_root_uid = FR_off, \ + .audit_uid = RSBAC_NO_USER, \ + .auid_exempt = RSBAC_NO_USER, \ + .remote_ip = 0, \ + .kernel_thread = 0, \ + .vset = 0, \ + .allow_write_exec = AWX_relocate, \ + } +#endif + + +#if defined(CONFIG_RSBAC_MAC) || defined(CONFIG_RSBAC_MAC_MAINT) +#define RSBAC_MAC_PROCESS_ACI_VERSION 1 +#define RSBAC_MAC_PROCESS_ACI_KEY 1001 +struct rsbac_mac_process_aci_t { + rsbac_security_level_t owner_sec_level; /* enum old_rsbac_security_level_t */ + rsbac_security_level_t owner_initial_sec_level; /* enum old_rsbac_security_level_t */ + rsbac_security_level_t owner_min_sec_level; /* enum old_rsbac_security_level_t */ + rsbac_mac_category_vector_t mac_owner_categories; /* MAC category set */ + rsbac_mac_category_vector_t mac_owner_initial_categories; /* MAC category set */ + rsbac_mac_category_vector_t mac_owner_min_categories; /* MAC category set */ + rsbac_security_level_t current_sec_level; /* enum rsbac_security_level_t */ + rsbac_mac_category_vector_t mac_curr_categories; /* MAC current category set */ + rsbac_security_level_t min_write_open; /* for *-property, enum rsbac_security_level_t */ + rsbac_mac_category_vector_t min_write_categories; /* MAC, for *-property */ + rsbac_security_level_t max_read_open; /* for *-property, enum rsbac_security_level_t */ + rsbac_mac_category_vector_t max_read_categories; /* MAC, for *-property */ + rsbac_mac_process_flags_t mac_process_flags; /* flags (override, trusted, auto etc.) */ +}; +#define DEFAULT_MAC_P_ACI \ + { \ + .owner_sec_level = SL_unclassified, \ + .owner_initial_sec_level = SL_unclassified, \ + .owner_min_sec_level = SL_unclassified, \ + .mac_owner_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_owner_initial_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_owner_min_categories = RSBAC_MAC_MIN_CAT_VECTOR, \ + .current_sec_level = SL_unclassified, \ + .mac_curr_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .min_write_open = SL_max, \ + .min_write_categories = RSBAC_MAC_MAX_CAT_VECTOR, \ + .max_read_open = SL_unclassified, \ + .max_read_categories = RSBAC_MAC_MIN_CAT_VECTOR, \ + .mac_process_flags = RSBAC_MAC_DEF_P_FLAGS, \ + } +#define DEFAULT_MAC_P_INIT_ACI \ + { \ + .owner_sec_level = SL_unclassified, \ + .owner_initial_sec_level = SL_unclassified, \ + .owner_min_sec_level = SL_unclassified, \ + .mac_owner_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_owner_initial_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .mac_owner_min_categories = RSBAC_MAC_MIN_CAT_VECTOR, \ + .current_sec_level = SL_unclassified, \ + .mac_curr_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + .min_write_open = SL_max, \ + .min_write_categories = RSBAC_MAC_MAX_CAT_VECTOR, \ + .max_read_open = SL_unclassified, \ + .max_read_categories = RSBAC_MAC_MIN_CAT_VECTOR, \ + .mac_process_flags = RSBAC_MAC_DEF_INIT_P_FLAGS, \ + } +#endif + +#if defined(CONFIG_RSBAC_DAZ) +#define RSBAC_DAZ_PROCESS_ACI_VERSION 1 +#define RSBAC_DAZ_PROCESS_ACI_KEY 1001 +struct rsbac_daz_process_aci_t { + rsbac_boolean_int_t daz_scanner; /* DAZ, boolean */ +}; +#define DEFAULT_DAZ_P_ACI \ + { \ + .daz_scanner = FALSE, \ + } +#endif + +#if defined(CONFIG_RSBAC_RC) +#define RSBAC_RC_PROCESS_ACI_VERSION 1 +#define RSBAC_RC_PROCESS_ACI_KEY 1001 +struct rsbac_rc_process_aci_t { + rsbac_rc_role_id_t rc_role; /* RC */ + rsbac_rc_type_id_t rc_type; /* RC */ + rsbac_rc_role_id_t rc_force_role; /* RC */ + rsbac_rc_type_id_t rc_select_type; /* RC */ +}; +#define DEFAULT_RC_P_ACI \ + { \ + .rc_role = RSBAC_RC_GENERAL_ROLE, \ + .rc_type = RSBAC_RC_GENERAL_TYPE, \ + .rc_force_role = RC_default_force_role, \ + .rc_select_type = RC_type_use_fd, \ + } +#define DEFAULT_RC_P_INIT_ACI \ + { \ + .rc_role = RSBAC_RC_SYSTEM_ADMIN_ROLE, \ + .rc_type = RSBAC_RC_GENERAL_TYPE, \ + .rc_force_role = RC_default_force_role, \ + .rc_select_type = RC_type_use_fd, \ + } +#define DEFAULT_RC_P_KERNEL_ACI \ + { \ + .rc_role = RSBAC_RC_SYSTEM_ADMIN_ROLE, \ + .rc_type = CONFIG_RSBAC_RC_KERNEL_PROCESS_TYPE, \ + .rc_force_role = RC_default_force_role, \ + .rc_select_type = RC_type_use_fd, \ + } +#endif + +#if defined(CONFIG_RSBAC_AUTH) +#define RSBAC_AUTH_PROCESS_ACI_VERSION 1 +#define RSBAC_AUTH_PROCESS_ACI_KEY 1001 +struct rsbac_auth_process_aci_t { + __u8 auth_may_setuid; /* AUTH (boolean) */ + __u8 auth_may_set_cap; /* AUTH (boolean) */ + rsbac_uid_t auth_last_auth; +#if defined(CONFIG_RSBAC_AUTH_LEARN) + rsbac_uid_t auth_start_uid; +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + rsbac_uid_t auth_start_euid; +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + rsbac_gid_t auth_start_gid; +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + rsbac_gid_t auth_start_egid; +#endif +#endif + __u8 auth_learn; /* AUTH (boolean) */ +#endif +}; + +#if defined(CONFIG_RSBAC_AUTH_LEARN) +#define DEFAULT_AUTH_P_ACI \ + { \ + .auth_may_setuid = FALSE, \ + .auth_may_set_cap = FALSE, \ + .auth_last_auth = RSBAC_NO_USER, \ + .auth_start_uid = 0, \ + .auth_learn = 0, \ + } +#else +#define DEFAULT_AUTH_P_ACI \ + { \ + .auth_may_setuid = FALSE, \ + .auth_may_set_cap = FALSE, \ + .auth_last_auth = RSBAC_NO_USER, \ + } +#endif +#endif + + +#if defined(CONFIG_RSBAC_CAP) +#define RSBAC_CAP_PROCESS_ACI_VERSION 2 +#define RSBAC_CAP_PROCESS_ACI_KEY 10013283 +struct rsbac_cap_process_aci_t { + rsbac_cap_process_hiding_int_t cap_process_hiding; +#if defined(CONFIG_RSBAC_CAP_LOG_MISSING) || defined(CONFIG_RSBAC_CAP_LEARN) + rsbac_cap_vector_t max_caps_user; + rsbac_cap_vector_t max_caps_program; +#endif + rsbac_cap_ld_env_int_t cap_ld_env; +}; + +#ifdef CONFIG_RSBAC_CAP_LOG_MISSING +#define DEFAULT_CAP_P_ACI \ + { \ + .cap_process_hiding = PH_off, \ + .max_caps_user.cap[0] = RSBAC_CAP_DEFAULT_MAX, \ + .max_caps_user.cap[1] = RSBAC_CAP_DEFAULT_MAX, \ + .max_caps_program.cap[0] = RSBAC_CAP_DEFAULT_MAX, \ + .max_caps_program.cap[1] = RSBAC_CAP_DEFAULT_MAX, \ + .cap_ld_env = LD_allow, \ + } +#else +#define DEFAULT_CAP_P_ACI \ + { \ + .cap_process_hiding = PH_off, \ + .cap_ld_env = LD_allow, \ + } +#endif +#endif + +#if defined(CONFIG_RSBAC_JAIL) +#define RSBAC_JAIL_PROCESS_ACI_VERSION 1 +#define RSBAC_JAIL_PROCESS_ACI_KEY 1001 +struct rsbac_jail_process_aci_t { + rsbac_jail_id_t id; + rsbac_jail_id_t parent; + rsbac_jail_ip_t ip; + rsbac_jail_flags_t flags; + rsbac_cap_vector_t max_caps; /* Program max Linux capabilities */ + rsbac_jail_scd_vector_t scd_get; /* SCD targets GET_STATUS_DATA */ + rsbac_jail_scd_vector_t scd_modify; /* SCD targets MODIFY_SYSTEM_DATA */ +}; +#define DEFAULT_JAIL_P_ACI \ + { \ + .id = 0, \ + .parent = 0, \ + .ip = 0, \ + .flags = 0, \ + .max_caps.cap[0] = -1, \ + .max_caps.cap[1] = -1, \ + .scd_get = 0, \ + .scd_modify = 0, \ + } +#endif + +#if defined(CONFIG_RSBAC_UDF) +#define RSBAC_UDF_PROCESS_ACI_VERSION 1 +#define RSBAC_UDF_PROCESS_ACI_KEY 98428 +struct rsbac_udf_process_aci_t { + rsbac_boolean_int_t udf_checker; /* UDF, boolean */ +}; +#define DEFAULT_UDF_P_ACI \ + { \ + .udf_checker = FALSE, \ + } +#endif + +#define RSBAC_PROCESS_NR_ATTRIBUTES 38 +#define RSBAC_PROCESS_ATTR_LIST { \ + A_security_level, \ + A_min_security_level, \ + A_mac_categories, \ + A_mac_min_categories, \ + A_current_sec_level, \ + A_mac_curr_categories, \ + A_min_write_open, \ + A_min_write_categories, \ + A_max_read_open, \ + A_max_read_categories, \ + A_mac_process_flags, \ + A_daz_scanner, \ + A_rc_role, \ + A_rc_type, \ + A_rc_force_role, \ + A_rc_select_type, \ + A_auth_may_setuid, \ + A_auth_may_set_cap, \ + A_auth_learn, \ + A_cap_process_hiding, \ + A_max_caps_user, \ + A_max_caps_program, \ + A_cap_ld_env, \ + A_jail_id, \ + A_jail_ip, \ + A_jail_flags, \ + A_jail_max_caps, \ + A_jail_scd_get, \ + A_jail_scd_modify, \ + A_log_program_based, \ + A_fake_root_uid, \ + A_audit_uid, \ + A_auid_exempt, \ + A_auth_last_auth, \ + A_remote_ip, \ + A_vset, \ + A_udf_checker, \ + A_allow_write_exec \ + } + +#ifdef __KERNEL__ +struct rsbac_process_handles_t { + rsbac_list_handle_t gen; +#if defined(CONFIG_RSBAC_MAC) + rsbac_list_handle_t mac; +#endif +#if defined(CONFIG_RSBAC_DAZ) + rsbac_list_handle_t daz; +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_list_handle_t rc; +#endif +#if defined(CONFIG_RSBAC_AUTH) + rsbac_list_handle_t auth; +#endif +#if defined(CONFIG_RSBAC_CAP) + rsbac_list_handle_t cap; +#endif +#if defined(CONFIG_RSBAC_JAIL) + rsbac_list_handle_t jail; +#endif +#if defined(CONFIG_RSBAC_UDF) + rsbac_list_handle_t udf; +#endif +}; +#endif /* __KERNEL__ */ + + +/******************************/ +/* OK, now we define the UM group ACI, holding all information */ +/* the ADF needs for decisions. */ + +#define RSBAC_RC_ACI_GROUP_NAME "grouprc" + +/* Caution: whenever ACI changes, version should be increased! */ + +#if defined(CONFIG_RSBAC_RC_UM_PROT) +#define RSBAC_RC_GROUP_ACI_VERSION 1 +#define RSBAC_RC_GROUP_ACI_KEY 13276142 +#endif + +#define RSBAC_GROUP_NR_ATTRIBUTES 1 +#define RSBAC_GROUP_ATTR_LIST { \ + A_rc_type \ + } + +#ifdef __KERNEL__ +struct rsbac_group_handles_t { +#if defined(CONFIG_RSBAC_RC_UM_PROT) + rsbac_list_handle_t rc; +#endif +}; +#endif /* __KERNEL__ */ + +/********************************/ +/* NETDEV ACI */ + +#define RSBAC_GEN_ACI_NETDEV_NAME "nd_gen" +#define RSBAC_RC_ACI_NETDEV_NAME "nd_rc" + +#define RSBAC_GEN_NETDEV_ACI_VERSION 1 +#define RSBAC_GEN_NETDEV_ACI_KEY 1001 +struct rsbac_gen_netdev_aci_t { + rsbac_log_array_t log_array_low; /* netdev based logging, */ + rsbac_log_array_t log_array_high; /* high and low bits */ +}; +#define DEFAULT_GEN_NETDEV_ACI \ + { \ + .log_array_low = -1, \ + .log_array_high = -1, \ + } + +#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT) +#define RSBAC_RC_NETDEV_ACI_VERSION 1 +#define RSBAC_RC_NETDEV_ACI_KEY 1001 +#endif + +#define RSBAC_NETDEV_NR_ATTRIBUTES 3 +#define RSBAC_NETDEV_ATTR_LIST { \ + A_rc_type, \ + A_log_array_low, \ + A_log_array_high \ + } + +#ifdef __KERNEL__ +struct rsbac_netdev_handles_t { +#if defined(CONFIG_RSBAC_IND_NETDEV_LOG) + rsbac_list_handle_t gen; +#endif +#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT) + rsbac_list_handle_t rc; +#endif +}; +#endif /* __KERNEL__ */ + +/********************************/ +/* NETTEMP ACI */ + +#define RSBAC_GEN_ACI_NETTEMP_NAME "nt_gen" +#define RSBAC_MAC_ACI_NETTEMP_NAME "nt_mac" +#define RSBAC_RC_ACI_NETTEMP_NAME "nt_rc" + +#define RSBAC_MAC_ACI_LNETOBJ_NAME "lnetobj_mac" +#define RSBAC_RC_ACI_LNETOBJ_NAME "lnetobj_rc" +#define RSBAC_MAC_ACI_RNETOBJ_NAME "rnetobj_mac" +#define RSBAC_RC_ACI_RNETOBJ_NAME "rnetobj_rc" + +#define RSBAC_GEN_NETOBJ_ACI_VERSION 1 +#define RSBAC_GEN_NETOBJ_ACI_KEY 1001 +struct rsbac_gen_netobj_aci_t { + rsbac_log_array_t log_array_low; /* nettemp/netobj based logging, */ + rsbac_log_array_t log_array_high; /* high and low bits */ +}; +#define DEFAULT_GEN_NETOBJ_ACI \ + { \ + .log_array_low = -1, \ + .log_array_high = -1, \ + } + +#if defined(CONFIG_RSBAC_MAC) || defined(CONFIG_RSBAC_MAC_MAINT) +#define RSBAC_MAC_NETOBJ_ACI_VERSION 1 +#define RSBAC_MAC_NETOBJ_ACI_KEY 1001 +struct rsbac_mac_netobj_aci_t { + rsbac_security_level_t sec_level; /* enum old_rsbac_security_level_t / __u8 */ + rsbac_mac_category_vector_t mac_categories; /* MAC category set */ +}; +#define DEFAULT_MAC_NETOBJ_ACI \ + { \ + .sec_level = SL_unclassified, /* security_level (MAC) */ \ + .mac_categories = RSBAC_MAC_DEF_CAT_VECTOR, \ + } +#endif + +#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT) +#define RSBAC_RC_NETOBJ_ACI_VERSION 1 +#define RSBAC_RC_NETOBJ_ACI_KEY 1001 +#define RSBAC_RC_NETTEMP_ACI_VERSION 1 +#define RSBAC_RC_NETTEMP_ACI_KEY 1002 + +struct rsbac_rc_nettemp_aci_t { + rsbac_rc_type_id_t netobj_type; /* type inherited to netobj */ + rsbac_rc_type_id_t nettemp_type; /* type of this tenplate */ +}; +#define DEFAULT_RC_NETTEMP_ACI \ + { \ + .netobj_type = RSBAC_RC_GENERAL_TYPE, \ + .nettemp_type = RSBAC_RC_GENERAL_TYPE, \ + } +#endif + +#define RSBAC_NETTEMP_NR_ATTRIBUTES 6 +#define RSBAC_NETTEMP_ATTR_LIST { \ + A_security_level, \ + A_mac_categories, \ + A_rc_type, \ + A_rc_type_nt, \ + A_log_array_low, \ + A_log_array_high \ + } + +#define RSBAC_NETOBJ_NR_ATTRIBUTES 10 +#define RSBAC_NETOBJ_ATTR_LIST { \ + A_local_sec_level, \ + A_remote_sec_level, \ + A_local_mac_categories, \ + A_remote_mac_categories, \ + A_local_rc_type, \ + A_remote_rc_type, \ + A_local_log_array_low, \ + A_remote_log_array_low, \ + A_local_log_array_high, \ + A_remote_log_array_high \ + } + +#ifdef __KERNEL__ +struct rsbac_nettemp_handles_t { +#if defined(CONFIG_RSBAC_IND_NETOBJ_LOG) + rsbac_list_handle_t gen; +#endif +#if defined(CONFIG_RSBAC_MAC) || defined(CONFIG_RSBAC_MAC_MAINT) + rsbac_list_handle_t mac; +#endif +#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT) + rsbac_list_handle_t rc; +#endif +}; + +struct rsbac_lnetobj_handles_t { +#if defined(CONFIG_RSBAC_MAC) || defined(CONFIG_RSBAC_MAC_MAINT) + rsbac_list_handle_t mac; +#endif +#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT) + rsbac_list_handle_t rc; +#endif +}; +struct rsbac_rnetobj_handles_t { +#if defined(CONFIG_RSBAC_MAC) || defined(CONFIG_RSBAC_MAC_MAINT) + rsbac_list_handle_t mac; +#endif +#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT) + rsbac_list_handle_t rc; +#endif +}; +#endif /* __KERNEL__ */ + + +/**********************************************/ +/* Declarations */ +/**********************************************/ + +#ifdef __KERNEL__ +extern kdev_t rsbac_root_dev; + +int rsbac_read_open(char *, struct file **, /* file */ + kdev_t); + +int rsbac_write_open(char *, struct file **, /* file */ + kdev_t); + +void rsbac_read_close(struct file *); + +void rsbac_write_close(struct file *); + +extern struct semaphore rsbac_write_sem; + +#endif /* __KERNEL__ */ + +/**********************************************/ +/* External Declarations */ +/**********************************************/ + +#ifdef __KERNEL__ + +static inline struct dentry *lock_parent(struct dentry *dentry) +{ + struct dentry *dir = dget(dentry->d_parent); + + inode_lock(dir->d_inode); + return dir; +} + +static inline void unlock_dir(struct dentry *dir) +{ + inode_unlock(dir->d_inode); + dput(dir); +} + +static inline void double_lock(struct dentry *d1, struct dentry *d2) +{ + if (d1->d_inode != d2->d_inode) + inode_lock(d1->d_inode); + inode_lock(d2->d_inode); +} + +static inline void double_unlock(struct dentry *d1, struct dentry *d2) +{ + if (d1->d_inode != d2->d_inode) + inode_unlock(d2->d_inode); + inode_unlock(d1->d_inode); + dput(d1); + dput(d2); +} + +#ifdef CONFIG_RSBAC_DEBUG +static inline unsigned long rsbac_stack_free_space(void) +{ + unsigned long *n = (unsigned long *)(current + 1); + while (!*n) + n++; + return (unsigned long)n - (unsigned long)(current + 1); +} +#else +#define rsbac_stack_free_space() 0 +#endif + +#endif /* __KERNEL__ */ + +#endif diff --git a/include/rsbac/acl.h b/include/rsbac/acl.h new file mode 100644 index 000000000000..316399060cb5 --- /dev/null +++ b/include/rsbac/acl.h @@ -0,0 +1,266 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2013: Amon Ott */ +/* API: Data structures */ +/* and functions for Access */ +/* Control Information / ACL */ +/* Last modified: 14/Jan/2013 */ +/************************************ */ + +#ifndef __RSBAC_ACL_H +#define __RSBAC_ACL_H + +#include +#include + +/***************************************************/ +/* General Prototypes */ +/***************************************************/ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac_error.h. */ + +/****************************************************************************/ +/* Initialization, including ACI restoration for all mounted devices from */ +/* disk. After this call, all ACI is kept in memory for performance reasons,*/ +/* but user and file/dir object ACI are written to disk on every change. */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +extern int rsbac_init_acl(void); +#else +extern int rsbac_init_acl(void) __init; +#endif + +/* mounting and umounting */ +int rsbac_mount_acl(kdev_t kdev); +int rsbac_umount_acl(kdev_t kdev); + +/* Some information about the current status is also available */ +extern int rsbac_stats_acl(void); + +/* Status checking */ +extern int rsbac_check_acl(int correct); + +/************************************************* */ +/* Access functions */ +/************************************************* */ + +/* All these procedures handle the spinlocks to protect the targets during */ +/* access. */ + +/* rsbac_acl_set_acl_entry + * Set ACL entry for given target and subject to given rights. If entry does + * not exist, it is created, thus cutting the inheritance from default/parent. + */ + +int rsbac_acl_set_acl_entry(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t rights, + rsbac_time_t ttl); + +/* rsbac_acl_remove_acl_entry + * Remove ACL entry for given target and subject. This reactivates the + * inheritance from default/parent. + */ + +int rsbac_acl_remove_acl_entry(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id); + +/* rsbac_acl_remove_acl + * Remove ACL for given target. For cleanup on delete. + */ + +int rsbac_acl_remove_acl(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid); + +/* rsbac_acl_add_to_acl_entry + * Add given rights to ACL entry for given target and subject. If entry does + * not exist, behaviour is exactly like rsbac_acl_set_acl_entry. + */ + +int rsbac_acl_add_to_acl_entry(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t rights, + rsbac_time_t ttl); + +/* rsbac_acl_remove_from_acl_entry + * Remove given rights from ACL entry for given target and subject. If entry does + * not exist, nothing happens. + * This function does NOT remove the ACL entry, so removing all rights results in + * NO rights for this subject/target combination! + */ + +int rsbac_acl_remove_from_acl_entry(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t + subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t rights); + +/* rsbac_acl_set_mask + * Set inheritance mask for given target to given rights. If item does + * not exist, it is created. + */ + +int rsbac_acl_set_mask(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_acl_rights_vector_t mask); + +/* rsbac_acl_get_mask + * Get inheritance mask for given target to given rights. If item does + * not exist, default mask is returned. + */ + +int rsbac_acl_get_mask(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_acl_rights_vector_t * mask_p); + +/* rsbac_acl_get_rights + * Get effective rights from ACL entry for given target and subject. + * If entry does not exist, inherited rights are used. If there is no parent, + * the default rights vector for this target type is returned. + * This function does NOT add role or group rights to user rights! + */ + +int rsbac_acl_get_rights(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t * rights_p, + rsbac_boolean_t inherit); + +/* rsbac_acl_get_single_right + * Show, whether a right is set for given target and subject. + * If right is not set, it is checked at all parents, unless it has been + * masked out *or* it is SUPERVISOR, CONFIG_RSBAC_ACL_SUPER_FILTER is set + * and supervisor is masked out. + */ + +int rsbac_acl_get_single_right(enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + enum rsbac_adf_request_t right, + rsbac_boolean_t * result); + + +/************************************************************************** */ +/* The rsbac_acl_copy_fd_acl() function copies a file/dir ACL to another */ +/* file/dir ACL. The old ACL of fd2 is erased before copying. */ + +int rsbac_acl_copy_fd_acl(struct rsbac_fs_file_t file1, + struct rsbac_fs_file_t file2); + +/************************************************************************** */ +/* The rsbac_acl_copy_pp_acl() function copies a process acl to another */ + +int rsbac_acl_copy_pp_acl(rsbac_pid_t old_pid, rsbac_pid_t new_pid); + +/************************************************* + * rsbac_acl_get_tlist + * Get subjects from ACL entries for given target. + */ + +int rsbac_acl_get_tlist(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + struct rsbac_acl_entry_t **entry_pp, + rsbac_time_t ** ttl_pp); + +/************************************************* + * Group management + */ + +/* add a group with new id and fill this id into *group_id_p */ +int rsbac_acl_add_group(rsbac_list_ta_number_t ta_number, + rsbac_uid_t owner, + enum rsbac_acl_group_type_t type, + const char *name, rsbac_acl_group_id_t * group_id_p); + +int rsbac_acl_change_group(rsbac_list_ta_number_t ta_number, + rsbac_acl_group_id_t id, + rsbac_uid_t owner, + enum rsbac_acl_group_type_t type, const char *name); + +int rsbac_acl_remove_group(rsbac_list_ta_number_t ta_number, + rsbac_acl_group_id_t id); + +int rsbac_acl_get_group_entry(rsbac_list_ta_number_t ta_number, + rsbac_acl_group_id_t group, + struct rsbac_acl_group_entry_t *entry_p); + +int rsbac_acl_list_groups(rsbac_list_ta_number_t ta_number, + rsbac_uid_t owner, + rsbac_boolean_t include_global, + struct rsbac_acl_group_entry_t **entry_pp); + +/* check group existence */ +rsbac_boolean_t rsbac_acl_group_exist(rsbac_acl_group_id_t group); + +int rsbac_acl_add_group_member(rsbac_list_ta_number_t ta_number, + rsbac_acl_group_id_t group, + rsbac_uid_t user, rsbac_time_t ttl); + +int rsbac_acl_remove_group_member(rsbac_list_ta_number_t ta_number, + rsbac_acl_group_id_t group, + rsbac_uid_t user); + +/* check membership */ +rsbac_boolean_t rsbac_acl_group_member(rsbac_acl_group_id_t group, + rsbac_uid_t user); + +/* build rsbac_kmalloc'd array of all group memberships of the given user */ +/* returns number of groups or negative error */ +/* Attention: memory deallocation with rsbac_kfree must be done by caller! */ +int rsbac_acl_get_user_groups(rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + rsbac_acl_group_id_t ** group_pp, + rsbac_time_t ** ttl_pp); + +/* Returns number of members or negative error */ +int rsbac_acl_get_group_members(rsbac_list_ta_number_t ta_number, + rsbac_acl_group_id_t group, + rsbac_uid_t user_array[], + rsbac_time_t ttl_array[], int maxnum); + +/* Remove subject from all ACLs */ +int rsbac_acl_remove_subject(rsbac_list_ta_number_t ta_number, + struct rsbac_acl_entry_desc_t desc); + +/*************************************************/ +/* remove user from all groups and from all ACLs */ +int rsbac_acl_remove_user(rsbac_list_ta_number_t ta_number, + rsbac_uid_t user); + +/* Get list of all device entries */ + +int rsbac_acl_list_all_dev(rsbac_list_ta_number_t ta_number, + struct rsbac_dev_desc_t **id_pp); + +int rsbac_acl_list_all_major_dev(rsbac_list_ta_number_t ta_number, + struct rsbac_dev_desc_t **id_pp); + +int rsbac_acl_list_all_user(rsbac_list_ta_number_t ta_number, + rsbac_uid_t ** id_pp); + +int rsbac_acl_list_all_group(rsbac_list_ta_number_t ta_number, + rsbac_gid_t ** id_pp); + +int rsbac_acl_list_all_ipc(rsbac_list_ta_number_t ta_number, + struct rsbac_ipc_t ** id_pp); + +#endif diff --git a/include/rsbac/acl_data_structures.h b/include/rsbac/acl_data_structures.h new file mode 100644 index 000000000000..9766978842d1 --- /dev/null +++ b/include/rsbac/acl_data_structures.h @@ -0,0 +1,469 @@ +/**************************************/ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: */ +/* Amon Ott */ +/* Data structures / ACL */ +/* Last modified: 07/Jan/2016 */ +/**************************************/ + +#ifndef __RSBAC_ACL_DATA_STRUC_H +#define __RSBAC_ACL_DATA_STRUC_H + +#include +#include +#include +#include + +#define RSBAC_ACL_LIST_KEY 0x815affe + +#define RSBAC_ACL_GENERAL_FD_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + ( RSBAC_FD_REQUEST_VECTOR & RSBAC_READ_WRITE_REQUEST_VECTOR ) | RSBAC_EXECUTE_REQUEST_VECTOR | RSBAC_ACL_GEN_RIGHTS_VECTOR } + +#define RSBAC_ACL_ACMAN_FD_ENTRY \ + { ACLS_USER, \ + RSBAC_SECOFF_UID, \ + ( RSBAC_FD_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_EXECUTE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_ACMAN_RIGHTS_VECTOR } + +#define RSBAC_ACL_SYSADM_FD_ENTRY \ + { ACLS_USER, \ + RSBAC_SYSADM_UID, \ + ( RSBAC_FD_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_EXECUTE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_SYSADM_RIGHTS_VECTOR } + +#define RSBAC_ACL_GENERAL_DEV_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + ( RSBAC_DEV_REQUEST_VECTOR & RSBAC_READ_WRITE_REQUEST_VECTOR ) | RSBAC_ACL_GEN_RIGHTS_VECTOR } + +#define RSBAC_ACL_ACMAN_DEV_ENTRY \ + { ACLS_USER, \ + RSBAC_SECOFF_UID, \ + ( RSBAC_DEV_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_ACMAN_RIGHTS_VECTOR } + +#define RSBAC_ACL_SYSADM_DEV_ENTRY \ + { ACLS_USER, \ + RSBAC_SYSADM_UID, \ + ( RSBAC_DEV_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_SYSADM_RIGHTS_VECTOR } + +#define RSBAC_ACL_GENERAL_IPC_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + ( RSBAC_IPC_REQUEST_VECTOR & RSBAC_READ_WRITE_REQUEST_VECTOR ) | RSBAC_ACL_GEN_RIGHTS_VECTOR } + +#define RSBAC_ACL_ACMAN_IPC_ENTRY \ + { ACLS_USER, \ + RSBAC_SECOFF_UID, \ + ( RSBAC_IPC_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_ACMAN_RIGHTS_VECTOR } + +#define RSBAC_ACL_SYSADM_IPC_ENTRY \ + { ACLS_USER, \ + RSBAC_SYSADM_UID, \ + ( RSBAC_IPC_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_SYSADM_RIGHTS_VECTOR } + +#define RSBAC_ACL_GENERAL_SCD_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + ( RSBAC_SCD_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) ) \ + ) \ + | RSBAC_ACL_GEN_RIGHTS_VECTOR \ + } + +#ifdef CONFIG_RSBAC_USER_MOD_IOPERM +#define RSBAC_ACL_GENERAL_SCD_IOPORTS_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) \ + } +#endif + +#define RSBAC_ACL_GENERAL_SCD_OTHER_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + } + +#define RSBAC_ACL_GENERAL_SCD_NETWORK_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) \ + } + +#define RSBAC_ACL_ACMAN_SCD_ENTRY \ + { ACLS_USER, \ + RSBAC_SECOFF_UID, \ + ( RSBAC_SCD_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_ACMAN_RIGHTS_VECTOR } + +#define RSBAC_ACL_ACMAN_SCD_OTHER_ENTRY \ + { ACLS_USER, \ + RSBAC_SECOFF_UID, \ + ( RSBAC_NONE_REQUEST_VECTOR & \ + ( \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + | ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) \ + | ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) \ + | ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) \ + | ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) \ + | ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) \ + | ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) \ + ) \ + ) \ + | RSBAC_ACL_ACMAN_RIGHTS_VECTOR } + +#define RSBAC_ACL_SYSADM_SCD_ENTRY \ + { ACLS_USER, \ + RSBAC_SYSADM_UID, \ + ( RSBAC_SCD_REQUEST_VECTOR & \ + ( \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) \ + | ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) \ + | ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) \ + | ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) \ + | ((rsbac_request_vector_t) 1 << R_WRITE) \ + ) \ + ) \ + | RSBAC_ACL_SYSADM_RIGHTS_VECTOR } + +#define RSBAC_ACL_SYSADM_SCD_OTHER_ENTRY \ + { ACLS_USER, \ + RSBAC_SYSADM_UID, \ + ( RSBAC_NONE_REQUEST_VECTOR & \ + ( \ + ((rsbac_request_vector_t) 1 << R_ADD_TO_KERNEL) \ + | ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) \ + | ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) \ + | ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) \ + | ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + | ((rsbac_request_vector_t) 1 << R_MOUNT) \ + | ((rsbac_request_vector_t) 1 << R_REMOVE_FROM_KERNEL) \ + | ((rsbac_request_vector_t) 1 << R_UMOUNT) \ + | ((rsbac_request_vector_t) 1 << R_SHUTDOWN) \ + ) \ + ) \ + | ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) \ + | RSBAC_ACL_SYSADM_RIGHTS_VECTOR } + +#define RSBAC_ACL_AUDITOR_SCD_RSBACLOG_ENTRY \ + { ACLS_USER, \ + RSBAC_AUDITOR_UID, \ + ( RSBAC_SCD_REQUEST_VECTOR & \ + ( \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) \ + | ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) \ + ) \ + ) \ + } + +#ifdef CONFIG_RSBAC_USER_MOD_IOPERM +#define RSBAC_ACL_SYSADM_SCD_KMEM_ENTRY \ + { ACLS_USER, \ + RSBAC_SYSADM_UID, \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) \ + } +#endif + +#define RSBAC_ACL_GENERAL_U_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + RSBAC_REQUEST_VECTOR(R_CHANGE_OWNER) | RSBAC_REQUEST_VECTOR(R_SEARCH) \ + | RSBAC_REQUEST_VECTOR(R_GET_STATUS_DATA) } + +#define RSBAC_ACL_ACMAN_U_ENTRY \ + { ACLS_USER, \ + RSBAC_SECOFF_UID, \ + RSBAC_ACL_USER_RIGHTS_VECTOR \ + | RSBAC_ACL_ACMAN_RIGHTS_VECTOR } + +#define RSBAC_ACL_SYSADM_U_ENTRY \ + { ACLS_USER, \ + RSBAC_SYSADM_UID, \ + RSBAC_REQUEST_VECTOR(R_CHANGE_OWNER) | RSBAC_ACL_RIGHTS_VECTOR(R_READ_ATTRIBUTE) \ + | RSBAC_REQUEST_VECTOR(R_SEARCH) | RSBAC_REQUEST_VECTOR(R_GET_STATUS_DATA) \ + | RSBAC_REQUEST_VECTOR(R_AUTHENTICATE) \ + | RSBAC_ACL_SYSADM_RIGHTS_VECTOR } + +#define RSBAC_ACL_GENERAL_P_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + ( RSBAC_PROCESS_REQUEST_VECTOR & RSBAC_READ_WRITE_REQUEST_VECTOR ) | RSBAC_ACL_GEN_RIGHTS_VECTOR } + +#define RSBAC_ACL_ACMAN_P_ENTRY \ + { ACLS_USER, \ + RSBAC_SECOFF_UID, \ + ( RSBAC_PROCESS_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_ACMAN_RIGHTS_VECTOR } + +#define RSBAC_ACL_SYSADM_P_ENTRY \ + { ACLS_USER, \ + RSBAC_SYSADM_UID, \ + ( RSBAC_PROCESS_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_SYSADM_RIGHTS_VECTOR } + +#define RSBAC_ACL_GENERAL_G_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + RSBAC_REQUEST_VECTOR(R_SEARCH) | RSBAC_REQUEST_VECTOR(R_READ) } + +#define RSBAC_ACL_ACMAN_G_ENTRY \ + { ACLS_USER, \ + RSBAC_SECOFF_UID, \ + ( RSBAC_GROUP_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_ACMAN_RIGHTS_VECTOR } + +#define RSBAC_ACL_SYSADM_G_ENTRY \ + { ACLS_USER, \ + RSBAC_SYSADM_UID, \ + RSBAC_REQUEST_VECTOR(R_SEARCH) | RSBAC_REQUEST_VECTOR(R_READ) } + +#define RSBAC_ACL_GENERAL_NETDEV_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + ( RSBAC_NETDEV_REQUEST_VECTOR ) | RSBAC_ACL_GEN_RIGHTS_VECTOR } + +#define RSBAC_ACL_ACMAN_NETDEV_ENTRY \ + { ACLS_USER, \ + RSBAC_SECOFF_UID, \ + ( RSBAC_NETDEV_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_ACMAN_RIGHTS_VECTOR } + +#define RSBAC_ACL_SYSADM_NETDEV_ENTRY \ + { ACLS_USER, \ + RSBAC_SYSADM_UID, \ + ( RSBAC_NETDEV_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_SYSADM_RIGHTS_VECTOR } + +#define RSBAC_ACL_GENERAL_NETTEMP_NT_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + ( RSBAC_NETTEMP_REQUEST_VECTOR & RSBAC_READ_REQUEST_VECTOR ) | RSBAC_ACL_GEN_RIGHTS_VECTOR } + +#define RSBAC_ACL_ACMAN_NETTEMP_NT_ENTRY \ + { ACLS_USER, \ + RSBAC_SECOFF_UID, \ + ( RSBAC_NETTEMP_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_ACMAN_RIGHTS_VECTOR } + +#define RSBAC_ACL_SYSADM_NETTEMP_NT_ENTRY \ + { ACLS_USER, \ + RSBAC_SYSADM_UID, \ + ( RSBAC_NETTEMP_REQUEST_VECTOR & \ + ( RSBAC_READ_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR ) ) \ + | RSBAC_ACL_SYSADM_RIGHTS_VECTOR } + +#define RSBAC_ACL_GENERAL_NETOBJ_ENTRY \ + { ACLS_GROUP, \ + RSBAC_ACL_GROUP_EVERYONE, \ + ( RSBAC_NETOBJ_REQUEST_VECTOR & RSBAC_READ_WRITE_REQUEST_VECTOR ) \ + | RSBAC_REQUEST_VECTOR(R_MODIFY_SYSTEM_DATA) \ + | RSBAC_ACL_GEN_RIGHTS_VECTOR } + +#define RSBAC_ACL_ACMAN_NETOBJ_ENTRY \ + { ACLS_USER, \ + RSBAC_SECOFF_UID, \ + ( RSBAC_NETOBJ_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SECURITY_REQUEST_VECTOR ) ) \ + | RSBAC_REQUEST_VECTOR(R_MODIFY_SYSTEM_DATA) \ + | RSBAC_ACL_ACMAN_RIGHTS_VECTOR } + +#define RSBAC_ACL_SYSADM_NETOBJ_ENTRY \ + { ACLS_USER, \ + RSBAC_SYSADM_UID, \ + ( RSBAC_NETOBJ_REQUEST_VECTOR & \ + ( RSBAC_READ_WRITE_REQUEST_VECTOR | RSBAC_SYSTEM_REQUEST_VECTOR ) ) \ + | RSBAC_REQUEST_VECTOR(R_MODIFY_SYSTEM_DATA) \ + | RSBAC_ACL_SYSADM_RIGHTS_VECTOR } + + +/**********************************************/ +/* Lists of ACL / General subitems */ +/**********************************************/ + +/* Each list represents sets of ACL entries, using a set-id and a sublist each */ + +#define RSBAC_ACL_VERSION 1 + +/**********************************************/ +/* ACL and device entries for File/Dir ACL */ +/**********************************************/ + +#define RSBAC_ACL_FD_FILENAME "aclfd" +#define RSBAC_ACL_FD_OLD_FILENAME "aclfd." +#define RSBAC_ACL_DEF_FD_FILENAME "aclfd.df" +#define RSBAC_ACL_NR_FD_LIST_BITS 2 +#define RSBAC_ACL_FD_LIST_VERSION 3 +#define RSBAC_ACL_DEF_FD_LIST_VERSION 3 +#define RSBAC_ACL_FD_OLD_LIST_VERSION 2 +#define RSBAC_ACL_DEF_FD_OLD_LIST_VERSION 2 +#define RSBAC_ACL_FD_OLD_OLD_LIST_VERSION 1 +#define RSBAC_ACL_DEF_FD_OLD_OLD_LIST_VERSION 1 + +/* The list of devices is also a double linked list, so we define list */ +/* items and a list head. */ + +struct rsbac_acl_device_list_item_t { + kdev_t id; + u_int mount_count; + rsbac_list_handle_t handle; + struct rsbac_acl_device_list_item_t *prev; + struct rsbac_acl_device_list_item_t *next; +}; + +/* To provide consistency we use spinlocks for all list accesses. The */ +/* 'curr' entry is used to avoid repeated lookups for the same item. */ + +struct rsbac_acl_device_list_head_t { + struct rsbac_acl_device_list_item_t *head; + struct rsbac_acl_device_list_item_t *tail; + struct rsbac_acl_device_list_item_t *curr; + u_int count; +}; + + +/**********************************************/ +/* ACL entries for Device ACL */ +/**********************************************/ + +#define RSBAC_ACL_DEV_FILENAME "acldev" +#define RSBAC_ACL_DEV_MAJOR_FILENAME "acldevm" +#define RSBAC_ACL_DEV_LIST_VERSION 4 +#define RSBAC_ACL_DEV_OLD_LIST_VERSION 3 +#define RSBAC_ACL_DEV_OLD_OLD_LIST_VERSION 2 +#define RSBAC_ACL_DEV_OLD_OLD_OLD_LIST_VERSION 1 +#define RSBAC_ACL_DEF_DEV_FILENAME "acldev.df" +#define RSBAC_ACL_DEF_DEV_LIST_VERSION 3 +#define RSBAC_ACL_DEF_DEV_OLD_LIST_VERSION 2 +#define RSBAC_ACL_DEF_DEV_OLD_OLD_LIST_VERSION 1 + +/**********************************************/ +/* ACL entries for IPC ACL */ +/**********************************************/ + +#define RSBAC_ACL_DEF_IPC_FILENAME "aclipc.df" +#define RSBAC_ACL_DEF_IPC_LIST_VERSION 3 +#define RSBAC_ACL_DEF_IPC_OLD_LIST_VERSION 2 +#define RSBAC_ACL_DEF_IPC_OLD_OLD_LIST_VERSION 1 + +/**********************************************/ +/* ACL entries for SCD ACL */ +/**********************************************/ + +#define RSBAC_ACL_SCD_FILENAME "aclscd" +#define RSBAC_ACL_DEF_SCD_FILENAME "aclscd.df" +#define RSBAC_ACL_SCD_LIST_VERSION 3 +#define RSBAC_ACL_SCD_OLD_LIST_VERSION 2 +#define RSBAC_ACL_SCD_OLD_OLD_LIST_VERSION 1 +#define RSBAC_ACL_DEF_SCD_LIST_VERSION 3 +#define RSBAC_ACL_DEF_SCD_OLD_LIST_VERSION 2 +#define RSBAC_ACL_DEF_SCD_OLD_OLD_LIST_VERSION 1 + +/**********************************************/ +/* ACL entries for user ACL */ +/**********************************************/ + +#define RSBAC_ACL_U_FILENAME "acluser" +#define RSBAC_ACL_U_LIST_VERSION 2 +#define RSBAC_ACL_U_OLD_LIST_VERSION 1 +#define RSBAC_ACL_DEF_U_FILENAME "acluser.df" +#define RSBAC_ACL_DEF_U_LIST_VERSION 3 +#define RSBAC_ACL_DEF_U_OLD_LIST_VERSION 2 +#define RSBAC_ACL_DEF_U_OLD_OLD_LIST_VERSION 1 + +/**********************************************/ +/* ACL entries for process ACL */ +/**********************************************/ + +#define RSBAC_ACL_DEF_P_FILENAME "aclproc.df" +#define RSBAC_ACL_DEF_P_LIST_VERSION 3 +#define RSBAC_ACL_DEF_P_OLD_LIST_VERSION 2 +#define RSBAC_ACL_DEF_P_OLD_OLD_LIST_VERSION 1 + +/**********************************************/ +/* ACL entries for Linux group ACL */ +/**********************************************/ + +#define RSBAC_ACL_G_FILENAME "acllgrp" +#define RSBAC_ACL_G_LIST_VERSION 2 +#define RSBAC_ACL_G_OLD_LIST_VERSION 1 +#define RSBAC_ACL_DEF_G_FILENAME "acllgrp.df" +#define RSBAC_ACL_DEF_G_LIST_VERSION 3 +#define RSBAC_ACL_DEF_G_OLD_LIST_VERSION 2 +#define RSBAC_ACL_DEF_G_OLD_OLD_LIST_VERSION 1 + +/**********************************************/ +/* ACL entries for Network Device ACL */ +/**********************************************/ + +#define RSBAC_ACL_NETDEV_FILENAME "aclndev" +#define RSBAC_ACL_NETDEV_LIST_VERSION 3 +#define RSBAC_ACL_NETDEV_OLD_LIST_VERSION 2 +#define RSBAC_ACL_NETDEV_OLD_OLD_LIST_VERSION 1 +#define RSBAC_ACL_DEF_NETDEV_FILENAME "aclndev.df" +#define RSBAC_ACL_DEF_NETDEV_LIST_VERSION 3 +#define RSBAC_ACL_DEF_NETDEV_OLD_LIST_VERSION 2 +#define RSBAC_ACL_DEF_NETDEV_OLD_OLD_LIST_VERSION 1 + +/**********************************************/ +/* ACL entries for Network Template NT (template protection) ACL */ +/**********************************************/ + +#define RSBAC_ACL_NETTEMP_NT_FILENAME "aclntnt" +#define RSBAC_ACL_NETTEMP_NT_LIST_VERSION 3 +#define RSBAC_ACL_NETTEMP_NT_OLD_LIST_VERSION 2 +#define RSBAC_ACL_NETTEMP_NT_OLD_OLD_LIST_VERSION 1 +#define RSBAC_ACL_DEF_NETTEMP_NT_FILENAME "aclntnt.df" +#define RSBAC_ACL_DEF_NETTEMP_NT_LIST_VERSION 3 +#define RSBAC_ACL_DEF_NETTEMP_NT_OLD_LIST_VERSION 2 +#define RSBAC_ACL_DEF_NETTEMP_NT_OLD_OLD_LIST_VERSION 1 + +/**********************************************/ +/* ACL entries for Network Object ACL */ +/**********************************************/ + +#define RSBAC_ACL_NETTEMP_FILENAME "aclnt" +#define RSBAC_ACL_NETTEMP_LIST_VERSION 3 +#define RSBAC_ACL_NETTEMP_OLD_LIST_VERSION 2 +#define RSBAC_ACL_NETTEMP_OLD_OLD_LIST_VERSION 1 +#define RSBAC_ACL_NETOBJ_FILENAME "aclno" +#define RSBAC_ACL_NETOBJ_LIST_VERSION 3 +#define RSBAC_ACL_NETOBJ_OLD_LIST_VERSION 2 +#define RSBAC_ACL_NETOBJ_OLD_OLD_LIST_VERSION 1 +#define RSBAC_ACL_DEF_NETOBJ_FILENAME "aclno.df" +#define RSBAC_ACL_DEF_NETOBJ_LIST_VERSION 3 +#define RSBAC_ACL_DEF_NETOBJ_OLD_LIST_VERSION 2 +#define RSBAC_ACL_DEF_NETOBJ_OLD_OLD_LIST_VERSION 1 + + +/**********************************************/ +/* Group Lists */ +/**********************************************/ + +#define RSBAC_ACL_GROUP_FILENAME "aclgrp" +#define RSBAC_ACL_GM_FILENAME "aclgm" + +/* In acl_types.h: #define RSBAC_ACL_GROUP_VERSION 2 */ + +#define RSBAC_ACL_GM_VERSION 2 +#define RSBAC_ACL_GM_OLD_VERSION 1 + +#endif diff --git a/include/rsbac/acl_getname.h b/include/rsbac/acl_getname.h new file mode 100644 index 000000000000..638b43c139d0 --- /dev/null +++ b/include/rsbac/acl_getname.h @@ -0,0 +1,42 @@ +/********************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2001: */ +/* Amon Ott */ +/* Getname functions for ACL parts */ +/* Last modified: 02/Aug/2001 */ +/********************************* */ + +#ifndef __RSBAC_ACL_GETNAME_H +#define __RSBAC_ACL_GETNAME_H + +#include + +char * get_acl_subject_type_name(char * name, + enum rsbac_acl_subject_type_t value); + +#ifndef __KERNEL__ +enum rsbac_acl_subject_type_t get_acl_subject_type_nr(const char * name); +#endif + +char * get_acl_group_syscall_name(char * name, + enum rsbac_acl_group_syscall_type_t value); + +#ifndef __KERNEL__ +enum rsbac_acl_group_syscall_type_t get_acl_group_syscall_nr(const char * name); +#endif + +char * get_acl_special_right_name(char * name, + enum rsbac_acl_special_rights_t value); + +#ifndef __KERNEL__ +enum rsbac_acl_special_rights_t get_acl_special_right_nr(const char * name); +#endif + +char * get_acl_scd_type_name(char * name, + enum rsbac_acl_scd_type_t value); + +#ifndef __KERNEL__ +enum rsbac_acl_scd_type_t get_acl_scd_type_nr(const char * name); +#endif + +#endif diff --git a/include/rsbac/acl_types.h b/include/rsbac/acl_types.h new file mode 100644 index 000000000000..0906f59931e4 --- /dev/null +++ b/include/rsbac/acl_types.h @@ -0,0 +1,351 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: */ +/* Amon Ott */ +/* API: Data types for attributes */ +/* and standard module calls */ +/* Last modified: 17/Feb/2016 */ +/************************************ */ + +#ifndef __RSBAC_ACL_TYPES_H +#define __RSBAC_ACL_TYPES_H + +#include + +#define RSBAC_ACL_TTL_KEEP RSBAC_LIST_TTL_KEEP + +#define RSBAC_ACL_MAX_MAXNUM 1000000 + +enum rsbac_acl_subject_type_t {ACLS_USER, ACLS_ROLE, ACLS_GROUP, ACLS_NONE}; + +typedef __u8 rsbac_acl_int_subject_type_t; +typedef __u64 rsbac_acl_subject_id_t; +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +typedef __u64 __attribute__((aligned(4))) rsbac_acl_subject_id_ia32_t; +#endif +typedef __u32 rsbac_acl_old_subject_id_t; + +#define RSBAC_ACL_GROUP_EVERYONE 0 + +#define RSBAC_ACL_ROLE_EVERYROLE 64 + +#define RSBAC_ACL_OLD_SPECIAL_RIGHT_BASE 48 +#define RSBAC_ACL_SPECIAL_RIGHT_BASE 56 + +enum rsbac_acl_special_rights_t + { ACLR_FORWARD = RSBAC_ACL_SPECIAL_RIGHT_BASE, + ACLR_ACCESS_CONTROL, + ACLR_SUPERVISOR, + ACLR_NONE}; + +typedef __u64 rsbac_acl_rights_vector_t; +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +typedef __u64 __attribute__((aligned(4))) rsbac_acl_rights_vector_ia32_t; +#endif + +#define RSBAC_ACL_RIGHTS_VECTOR(x) ((rsbac_acl_rights_vector_t) 1 << (x)) + +#define RSBAC_ACL_SPECIAL_RIGHTS_VECTOR (\ + ((rsbac_acl_rights_vector_t) 1 << ACLR_FORWARD) | \ + ((rsbac_acl_rights_vector_t) 1 << ACLR_ACCESS_CONTROL) | \ + ((rsbac_acl_rights_vector_t) 1 << ACLR_SUPERVISOR) \ + ) + +#define RSBAC_ACL_SUPERVISOR_RIGHT_VECTOR (\ + ((rsbac_acl_rights_vector_t) 1 << ACLR_SUPERVISOR) \ + ) +#define RSBAC_NWS_REQUEST_VECTOR RSBAC_ACL_SUPERVISOR_RIGHT_VECTOR + +#define RSBAC_ACL_ACCESS_CONTROL_RIGHT_VECTOR (\ + ((rsbac_acl_rights_vector_t) 1 << ACLR_ACCESS_CONTROL) \ + ) +#define RSBAC_NWA_REQUEST_VECTOR RSBAC_ACL_ACCESS_CONTROL_RIGHT_VECTOR + +#define RSBAC_ACL_ALL_RIGHTS_VECTOR (RSBAC_ALL_REQUEST_VECTOR | RSBAC_ACL_SPECIAL_RIGHTS_VECTOR) + +#define RSBAC_ACL_DEFAULT_FD_MASK (RSBAC_FD_REQUEST_VECTOR | RSBAC_ACL_SPECIAL_RIGHTS_VECTOR) +#define RSBAC_ACL_DEFAULT_DEV_MASK (RSBAC_DEV_REQUEST_VECTOR | RSBAC_ACL_SPECIAL_RIGHTS_VECTOR) +#define RSBAC_ACL_DEFAULT_SCD_MASK (RSBAC_SCD_REQUEST_VECTOR | RSBAC_ACL_SPECIAL_RIGHTS_VECTOR) +#define RSBAC_ACL_DEFAULT_U_MASK (RSBAC_USER_REQUEST_VECTOR | RSBAC_ACL_SPECIAL_RIGHTS_VECTOR) +#define RSBAC_ACL_DEFAULT_G_MASK (RSBAC_GROUP_REQUEST_VECTOR | RSBAC_ACL_SPECIAL_RIGHTS_VECTOR) +#define RSBAC_ACL_DEFAULT_NETDEV_MASK (RSBAC_NETDEV_REQUEST_VECTOR | RSBAC_ACL_SPECIAL_RIGHTS_VECTOR) +#define RSBAC_ACL_DEFAULT_NETTEMP_MASK (RSBAC_NETTEMP_REQUEST_VECTOR | RSBAC_ACL_SPECIAL_RIGHTS_VECTOR) +#define RSBAC_ACL_DEFAULT_NETOBJ_MASK (RSBAC_NETOBJ_REQUEST_VECTOR | RSBAC_ACL_SPECIAL_RIGHTS_VECTOR) + +#define RSBAC_ACL_USER_RIGHTS_VECTOR (RSBAC_USER_REQUEST_VECTOR \ + | RSBAC_ACL_RIGHTS_VECTOR(R_DELETE)) + +#define RSBAC_ACL_GROUP_RIGHTS_VECTOR RSBAC_GROUP_REQUEST_VECTOR + +#define RSBAC_ACL_GEN_RIGHTS_VECTOR 0 + +#define RSBAC_ACL_ACMAN_RIGHTS_VECTOR (\ + ((rsbac_acl_rights_vector_t) 1 << ACLR_FORWARD) | \ + ((rsbac_acl_rights_vector_t) 1 << ACLR_ACCESS_CONTROL) | \ + ((rsbac_acl_rights_vector_t) 1 << ACLR_SUPERVISOR) \ + ) + +#define RSBAC_ACL_SYSADM_RIGHTS_VECTOR 0 + +/* + * System Control Types, including general SCD types + * (start at 32 to allow future SCD types, max is 63) + * (should always be same as in RC model) + */ +#define AST_min 32 +enum rsbac_acl_scd_type_t{AST_auth_administration = AST_min, + AST_udf_administration, + AST_none}; + +/* note: the desc struct must be the same as the beginning of the entry struct! */ +struct rsbac_acl_entry_t + { + rsbac_acl_int_subject_type_t subj_type; /* enum rsbac_acl_subject_type_t */ + rsbac_acl_subject_id_t subj_id; + rsbac_acl_rights_vector_t rights; + }; + +struct rsbac_acl_entry_desc_t + { + rsbac_acl_int_subject_type_t subj_type; /* enum rsbac_acl_subject_type_t */ + rsbac_acl_subject_id_t subj_id; + }; + +struct rsbac_acl_old_entry_desc_t + { + rsbac_acl_int_subject_type_t subj_type; /* enum rsbac_acl_subject_type_t */ + rsbac_acl_old_subject_id_t subj_id; + }; + +enum rsbac_acl_group_type_t {ACLG_GLOBAL, ACLG_PRIVATE, ACLG_NONE}; + +typedef __u32 rsbac_acl_group_id_t; + +#define RSBAC_ACL_GROUP_NAMELEN 16 + +#define RSBAC_ACL_GROUP_VERSION 2 + +struct rsbac_acl_group_entry_t + { + rsbac_acl_group_id_t id; + rsbac_uid_t owner; + enum rsbac_acl_group_type_t type; + char name[RSBAC_ACL_GROUP_NAMELEN]; + }; + +/**** syscalls ****/ + +enum rsbac_acl_syscall_type_t + { + ACLC_set_acl_entry, + ACLC_remove_acl_entry, + ACLC_remove_acl, + ACLC_add_to_acl_entry, + ACLC_remove_from_acl_entry, + ACLC_set_mask, + ACLC_remove_user, + ACLC_none + }; + +struct rsbac_acl_syscall_arg_t + { + enum rsbac_target_t target; + union rsbac_target_id_t tid; + enum rsbac_acl_subject_type_t subj_type; + rsbac_acl_subject_id_t subj_id; + rsbac_acl_rights_vector_t rights; + rsbac_time_t ttl; + }; + +struct rsbac_acl_syscall_n_arg_t + { + enum rsbac_target_t target; + char __user * name; + enum rsbac_acl_subject_type_t subj_type; + rsbac_acl_subject_id_t subj_id; + rsbac_acl_rights_vector_t rights; + rsbac_time_t ttl; + }; + + +enum rsbac_acl_group_syscall_type_t + { + ACLGS_add_group, + ACLGS_change_group, + ACLGS_remove_group, + ACLGS_get_group_entry, + ACLGS_list_groups, + ACLGS_add_member, + ACLGS_remove_member, + ACLGS_get_user_groups, + ACLGS_get_group_members, + ACLGS_none + }; + +struct rsbac_acl_add_group_arg_t + { + enum rsbac_acl_group_type_t type; + char __user * name; + rsbac_acl_group_id_t * group_id_p; + }; + +struct rsbac_acl_change_group_arg_t + { + rsbac_acl_group_id_t id; + rsbac_uid_t owner; + enum rsbac_acl_group_type_t type; + char __user * name; + }; + +struct rsbac_acl_remove_group_arg_t + { + rsbac_acl_group_id_t id; + }; + +struct rsbac_acl_get_group_entry_arg_t + { + rsbac_acl_group_id_t id; + struct rsbac_acl_group_entry_t __user * entry_p; + }; + +struct rsbac_acl_list_groups_arg_t + { + rsbac_boolean_t include_global; + struct rsbac_acl_group_entry_t __user * group_entry_array; + u_int maxnum; + }; + +struct rsbac_acl_add_member_arg_t + { + rsbac_acl_group_id_t group; + rsbac_uid_t user; + rsbac_time_t ttl; + }; + +struct rsbac_acl_remove_member_arg_t + { + rsbac_acl_group_id_t group; + rsbac_uid_t user; + }; + +struct rsbac_acl_get_user_groups_arg_t + { + rsbac_uid_t user; + rsbac_acl_group_id_t __user * group_array; + rsbac_time_t __user * ttl_array; + u_int maxnum; + }; + +struct rsbac_acl_get_group_members_arg_t + { + rsbac_acl_group_id_t group; + rsbac_uid_t __user * user_array; + rsbac_time_t __user * ttl_array; + u_int maxnum; + }; + +union rsbac_acl_group_syscall_arg_t + { + struct rsbac_acl_add_group_arg_t add_group; + struct rsbac_acl_change_group_arg_t change_group; + struct rsbac_acl_remove_group_arg_t remove_group; + struct rsbac_acl_get_group_entry_arg_t get_group_entry; + struct rsbac_acl_list_groups_arg_t list_groups; + struct rsbac_acl_add_member_arg_t add_member; + struct rsbac_acl_remove_member_arg_t remove_member; + struct rsbac_acl_get_user_groups_arg_t get_user_groups; + struct rsbac_acl_get_group_members_arg_t get_group_members; + }; + +/* + * 32 Bit emulation support on x86_64 system + */ + +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +struct rsbac_acl_syscall_n_arg_ia32_t + { + enum rsbac_target_t target; + __u32 name; + enum rsbac_acl_subject_type_t subj_type; + rsbac_acl_subject_id_ia32_t subj_id; + rsbac_acl_rights_vector_ia32_t rights; + rsbac_time_t ttl; + } __attribute__ ((aligned (4))); + +struct rsbac_acl_add_group_arg_ia32_t + { + enum rsbac_acl_group_type_t type; + __u32 name; + __u32 group_id_p; + } __attribute__ ((aligned (4))); + +struct rsbac_acl_change_group_arg_ia32_t + { + rsbac_acl_group_id_t id; + rsbac_uid_ia32_t owner; + enum rsbac_acl_group_type_t type; + __u32 name; + } __attribute__ ((aligned (4))); + +struct rsbac_acl_remove_group_arg_ia32_t + { + rsbac_acl_group_id_t id; + } __attribute__ ((aligned (4))); + +struct rsbac_acl_get_group_entry_arg_ia32_t + { + rsbac_acl_group_id_t id; + __u32 entry_p; + } __attribute__ ((aligned (4))); + +struct rsbac_acl_list_groups_arg_ia32_t + { + rsbac_boolean_t include_global; + __u32 group_entry_array; + __u32 maxnum; + } __attribute__ ((aligned (4))); + +struct rsbac_acl_add_member_arg_ia32_t + { + rsbac_acl_group_id_t group; + rsbac_uid_ia32_t user; + rsbac_time_t ttl; + } __attribute__ ((aligned (4))); + +struct rsbac_acl_remove_member_arg_ia32_t + { + rsbac_acl_group_id_t group; + rsbac_uid_ia32_t user; + } __attribute__ ((aligned (4))); + +struct rsbac_acl_get_user_groups_arg_ia32_t + { + rsbac_uid_ia32_t user; + __u32 group_array; + __u32 ttl_array; + __u32 maxnum; + } __attribute__ ((aligned (4))); + +struct rsbac_acl_get_group_members_arg_ia32_t + { + rsbac_acl_group_id_t group; + rsbac_uid_ia32_t __user * user_array; + rsbac_time_t __user * ttl_array; + __u32 maxnum; + } __attribute__ ((aligned (4))); + +union rsbac_acl_group_syscall_arg_ia32_t + { + struct rsbac_acl_add_group_arg_ia32_t add_group; + struct rsbac_acl_change_group_arg_ia32_t change_group; + struct rsbac_acl_remove_group_arg_ia32_t remove_group; + struct rsbac_acl_get_group_entry_arg_ia32_t get_group_entry; + struct rsbac_acl_list_groups_arg_ia32_t list_groups; + struct rsbac_acl_add_member_arg_ia32_t add_member; + struct rsbac_acl_remove_member_arg_ia32_t remove_member; + struct rsbac_acl_get_user_groups_arg_ia32_t get_user_groups; + struct rsbac_acl_get_group_members_arg_ia32_t get_group_members; + } __attribute__ ((aligned (4))); +#endif + +#endif diff --git a/include/rsbac/adf.h b/include/rsbac/adf.h new file mode 100644 index 000000000000..12c8e61e3889 --- /dev/null +++ b/include/rsbac/adf.h @@ -0,0 +1,139 @@ +/******************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2017: */ +/* Amon Ott */ +/* API: for Access Control */ +/* Decision Facility */ +/* Last modified: 11/Jul/2017 */ +/******************************* */ + +#ifndef __RSBAC_ADF_H +#define __RSBAC_ADF_H + +#include +#include +#include +#include +#include +#include + +/***************************************************/ +/* Prototypes */ +/***************************************************/ + +/* Init function */ +#ifdef CONFIG_RSBAC_INIT_DELAY +extern void rsbac_init_adf(void); +#else +extern void rsbac_init_adf(void) __init; +#endif + +/* This function is the internal decision function, called from the next. */ +/* It allows to ignore a certain module (last parameter), e.g. for asking */ +/* all _other_ modules, but not the calling module, to avoid a circle. */ + +extern enum rsbac_adf_req_ret_t + rsbac_adf_request_int(enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t * tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t * attr_val_p, + enum rsbac_switch_target_t ignore_module); + +/*********************************************************************/ +/* rsbac_adf_request() */ +/* This function is the main decision function, called from the AEF. */ +/* It is a simple wrapper to the internal function, setting */ +/* ignore_module to SW_NONE. */ + +static inline enum rsbac_adf_req_ret_t + rsbac_adf_request( enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val) + { + return rsbac_adf_request_int(request, + caller_pid, + target, + &tid, + attr, + &attr_val, + SW_NONE); + } + + +/* If the request returned granted and the operation is performed, */ +/* the following function is called by the AEF to get all aci set correctly. */ +/* The second instance of target specification is the new target, if one has */ +/* been created, otherwise its values are ignored. */ +/* It returns 0 on success and an error from error.h otherwise. */ + +extern int rsbac_adf_set_attr( enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t); + +#include +#include + +int rsbac_sec_del(struct dentry * dentry_p, u_int may_sync); + +int rsbac_sec_trunc(struct dentry * dentry_p, + loff_t new_len, loff_t old_len); + +/* This function changes the symlink content by adding a suffix, if + * requested. It returns NULL, if unchanged, or a pointer to a + * kmalloc'd new char * otherwise, which has to be kfree'd after use. + */ +char * rsbac_symlink_redirect( + struct inode * inode_p, + const char * name, + u_int maxlen, + rsbac_boolean_t may_sleep); + +#ifdef CONFIG_RSBAC_FAKE_ROOT_UID +extern rsbac_uid_t rsbac_fake_uid(void); +extern rsbac_uid_t rsbac_fake_euid(void); +extern int rsbac_uid_faked(void); +#endif + +int rsbac_cap_check_envp(struct linux_binprm *bprm); + +extern int rsbac_handle_filldir(const struct file *file, const char *name, const unsigned int namlen, const ino_t ino); + +int rsbac_set_audit_uid(rsbac_uid_t uid); + +#ifdef CONFIG_RSBAC_MPROTECT +extern int rsbac_write_exec_allowed(struct vm_area_struct *vma, unsigned int prot); +#endif + +/* Mostly copied from drivers/char/mem.c */ +static inline rsbac_boolean_t rsbac_is_videomem(unsigned long pfn, unsigned long size) +{ +/* Intel architecture is a security disaster */ +#if defined X86_64 || defined X86 + + u64 from = ((u64)pfn) << PAGE_SHIFT; + u64 to = from + size; + u64 cursor = from; + + while (cursor < to) { + if (!devmem_is_allowed(pfn)) { + return FALSE; + } + cursor += PAGE_SIZE; + pfn++; + } + return TRUE; +#endif + return TRUE; +}; + +#endif diff --git a/include/rsbac/adf_main.h b/include/rsbac/adf_main.h new file mode 100644 index 000000000000..6eb5cdbf4ab8 --- /dev/null +++ b/include/rsbac/adf_main.h @@ -0,0 +1,804 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2013: */ +/* Amon Ott */ +/* Data Structs etc. for Access */ +/* Control Decision Facility */ +/* Last modified: 28/Nov/2013 */ +/************************************ */ + +#ifndef __RSBAC_ADF_MAIN_H +#define __RSBAC_ADF_MAIN_H + +#include +#include + +#if defined(CONFIG_RSBAC_REG) +#include +#endif + +#ifdef CONFIG_RSBAC_SECDEL +#include +#endif + +/***************************************************/ +/* Global Variables */ +/***************************************************/ + +extern __u64 rsbac_adf_request_count[T_NONE+1]; +extern __u64 rsbac_adf_set_attr_count[T_NONE+1]; +#ifdef CONFIG_RSBAC_XSTATS +extern __u64 rsbac_adf_request_xcount[T_NONE+1][R_NONE]; +extern __u64 rsbac_adf_set_attr_xcount[T_NONE+1][R_NONE]; +#endif + +/* Bitmasks to ignore some requests on some modules */ + +#ifdef CONFIG_RSBAC_MAC +#define RSBAC_MAC_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_ADD_TO_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_ALTER) | \ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHDIR) | \ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_LINK_HARD) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ACCESS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MOUNT) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_REMOVE_FROM_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_RENAME) | \ + ((rsbac_request_vector_t) 1 << R_SEARCH) | \ + ((rsbac_request_vector_t) 1 << R_SEND_SIGNAL) | \ + ((rsbac_request_vector_t) 1 << R_SHUTDOWN) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) | \ + ((rsbac_request_vector_t) 1 << R_TRACE) | \ + ((rsbac_request_vector_t) 1 << R_TRUNCATE) | \ + ((rsbac_request_vector_t) 1 << R_UMOUNT) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) | \ + ((rsbac_request_vector_t) 1 << R_BIND) | \ + ((rsbac_request_vector_t) 1 << R_LISTEN) | \ + ((rsbac_request_vector_t) 1 << R_ACCEPT) | \ + ((rsbac_request_vector_t) 1 << R_CONNECT) | \ + ((rsbac_request_vector_t) 1 << R_SEND) | \ + ((rsbac_request_vector_t) 1 << R_RECEIVE) \ + ) +#define RSBAC_MAC_SET_ATTR_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CLONE) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_MOUNT) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_SEARCH) | \ + ((rsbac_request_vector_t) 1 << R_TRACE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_BIND) | \ + ((rsbac_request_vector_t) 1 << R_LISTEN) | \ + ((rsbac_request_vector_t) 1 << R_ACCEPT) | \ + ((rsbac_request_vector_t) 1 << R_CONNECT) | \ + ((rsbac_request_vector_t) 1 << R_SEND) | \ + ((rsbac_request_vector_t) 1 << R_RECEIVE) \ + ) +#endif + +#ifdef CONFIG_RSBAC_DAZ +#define RSBAC_DAZ_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) \ + ) +#define RSBAC_DAZ_SET_ATTR_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CLONE) | \ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) ) +#endif + +#ifdef CONFIG_RSBAC_FF +#if defined(CONFIG_RSBAC_FF_UM_PROT) +#define RSBAC_FF_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHDIR) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_LINK_HARD) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ACCESS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MOUNT) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_RENAME) | \ + ((rsbac_request_vector_t) 1 << R_SEARCH) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) | \ + ((rsbac_request_vector_t) 1 << R_TRUNCATE) | \ + ((rsbac_request_vector_t) 1 << R_UMOUNT) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + ) +#else +#define RSBAC_FF_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHDIR) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_LINK_HARD) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ACCESS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MOUNT) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_RENAME) | \ + ((rsbac_request_vector_t) 1 << R_SEARCH) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) | \ + ((rsbac_request_vector_t) 1 << R_TRUNCATE) | \ + ((rsbac_request_vector_t) 1 << R_UMOUNT) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + ) +#endif +#endif + +#ifdef CONFIG_RSBAC_AUTH +#if defined(CONFIG_RSBAC_AUTH_UM_PROT) +#define RSBAC_AUTH_REQUEST_VECTOR_UM (\ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_RENAME) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) ) +#else +#define RSBAC_AUTH_REQUEST_VECTOR_UM 0 +#endif +#if defined(CONFIG_RSBAC_AUTH_UM_PROT) || defined(CONFIG_RSBAC_AUTH_GROUP) +#define RSBAC_AUTH_REQUEST_VECTOR_CG ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) +#else +#define RSBAC_AUTH_REQUEST_VECTOR_CG 0 +#endif +#if defined(CONFIG_RSBAC_AUTH_GROUP) && defined (CONFIG_RSBAC_AUTH_DAC_GROUP) +#define RSBAC_AUTH_REQUEST_VECTOR_DG ( \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_GROUP) ) +#else +#define RSBAC_AUTH_REQUEST_VECTOR_DG 0 +#endif +#if defined (CONFIG_RSBAC_AUTH_DAC_OWNER) +#define RSBAC_AUTH_REQUEST_VECTOR_DO ( \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_OWNER) ) +#else +#define RSBAC_AUTH_REQUEST_VECTOR_DO 0 +#endif +#if defined (CONFIG_RSBAC_AUTH_AUTH_PROT) +#define RSBAC_AUTH_REQUEST_VECTOR_AA ( \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) ) +#else +#define RSBAC_AUTH_REQUEST_VECTOR_AA 0 +#endif + +#define RSBAC_AUTH_REQUEST_VECTOR (\ + RSBAC_AUTH_REQUEST_VECTOR_UM | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + RSBAC_AUTH_REQUEST_VECTOR_CG | \ + RSBAC_AUTH_REQUEST_VECTOR_DG | \ + RSBAC_AUTH_REQUEST_VECTOR_DO | \ + RSBAC_AUTH_REQUEST_VECTOR_AA | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) \ + ) + +#if defined (CONFIG_RSBAC_AUTH_AUTH_PROT) +#define RSBAC_AUTH_SET_ATTR_VECTOR_AA ( \ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_LINK_HARD) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ACCESS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_RENAME) | \ + ((rsbac_request_vector_t) 1 << R_TRUNCATE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) ) +#else +#define RSBAC_AUTH_SET_ATTR_VECTOR_AA 0 +#endif +#define RSBAC_AUTH_SET_ATTR_VECTOR (\ + RSBAC_AUTH_SET_ATTR_VECTOR_AA | \ + ((rsbac_request_vector_t) 1 << R_CLONE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) \ + ) +#endif + +#ifdef CONFIG_RSBAC_CAP +#ifdef CONFIG_RSBAC_CAP_PROC_HIDE +#define RSBAC_CAP_REQUEST_VECTOR ( \ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_SEND_SIGNAL) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) | \ + ((rsbac_request_vector_t) 1 << R_TRACE) ) +#else +#define RSBAC_CAP_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) ) +#endif +#if defined (CONFIG_RSBAC_CAP_PROC_HIDE) || defined(CONFIG_RSBAC_CAP_LOG_MISSING) +#define RSBAC_CAP_SET_ATTR_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CLONE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) ) +#else +#define RSBAC_CAP_SET_ATTR_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) ) +#endif +#endif + +#ifdef CONFIG_RSBAC_JAIL +#define RSBAC_JAIL_REQUEST_VECTOR ( \ + ((rsbac_request_vector_t) 1 << R_ADD_TO_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_ALTER) | \ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MOUNT) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_REMOVE_FROM_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_SEND_SIGNAL) | \ + ((rsbac_request_vector_t) 1 << R_SHUTDOWN) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) | \ + ((rsbac_request_vector_t) 1 << R_TRACE) | \ + ((rsbac_request_vector_t) 1 << R_UMOUNT) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_BIND) | \ + ((rsbac_request_vector_t) 1 << R_LISTEN) | \ + ((rsbac_request_vector_t) 1 << R_ACCEPT) | \ + ((rsbac_request_vector_t) 1 << R_CONNECT) | \ + ((rsbac_request_vector_t) 1 << R_SEND) | \ + ((rsbac_request_vector_t) 1 << R_RECEIVE) | \ + ((rsbac_request_vector_t) 1 << R_NET_SHUTDOWN) ) +#define RSBAC_JAIL_SET_ATTR_VECTOR ( \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CLONE) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_CONNECT) | \ + ((rsbac_request_vector_t) 1 << R_BIND) ) +#endif + +#ifdef CONFIG_RSBAC_PAX +#define RSBAC_PAX_REQUEST_VECTOR ( \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) ) +#endif + +#ifdef CONFIG_RSBAC_RES +#define RSBAC_RES_REQUEST_VECTOR ( \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) ) +#define RSBAC_RES_SET_ATTR_VECTOR ( \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) ) +#endif + +#ifdef CONFIG_RSBAC_UDF +#define RSBAC_UDF_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) \ + ) +#define RSBAC_UDF_SET_ATTR_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CLONE) | \ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) ) +#endif + +/***************************************************/ +/* General Prototypes */ +/***************************************************/ + +/* We call this function in kernel/sched.c */ +extern struct task_struct * find_process_by_pid(pid_t); + +#ifdef CONFIG_RSBAC_DEBUG +extern enum rsbac_adf_req_ret_t + rsbac_adf_request_check (enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t * tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t * attr_val_p, + rsbac_uid_t owner); + +extern int rsbac_adf_set_attr_check( enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ +#endif + +extern enum rsbac_adf_req_ret_t + adf_and_plus(enum rsbac_adf_req_ret_t res1, + enum rsbac_adf_req_ret_t res2); + +/***************************************************/ +/* Module Prototypes */ +/***************************************************/ + +/******* MAC ********/ + +#ifdef CONFIG_RSBAC_MAC +#ifdef CONFIG_RSBAC_SWITCH_MAC +extern rsbac_boolean_t rsbac_switch_mac; +#endif + +extern enum rsbac_adf_req_ret_t rsbac_adf_request_mac( + enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +extern int rsbac_adf_set_attr_mac( enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +#endif /* MAC */ + +/******* DAZ ********/ + +#ifdef CONFIG_RSBAC_DAZ +#ifdef CONFIG_RSBAC_SWITCH_DAZ +extern rsbac_boolean_t rsbac_switch_daz; +#endif + +extern enum rsbac_adf_req_ret_t rsbac_adf_request_daz( + enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +extern int rsbac_adf_set_attr_daz (enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +#endif /* DAZ */ + +/******* FF ********/ + +#ifdef CONFIG_RSBAC_FF +#ifdef CONFIG_RSBAC_SWITCH_FF +extern rsbac_boolean_t rsbac_switch_ff; +#endif + +extern enum rsbac_adf_req_ret_t rsbac_adf_request_ff( + enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +extern int rsbac_adf_set_attr_ff ( enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +#ifdef CONFIG_RSBAC_SECDEL +extern rsbac_boolean_t rsbac_need_overwrite_ff(struct dentry * dentry_p); +#endif + +#endif /* FF */ + +/******* RC ********/ + +#ifdef CONFIG_RSBAC_RC +#ifdef CONFIG_RSBAC_SWITCH_RC +extern rsbac_boolean_t rsbac_switch_rc; +#endif + +extern enum rsbac_adf_req_ret_t rsbac_adf_request_rc( + enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +extern int rsbac_adf_set_attr_rc ( enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +/* Secure delete/truncate for this module */ +#ifdef CONFIG_RSBAC_SECDEL +extern rsbac_boolean_t rsbac_need_overwrite_rc(struct dentry * dentry_p); +#endif +#endif /* RC */ + +/****** AUTH *******/ + +#ifdef CONFIG_RSBAC_AUTH +#ifdef CONFIG_RSBAC_SWITCH_AUTH +extern rsbac_boolean_t rsbac_switch_auth; +#endif + +extern enum rsbac_adf_req_ret_t rsbac_adf_request_auth( + enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +extern int rsbac_adf_set_attr_auth(enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +#endif /* AUTH */ + +/****** ACL *******/ + +#ifdef CONFIG_RSBAC_ACL +#ifdef CONFIG_RSBAC_SWITCH_ACL +extern rsbac_boolean_t rsbac_switch_acl; +#endif + +extern enum rsbac_adf_req_ret_t rsbac_adf_request_acl( + enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +extern int rsbac_adf_set_attr_acl (enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +#endif /* ACL */ + +/****** CAP *******/ + +#ifdef CONFIG_RSBAC_CAP +#ifdef CONFIG_RSBAC_SWITCH_CAP +extern rsbac_boolean_t rsbac_switch_cap; +#endif + +extern enum rsbac_adf_req_ret_t rsbac_adf_request_cap( + enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +extern int rsbac_adf_set_attr_cap (enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +#endif /* CAP */ + +/****** JAIL *******/ + +#ifdef CONFIG_RSBAC_JAIL +#ifdef CONFIG_RSBAC_SWITCH_JAIL +extern rsbac_boolean_t rsbac_switch_jail; +#endif + +extern enum rsbac_adf_req_ret_t rsbac_adf_request_jail( + enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +extern int rsbac_adf_set_attr_jail(enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +#endif /* JAIL */ + +/******* PAX ********/ + +#ifdef CONFIG_RSBAC_PAX +#ifdef CONFIG_RSBAC_SWITCH_PAX +extern rsbac_boolean_t rsbac_switch_pax; +#endif + +extern enum rsbac_adf_req_ret_t rsbac_adf_request_pax( + enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +extern int rsbac_adf_set_attr_pax( enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +#endif /* PAX */ + + +/****** RES *******/ + +#ifdef CONFIG_RSBAC_RES +#ifdef CONFIG_RSBAC_SWITCH_RES +extern rsbac_boolean_t rsbac_switch_res; +#endif + +extern enum rsbac_adf_req_ret_t rsbac_adf_request_res( + enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +extern int rsbac_adf_set_attr_res (enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +#ifdef CONFIG_RSBAC_SECDEL +extern inline rsbac_boolean_t rsbac_need_overwrite_res(struct dentry * dentry_p) + { + return FALSE; + } +#endif +#endif /* RES */ + +/******* UDF ********/ + +#ifdef CONFIG_RSBAC_UDF +#ifdef CONFIG_RSBAC_SWITCH_UDF +extern rsbac_boolean_t rsbac_switch_udf; +#endif + +extern enum rsbac_adf_req_ret_t rsbac_adf_request_udf( + enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +extern int rsbac_adf_set_attr_udf (enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +#endif /* UDF */ + +/****** REG *******/ + +#if defined(CONFIG_RSBAC_REG) +extern enum rsbac_adf_req_ret_t rsbac_adf_request_reg( + enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +extern int rsbac_adf_set_attr_reg (enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +#ifdef CONFIG_RSBAC_SECDEL +extern inline rsbac_boolean_t rsbac_need_overwrite_reg(struct dentry * dentry_p) + { + return FALSE; + } +#endif +#endif /* REG */ + +#ifdef CONFIG_RSBAC_MPROTECT +#ifdef CONFIG_RSBAC_SWITCH_MPROTECT +extern rsbac_boolean_t rsbac_switch_mprotect; +#endif +#endif + +#if defined(CONFIG_RSBAC_REG) +/* Init */ +#ifdef CONFIG_RSBAC_INIT_DELAY +void rsbac_reg_init(void); +#else +void rsbac_reg_init(void) __init; +#endif + +/* mounting and umounting */ +extern int rsbac_mount_reg(kdev_t kdev); +extern int rsbac_umount_reg(kdev_t kdev); + +/* RSBAC attribute saving to disk can be triggered from outside + * param: call lock_kernel() before writing? + */ +#if defined(CONFIG_RSBAC_AUTO_WRITE) +extern int rsbac_write_reg(void); +#endif /* CONFIG_RSBAC_AUTO_WRITE */ + +/* Status checking */ +extern int rsbac_check_reg(int correct, int check_inode); + +#endif /* REG */ + +#endif /* End of adf_main.h */ diff --git a/include/rsbac/adf_syshelpers.h b/include/rsbac/adf_syshelpers.h new file mode 100644 index 000000000000..5f1f91f0ce05 --- /dev/null +++ b/include/rsbac/adf_syshelpers.h @@ -0,0 +1,266 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2013: */ +/* Amon Ott */ +/* */ +/* Helper Prototypes for model */ +/* specific system calls */ +/* Last modified: 18/Nov/2013 */ +/************************************ */ + +#ifndef __RSBAC_ADF_SYSHELPERS_H +#define __RSBAC_ADF_SYSHELPERS_H + +/* #include */ +#include + +/***************************************************/ +/* Global Variables */ +/***************************************************/ + +/***************************************************/ +/* General Prototypes */ +/***************************************************/ + +/***************************************************/ +/* Module Prototypes */ +/***************************************************/ + +/******* MAC ********/ + +#if defined(CONFIG_RSBAC_MAC) || defined(CONFIG_RSBAC_MAC_MAINT) +int rsbac_mac_set_curr_level(rsbac_security_level_t level, + rsbac_mac_category_vector_t categories); + +int rsbac_mac_get_curr_level(rsbac_security_level_t * level_p, + rsbac_mac_category_vector_t * categories_p); + +int rsbac_mac_get_max_level(rsbac_security_level_t * level_p, + rsbac_mac_category_vector_t * categories_p); + +int rsbac_mac_get_min_level(rsbac_security_level_t * level_p, + rsbac_mac_category_vector_t * categories_p); + +int rsbac_mac_add_p_tru( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + rsbac_uid_t uid, + rsbac_time_t ttl); + +int rsbac_mac_remove_p_tru( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + rsbac_uid_t uid); + +int rsbac_mac_add_f_tru( + rsbac_list_ta_number_t ta_number, + rsbac_mac_file_t file, + rsbac_uid_t uid, + rsbac_time_t ttl); + +int rsbac_mac_remove_f_tru( + rsbac_list_ta_number_t ta_number, + rsbac_mac_file_t file, + rsbac_uid_t uid); + +#endif /* MAC */ + + +/******* FF ********/ + +/******* RC ********/ + +#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT) +/* These functions in adf/rc/syscalls.c are called via sys_* system calls */ +/* and check for validity before passing the call to the rc_data_structures. */ + +/* All roles are always there, so instead of creation, we supply a copy for */ +/* initialization. There is always the well-defined role general to copy */ +extern int rsbac_rc_sys_copy_role ( + rsbac_list_ta_number_t ta_number, + rsbac_rc_role_id_t from_role, + rsbac_rc_role_id_t to_role); + +extern int rsbac_rc_sys_copy_type ( + rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + rsbac_rc_type_id_t from_type, + rsbac_rc_type_id_t to_type); + +/* Getting item values */ +extern int rsbac_rc_sys_get_item ( + rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t tid, + union rsbac_rc_target_id_t subtid, + enum rsbac_rc_item_t item, + union rsbac_rc_item_value_t * value_p, + rsbac_time_t * ttl_p); + +/* Setting item values */ +extern int rsbac_rc_sys_set_item ( + rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t tid, + union rsbac_rc_target_id_t subtid, + enum rsbac_rc_item_t item, + union rsbac_rc_item_value_t value, + rsbac_time_t ttl); + +/* Set own role, if allowed ( = in role_comp vector of current role) */ +extern int rsbac_rc_sys_change_role (rsbac_rc_role_id_t role, char __user * pass); + +/* Getting own effective rights */ +int rsbac_rc_sys_get_eff_rights ( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_rc_request_vector_t * request_vector, + rsbac_time_t * ttl_p); + +int rsbac_rc_sys_get_current_role (rsbac_rc_role_id_t * role_p); + +#endif /* RC || RC_MAINT */ + +/****** AUTH *******/ + +#if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT) +/* This function is called via sys_rsbac_auth_add_p_cap() system call */ +int rsbac_auth_add_p_cap( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range, + rsbac_time_t ttl); + +/* This function is called via sys_rsbac_auth_remove_p_cap() system call */ +int rsbac_auth_remove_p_cap( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range); + +/* This function is called via sys_rsbac_auth_add_f_cap() system call */ +int rsbac_auth_add_f_cap( + rsbac_list_ta_number_t ta_number, + rsbac_auth_file_t file, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range, + rsbac_time_t ttl); + +/* This function is called via sys_rsbac_auth_remove_f_cap() system call */ +int rsbac_auth_remove_f_cap( + rsbac_list_ta_number_t ta_number, + rsbac_auth_file_t file, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range); + +#endif /* AUTH || AUTH_MAINT */ + +/****** REG *******/ + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +/* + * System call dispatcher + * Returns 0 on success or -EINVALIDTARGET, if handle is invalid. + */ + +int rsbac_reg_syscall(rsbac_reg_handle_t handle, + void __user * arg); +#endif /* REG || REG_MAINT */ + +/****** ACL *******/ + +#if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT) +int rsbac_acl_sys_set_acl_entry( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t rights, + rsbac_time_t ttl); + +int rsbac_acl_sys_remove_acl_entry( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id); + +int rsbac_acl_sys_remove_acl( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid); + +int rsbac_acl_sys_add_to_acl_entry( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t rights, + rsbac_time_t ttl); + +int rsbac_acl_sys_remove_from_acl_entry( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t rights); + +int rsbac_acl_sys_set_mask( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_acl_rights_vector_t mask); + +int rsbac_acl_sys_remove_user( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t uid); + +int rsbac_acl_sys_get_mask( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_acl_rights_vector_t * mask_p); + + +int rsbac_acl_sys_get_rights( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t * rights_p, + rsbac_boolean_t inherit); + +int rsbac_acl_sys_get_tlist( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + struct rsbac_acl_entry_t ** entry_pp, + rsbac_time_t ** ttl_pp); + +int rsbac_acl_sys_group( + rsbac_list_ta_number_t ta_number, + enum rsbac_acl_group_syscall_type_t call, + union rsbac_acl_group_syscall_arg_t arg); + +#endif /* ACL || ACL_MAINT */ + +/****** JAIL *******/ + +#if defined(CONFIG_RSBAC_JAIL) +/* This function is called via sys_rsbac_jail() system call */ +int rsbac_jail_sys_jail(rsbac_version_t version, + char __user * path, + rsbac_jail_ip_t ip, + rsbac_jail_flags_t flags, + rsbac_cap_vector_t max_caps, + rsbac_jail_scd_vector_t scd_get, + rsbac_jail_scd_vector_t scd_modify); +#endif + +#endif /* End of adf_syshelpers.h */ diff --git a/include/rsbac/auth.h b/include/rsbac/auth.h new file mode 100644 index 000000000000..9960bef1b7d6 --- /dev/null +++ b/include/rsbac/auth.h @@ -0,0 +1,154 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2013: */ +/* Amon Ott */ +/* API: Data structures */ +/* and functions for Access */ +/* Control Information / AUTH */ +/* Last modified: 09/Aug/2013 */ +/************************************ */ + +#ifndef __RSBAC_AUTH_H +#define __RSBAC_AUTH_H + +#include +#include + +/***************************************************/ +/* General Prototypes */ +/***************************************************/ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac_error.h. */ + +/****************************************************************************/ +/* Initialization, including ACI restoration for all mounted devices from */ +/* disk. After this call, all ACI is kept in memory for performance reasons,*/ +/* but user and file/dir object ACI are written to disk on every change. */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +extern int rsbac_init_auth(void); +#else +extern int rsbac_init_auth(void) __init; +#endif + +/* mounting and umounting */ +int rsbac_mount_auth(kdev_t kdev); +int rsbac_umount_auth(kdev_t kdev); + +/* Some information about the current status is also available */ +extern int rsbac_stats_auth(void); + +/* Status checking */ +extern int rsbac_check_auth(int correct, int check_inode); + +/* RSBAC attribute saving to disk can be triggered from outside + * param: call lock_kernel() before writing? + */ +#if defined(CONFIG_RSBAC_AUTO_WRITE) +extern int rsbac_write_auth(rsbac_boolean_t); +#endif /* CONFIG_RSBAC_AUTO_WRITE */ + +/************************************************* */ +/* Access functions */ +/************************************************* */ + +/* All these procedures handle the semaphores to protect the targets during */ +/* access. */ +/* Trying to access a never created or removed set returns an error! */ + +/* rsbac_auth_add_to_p_capset */ +/* Add a set member to a set sublist. Set behaviour: also returns success, */ +/* if member was already in set! */ + +int rsbac_auth_add_to_p_capset( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range, + rsbac_time_t ttl); + +int rsbac_auth_add_to_f_capset( + rsbac_list_ta_number_t ta_number, + rsbac_auth_file_t file, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range, + rsbac_time_t ttl); + +/* rsbac_auth_remove_from_p_capset */ +/* Remove a set member from a sublist. Set behaviour: Returns no error, if */ +/* member is not in list. */ + +int rsbac_auth_remove_from_p_capset( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range); + +int rsbac_auth_remove_from_f_capset( + rsbac_list_ta_number_t ta_number, + rsbac_auth_file_t file, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range); + +/* rsbac_auth_clear_p_capset */ +/* Remove all set members from a sublist. Set behaviour: Returns no error, */ +/* if list is empty. */ + +int rsbac_auth_clear_p_capset( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type); + +int rsbac_auth_clear_f_capset( + rsbac_list_ta_number_t ta_number, + rsbac_auth_file_t file, + enum rsbac_auth_cap_type_t cap_type); + +/* rsbac_auth_p_capset_member */ +/* Return truth value, whether member is in set */ + +rsbac_boolean_t rsbac_auth_p_capset_member(rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type, + rsbac_uid_t member); + +/* rsbac_auth_remove_p_capset */ +/* Remove a full set. After this call the given id can only be used for */ +/* creating a new set, anything else returns an error. */ +/* To empty an existing set use rsbac_auth_clear_p_capset. */ + +int rsbac_auth_remove_p_capsets(rsbac_pid_t pid); + +int rsbac_auth_remove_f_capsets(rsbac_auth_file_t file); + +/* rsbac_auth_copy_fp_capset */ +/* copy a file capset to a process capset */ +int rsbac_auth_copy_fp_capset(rsbac_auth_file_t file, + rsbac_pid_t p_cap_set_id); + +/* rsbac_auth_copy_pp_capset */ +/* copy a process capset to another process capset */ +int rsbac_auth_copy_pp_capset(rsbac_pid_t old_p_set_id, + rsbac_pid_t new_p_set_id); + +/* rsbac_auth_get_f_caplist */ +/* copy a file/dir capset to an array of length 2 * maxnum (first+last), */ +/* returns number of caps copied */ +int rsbac_auth_get_f_caplist( + rsbac_list_ta_number_t ta_number, + rsbac_auth_file_t file, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t **caplist_p, + rsbac_time_t **ttllist_p); + +/* rsbac_auth_get_p_caplist */ +/* copy a process capset to an array of length 2 * maxnum (first+last), */ +/* returns number of caps copied */ +int rsbac_auth_get_p_caplist( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t **caplist_p, + rsbac_time_t **ttllist_p); + +#endif diff --git a/include/rsbac/auth_data_structures.h b/include/rsbac/auth_data_structures.h new file mode 100644 index 000000000000..5ef0ea1ff836 --- /dev/null +++ b/include/rsbac/auth_data_structures.h @@ -0,0 +1,97 @@ +/**************************************/ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: */ +/* Amon Ott */ +/* Data structures / AUTH */ +/* Last modified: 07/Jan/2016 */ +/**************************************/ + +#ifndef __RSBAC_AUTH_DATA_STRUC_H +#define __RSBAC_AUTH_DATA_STRUC_H + +#include +#include +#include + +/**********************************************/ +/* Capability lists */ +/**********************************************/ + +#define RSBAC_AUTH_LIST_KEY 626281 + +#define RSBAC_AUTH_P_LIST_VERSION 1 +#define RSBAC_AUTH_P_LIST_NAME "authproc" +#define RSBAC_AUTH_P_EFF_LIST_NAME "authproceff" +#define RSBAC_AUTH_P_FS_LIST_NAME "authprocfs" +#define RSBAC_AUTH_P_GROUP_LIST_NAME "authprocgr" +#define RSBAC_AUTH_P_GROUP_EFF_LIST_NAME "authprocgreff" +#define RSBAC_AUTH_P_GROUP_FS_LIST_NAME "authprocgrfs" + +#define RSBAC_AUTH_FD_FILENAME "authfd" +#define RSBAC_AUTH_FD_EFF_FILENAME "authfde" +#define RSBAC_AUTH_FD_FS_FILENAME "authfdf" +#define RSBAC_AUTH_FD_GROUP_FILENAME "authfg" +#define RSBAC_AUTH_FD_GROUP_EFF_FILENAME "authfge" +#define RSBAC_AUTH_FD_GROUP_FS_FILENAME "authfgf" +#define RSBAC_AUTH_FD_OLD_FILENAME "authfd." +#define RSBAC_AUTH_FD_OLD_EFF_FILENAME "authfde." +#define RSBAC_AUTH_FD_OLD_FS_FILENAME "authfdf." +#define RSBAC_AUTH_FD_OLD_GROUP_FILENAME "authfg." +#define RSBAC_AUTH_FD_OLD_GROUP_EFF_FILENAME "authfge." +#define RSBAC_AUTH_FD_OLD_GROUP_FS_FILENAME "authfgf." +#define RSBAC_AUTH_NR_CAP_FD_LIST_HASH_BITS 2 +#define RSBAC_AUTH_NR_CAP_EFF_FD_LIST_HASH_BITS 1 +#define RSBAC_AUTH_NR_CAP_FS_FD_LIST_HASH_BITS 1 +#define RSBAC_AUTH_NR_CAP_GROUP_FD_LIST_HASH_BITS 2 +#define RSBAC_AUTH_NR_CAP_GROUP_EFF_FD_LIST_HASH_BITS 1 +#define RSBAC_AUTH_NR_CAP_GROUP_FS_FD_LIST_HASH_BITS 1 + +#define RSBAC_AUTH_FD_LIST_VERSION 2 +#define RSBAC_AUTH_FD_EFF_LIST_VERSION 2 +#define RSBAC_AUTH_FD_FS_LIST_VERSION 2 +#define RSBAC_AUTH_FD_GROUP_LIST_VERSION 2 +#define RSBAC_AUTH_FD_GROUP_EFF_LIST_VERSION 2 +#define RSBAC_AUTH_FD_GROUP_FS_LIST_VERSION 2 +#define RSBAC_AUTH_FD_OLD_LIST_VERSION 1 +#define RSBAC_AUTH_FD_EFF_OLD_LIST_VERSION 1 +#define RSBAC_AUTH_FD_FS_OLD_LIST_VERSION 1 +#define RSBAC_AUTH_FD_GROUP_OLD_LIST_VERSION 1 +#define RSBAC_AUTH_FD_GROUP_EFF_OLD_LIST_VERSION 1 +#define RSBAC_AUTH_FD_GROUP_FS_OLD_LIST_VERSION 1 + +/* The list of devices is also a double linked list, so we define list */ +/* items and a list head. */ + +struct rsbac_auth_device_list_item_t { + kdev_t id; /* set to 0 before deletion */ + u_int mount_count; + rsbac_list_handle_t handle; +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + rsbac_list_handle_t eff_handle; + rsbac_list_handle_t fs_handle; +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + rsbac_list_handle_t + group_handle; +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + rsbac_list_handle_t + group_eff_handle; + rsbac_list_handle_t + group_fs_handle; +#endif +#endif + struct rsbac_auth_device_list_item_t *prev; + struct rsbac_auth_device_list_item_t *next; +}; + +/* To provide consistency we use spinlocks for all list accesses. The */ +/* 'curr' entry is used to avoid repeated lookups for the same item. */ + +struct rsbac_auth_device_list_head_t { + struct rsbac_auth_device_list_item_t *head; + struct rsbac_auth_device_list_item_t *tail; + struct rsbac_auth_device_list_item_t *curr; + u_int count; +}; + +#endif diff --git a/include/rsbac/cap_getname.h b/include/rsbac/cap_getname.h new file mode 100644 index 000000000000..e5024a49d46f --- /dev/null +++ b/include/rsbac/cap_getname.h @@ -0,0 +1,14 @@ +/********************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2005: */ +/* Amon Ott */ +/* Getname functions for CAP module */ +/* Last modified: 28/Jan/2005 */ +/********************************** */ + +#ifndef __RSBAC_CAP_GETNAME_H +#define __RSBAC_CAP_GETNAME_H + +void rsbac_cap_log_missing_cap(int cap); + +#endif diff --git a/include/rsbac/daz.h b/include/rsbac/daz.h new file mode 100644 index 000000000000..9da0112b4dcd --- /dev/null +++ b/include/rsbac/daz.h @@ -0,0 +1,27 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2005: Amon Ott */ +/* API: */ +/* Functions for Access */ +/* Control Information / DAZ */ +/* Last modified: 18/Jan/2005 */ +/************************************ */ + +#ifndef __RSBAC_DAZ_H +#define __RSBAC_DAZ_H + +#include + +/* Get ttl for new cache items in seconds */ +/* This function returns 0, if no cache is available, and the ttl value + otherwise */ +rsbac_time_t rsbac_daz_get_ttl(void); + +/* Set ttl for new cache items in seconds */ +/* ttl must be positive, values bigger than 10 years in seconds + (RSBAC_LIST_MAX_AGE_LIMIT in lists.h) are reduced to this limit */ +void rsbac_daz_set_ttl(rsbac_time_t ttl); + +/* Flush DAZuko cache lists */ +int rsbac_daz_flush_cache(void); +#endif diff --git a/include/rsbac/debug.h b/include/rsbac/debug.h new file mode 100644 index 000000000000..d827af2398f7 --- /dev/null +++ b/include/rsbac/debug.h @@ -0,0 +1,297 @@ +/******************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: */ +/* Amon Ott */ +/* debug definitions */ +/* Last modified: 01/Aug/2016 */ +/******************************* */ + +#ifndef __RSBAC_DEBUG_H +#define __RSBAC_DEBUG_H + +#include +//#include + +#define set_rsbac_softmode 1 +#define set_rsbac_softmode_once 2 +#define set_rsbac_softmode_never 4 +#define set_rsbac_freeze 8 +#define set_rsbac_um_no_excl 16 +#define set_rsbac_auth_learn 32 +#define set_rsbac_acl_learn_fd 64 +#define set_rsbac_cap_log_missing 128 +#define set_rsbac_jail_log_missing 256 +#define set_rsbac_dac_disable 512 +#define set_rsbac_no_delay_init 1024 +#define set_rsbac_no_defaults 2048 +#define set_rsbac_nosyslog 4096 +#define set_rsbac_cap_process_hiding 8192 +#define set_rsbac_cap_learn 16384 +#define set_rsbac_rc_learn 32768 + +extern unsigned long int rsbac_flags; +extern void rsbac_flags_set(unsigned long int); + +extern int rsbac_debug_no_write; + +#ifdef CONFIG_RSBAC_DEBUG +extern int rsbac_debug_ds; +extern int rsbac_debug_write; +extern int rsbac_debug_stack; +extern int rsbac_debug_lists; +extern int rsbac_debug_aef; +#ifdef CONFIG_RSBAC_MPROTECT +extern int rsbac_debug_mprotect; +#endif +#endif + +extern int rsbac_debug_adf_default; +extern rsbac_log_entry_t rsbac_log_levels[R_NONE+1]; + +#define RSBAC_LOG_LEVELS_NAME "log_levels" +#define RSBAC_LOG_LEVEL_LIST_NAME "ll" +#define RSBAC_LOG_LEVEL_VERSION 4 +#define RSBAC_LOG_LEVEL_OLD_VERSION 3 +#define RSBAC_LOG_LEVEL_OLD_OLD_VERSION 2 +#define RSBAC_LOG_LEVEL_KEY 13123231 + + +extern int rsbac_no_defaults; + +#ifdef CONFIG_RSBAC_INIT_DELAY +extern void rsbac_init_debug(void); +#else +extern void rsbac_init_debug(void) __init; +#endif + +extern rsbac_boolean_t rsbac_parse_koptions(char *); + +#define RSBAC_WAKEUP_KEY 'w' +#define RSBAC_WAKEUP_UKEY 'W' + +#ifdef CONFIG_RSBAC_SOFTMODE +#define RSBAC_SOFTMODE_KEY 'x' +#define RSBAC_SOFTMODE_UKEY 'X' +extern int rsbac_softmode; +extern int rsbac_softmode_prohibit; +static inline int rsbac_in_softmode(void) + { + return rsbac_softmode; + } +#ifdef CONFIG_RSBAC_SOFTMODE_IND +extern int rsbac_ind_softmode[SW_NONE]; +#endif +#endif + +#if defined(CONFIG_RSBAC_FREEZE) +extern int rsbac_freeze; +#endif + +extern int rsbac_list_recover; +extern int rsbac_list_noread; +extern u_int rsbac_list_auto_rehash_trigger; + +#ifdef CONFIG_RSBAC_FD_CACHE +extern rsbac_time_t rsbac_fd_cache_ttl; +extern u_int rsbac_fd_cache_disable; +extern u_int rsbac_fd_cache_fuse; +extern u_int rsbac_fd_cache_ceph; +#endif + +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +extern rsbac_time_t rsbac_um_name_cache_ttl; +extern u_int rsbac_um_name_cache_disable; +#endif + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +extern rsbac_time_t rsbac_list_check_interval; +#endif + +#if defined(CONFIG_RSBAC_CAP_PROC_HIDE) +extern int rsbac_cap_process_hiding; +#endif +#ifdef CONFIG_RSBAC_CAP_LOG_MISSING +extern int rsbac_cap_log_missing; +#endif +#ifdef CONFIG_RSBAC_JAIL_LOG_MISSING +extern int rsbac_jail_log_missing; +#endif + +#ifdef CONFIG_RSBAC_RMSG_NOSYSLOG +extern int rsbac_nosyslog; +#endif + +#ifdef CONFIG_RSBAC_INIT_DELAY +extern int rsbac_no_delay_init; +extern kdev_t rsbac_delayed_root; +extern char rsbac_delayed_root_str[]; +#endif + +/* rsbac_printk(): You must always prepend the loglevel. As sequence numbers + * are per rsbac_printk() message, it is strongly recommended to output single + * full lines only. + * Example: + * rsbac_printk(KERN_DEBUG "Test value: %u\n", testval); + */ +extern int rsbac_printk(const char *, ...); + +#ifdef CONFIG_RSBAC_DEBUG +#define rsbac_pr_debug(type, fmt, arg...) \ + do { if (rsbac_debug_##type) \ + rsbac_printk(KERN_DEBUG "%s(): " fmt, __FUNCTION__, ##arg); \ + } while (0) +#else +#define rsbac_pr_debug(type, fmt, arg...) do { } while (0) +#endif + +#define rsbac_pr_get_error(attr) \ + do { rsbac_ds_get_error (__FUNCTION__, attr); \ + } while (0) +#define rsbac_pr_set_error(attr) \ + do { rsbac_ds_set_error (__FUNCTION__, attr); \ + } while (0) +#define rsbac_pr_get_error_num(attr, num) \ + do { rsbac_ds_get_error_num (__FUNCTION__, attr, num); \ + } while (0) +#define rsbac_pr_set_error_num(attr, num) \ + do { rsbac_ds_set_error_num (__FUNCTION__, attr, num); \ + } while (0) + +#define rsbac_rc_pr_get_error(item) \ + do { rsbac_rc_ds_get_error (__FUNCTION__, item); \ + } while (0) +#define rsbac_rc_pr_set_error(item) \ + do { rsbac_rc_ds_set_error (__FUNCTION__, item); \ + } while (0) + +#define RSBAC_LOG_MAXLINE 2020 + +#if defined(CONFIG_RSBAC_RMSG) +extern int rsbac_log(int, char *, int); + +#define RSBAC_LOG_MAXREADBUF (rsbac_min(8192,RSBAC_MAX_KMALLOC)) + +struct rsbac_log_list_item_t { + struct rsbac_log_list_item_t *next; + u16 size; + char buffer[0]; +}; + +struct rsbac_log_list_head_t { + struct rsbac_log_list_item_t *head; + struct rsbac_log_list_item_t *tail; + u_int count; + u_long lost; +}; +#if defined(CONFIG_RSBAC_LOG_REMOTE) +extern rsbac_pid_t rsbaclogd_pid; +#endif +#endif + +#ifdef CONFIG_RSBAC_NET +extern int rsbac_debug_ds_net; +extern int rsbac_debug_aef_net; +extern int rsbac_debug_adf_net; +#endif + +extern void wakeup_rsbacd(u_long dummy); + +/* switch log level for request */ +void rsbac_adf_log_switch(rsbac_adf_request_int_t request, + enum rsbac_target_t target, + rsbac_enum_t value); + +int rsbac_get_adf_log(rsbac_adf_request_int_t request, + enum rsbac_target_t target, + u_int * value_p); + +#ifdef CONFIG_RSBAC_DEBUG +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +extern int rsbac_debug_auto; +#endif /* CONFIG_RSBAC_AUTO_WRITE > 0 */ + +#ifdef CONFIG_RSBAC_FD_CACHE +extern int rsbac_debug_fdcache; +#endif + +#if defined(CONFIG_RSBAC_MAC) +extern int rsbac_debug_ds_mac; +extern int rsbac_debug_aef_mac; +extern int rsbac_debug_adf_mac; +#endif + +#if defined(CONFIG_RSBAC_DAZ) +extern int rsbac_debug_adf_daz; +#endif + +#if defined(CONFIG_RSBAC_RC) +extern int rsbac_debug_ds_rc; +extern int rsbac_debug_aef_rc; +extern int rsbac_debug_adf_rc; +#endif + +#if defined(CONFIG_RSBAC_AUTH) +extern int rsbac_debug_ds_auth; +extern int rsbac_debug_aef_auth; +extern int rsbac_debug_adf_auth; +#endif + +#if defined(CONFIG_RSBAC_REG) +extern int rsbac_debug_reg; +#endif + +#if defined(CONFIG_RSBAC_ACL) +extern int rsbac_debug_ds_acl; +extern int rsbac_debug_aef_acl; +extern int rsbac_debug_adf_acl; +#endif + +#if defined(CONFIG_RSBAC_JAIL) +extern int rsbac_debug_aef_jail; +extern int rsbac_debug_adf_jail; +#endif + +#if defined(CONFIG_RSBAC_PAX) +extern int rsbac_debug_adf_pax; +#endif + +#if defined(CONFIG_RSBAC_UM) +extern int rsbac_debug_ds_um; +extern int rsbac_debug_aef_um; +extern int rsbac_debug_adf_um; +#endif + +#if defined(CONFIG_RSBAC_UDF) +extern int rsbac_debug_adf_udf; +#endif + +#endif /* DEBUG */ + +#if defined(CONFIG_RSBAC_UM_EXCL) +extern int rsbac_um_no_excl; +#endif + +#if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT) +extern int rsbac_auth_enable_login; +#if defined(CONFIG_RSBAC_AUTH_LEARN) +extern int rsbac_auth_learn; +#define RSBAC_AUTH_LEARN_TA_NAME "AUTH-learn" +#endif +#endif + +#if defined(CONFIG_RSBAC_RC_LEARN) +extern int rsbac_rc_learn; +#define RSBAC_RC_LEARN_TA_NAME "RC-learn" +#endif + +#if defined(CONFIG_RSBAC_CAP_LEARN) +extern int rsbac_cap_learn; +#define RSBAC_CAP_LEARN_TA_NAME "CAP-learn" +#endif + +#if defined(CONFIG_RSBAC_ACL_LEARN) +extern int rsbac_acl_learn_fd; +#define RSBAC_ACL_LEARN_TA_NAME "ACL-FD-learn" +#endif + +#endif diff --git a/include/rsbac/error.h b/include/rsbac/error.h new file mode 100644 index 000000000000..33fa1daedc8d --- /dev/null +++ b/include/rsbac/error.h @@ -0,0 +1,66 @@ +/************************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2008: Amon Ott */ +/* Helper functions for all parts */ +/* Last modified: 03/Mar/2008 */ +/************************************* */ + +#ifndef __RSBAC_ERROR_H +#define __RSBAC_ERROR_H + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +/* Error values */ + +#define RSBAC_EPERM 1001 +#define RSBAC_EACCESS 1002 +#define RSBAC_EREADFAILED 1003 +#define RSBAC_EWRITEFAILED 1004 +#define RSBAC_EINVALIDPOINTER 1005 +#define RSBAC_ENOROOTDIR 1006 +#define RSBAC_EPATHTOOLONG 1007 +#define RSBAC_ENOROOTDEV 1008 +#define RSBAC_ENOTFOUND 1009 +#define RSBAC_ENOTINITIALIZED 1010 +#define RSBAC_EREINIT 1011 +#define RSBAC_ECOULDNOTADDDEVICE 1012 +#define RSBAC_ECOULDNOTADDITEM 1013 +#define RSBAC_ECOULDNOTCREATEPATH 1014 +#define RSBAC_EINVALIDATTR 1015 +#define RSBAC_EINVALIDDEV 1016 +#define RSBAC_EINVALIDTARGET 1017 +#define RSBAC_EINVALIDVALUE 1018 +#define RSBAC_EEXISTS 1019 +#define RSBAC_EINTERNONLY 1020 +#define RSBAC_EINVALIDREQUEST 1021 +#define RSBAC_ENOTWRITABLE 1022 +#define RSBAC_EMALWAREDETECTED 1023 +#define RSBAC_ENOMEM 1024 +#define RSBAC_EDECISIONMISMATCH 1025 +#define RSBAC_EINVALIDVERSION 1026 +#define RSBAC_EINVALIDMODULE 1027 +#define RSBAC_EEXPIRED 1028 +#define RSBAC_EMUSTCHANGE 1029 +#define RSBAC_EBUSY 1030 +#define RSBAC_EINVALIDTRANSACTION 1031 +#define RSBAC_EWEAKPASSWORD 1032 +#define RSBAC_EINVALIDLIST 1033 +#define RSBAC_EFROMINTERRUPT 1034 + +#define RSBAC_EMAX 1034 + +#define RSBAC_ERROR( res ) ((res <= -RSBAC_EPERM) && (res >= -RSBAC_EMAX)) + +#ifndef __KERNEL__ +/* exit on error */ +void error_exit(int error); + +/* show error */ +void show_error(int error); +#endif + +#endif diff --git a/include/rsbac/fs.h b/include/rsbac/fs.h new file mode 100644 index 000000000000..154924b2ed9a --- /dev/null +++ b/include/rsbac/fs.h @@ -0,0 +1,59 @@ +/************************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2015: Amon Ott */ +/* File system */ +/* helper functions for all parts */ +/* Last modified: 07/Jul/2015 */ +/************************************* */ + +#ifndef __RSBAC_FS_H +#define __RSBAC_FS_H + +#include +#include +#include +#include +#include + +/* original lookup_dentry function without rsbac patch for adf call */ + +struct dentry * rsbac_lookup_hash(struct qstr *name, struct dentry * base); +struct dentry * rsbac_lookup_one_len(const char * name, struct dentry * base, int len); + +#ifndef SOCKFS_MAGIC +#define SOCKFS_MAGIC 0x534F434B +#endif + +#ifndef SYSFS_MAGIC +#define SYSFS_MAGIC 0x62656572 +#endif + +#ifndef OCFS2_SUPER_MAGIC +#define OCFS2_SUPER_MAGIC 0x7461636f +#endif + +struct vfsmount * rsbac_get_vfsmount(kdev_t kdev); + +extern void __fput(struct file *); + +#ifndef SHM_FS_MAGIC +#define SHM_FS_MAGIC 0x02011994 +#endif + +static inline int init_private_file(struct file *filp, struct dentry *dentry, int mode) +{ + memset(filp, 0, sizeof(*filp)); + filp->f_mode = mode; + atomic_long_set(&filp->f_count, 1); + filp->f_path.dentry = dentry; + filp->f_cred = current_cred(); + filp->f_op = dentry->d_inode->i_fop; + filp->f_mapping = dentry->d_inode->i_mapping; + file_ra_state_init(&filp->f_ra, filp->f_mapping); + if (filp->f_op->open) + return filp->f_op->open(dentry->d_inode, filp); + else + return 0; +} + +#endif diff --git a/include/rsbac/gen_lists.h b/include/rsbac/gen_lists.h new file mode 100644 index 000000000000..97f72358fce2 --- /dev/null +++ b/include/rsbac/gen_lists.h @@ -0,0 +1,286 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: Amon Ott */ +/* Generic lists - internal structures */ +/* Last modified: 07/Jan/2016 */ +/*************************************************** */ + +#ifndef __RSBAC_GEN_LISTS_H +#define __RSBAC_GEN_LISTS_H + +#include +#include +#include +#include + +/* Sanity limit of list size, regardless of RSBAC_LIST_MAX_NR_ITEMS in lists.h */ +#define RSBAC_LIST_MAX_NR_ITEMS_LIMIT 65000 + +#define RSBAC_LIST_DISK_VERSION 10003 +#define RSBAC_LIST_DISK_OLD_VERSION 10002 +#define RSBAC_LIST_NONAME "(no name)" +#define RSBAC_LIST_PROC_NAME "gen_lists" +#define RSBAC_LIST_COUNTS_PROC_NAME "gen_lists_counts" + +#define RSBAC_LIST_TA_KEY 0xface99 + +#define RSBAC_LIST_MAX_OLD_HASH 32 +#define RSBAC_LIST_LOL_MAX_OLD_HASH 16 + +/* Rehashing interval in s - rehashing is triggered by rsbacd, so might happen + * less frequently, if rsbacd wakes up later. + */ +#define RSBAC_LIST_REHASH_INTERVAL 60 + +/* Prototypes */ + +/* Init */ +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_list_init(void); +#else +int __init rsbac_list_init(void); +#endif + +/* Status checking */ +int rsbac_check_lists(const int correct); + +#if defined(CONFIG_RSBAC_AUTO_WRITE) +int rsbac_write_lists(void); +#endif + +/* Data Structures */ + +/* All items will be organized in double linked lists + * However, we do not know the descriptor or item sizes, so we will access them + with offsets later and only define the list links here. + */ + +struct rsbac_list_item_t { + struct rsbac_list_item_t *prev; + struct rsbac_list_item_t *next; + rsbac_time_t max_age; +}; + +/* lists of lists ds */ +struct rsbac_list_lol_item_t { + struct rsbac_list_lol_item_t *prev; + struct rsbac_list_lol_item_t *next; + struct rsbac_list_item_t *head; + struct rsbac_list_item_t *tail; + struct rsbac_list_item_t *curr; + u_long count; + rsbac_time_t max_age; +}; + +typedef __u32 rsbac_list_count_t; + +struct rsbac_list_hashed_t { + struct rsbac_list_item_t *head; + struct rsbac_list_item_t *tail; + struct rsbac_list_item_t *curr; + rsbac_list_count_t count; +#ifdef CONFIG_RSBAC_LIST_TRANS + rsbac_ta_number_t ta_copied; + struct rsbac_list_item_t *ta_head; + struct rsbac_list_item_t *ta_tail; + struct rsbac_list_item_t *ta_curr; + rsbac_list_count_t ta_count; +#endif +}; + +struct rsbac_list_lol_hashed_t { + struct rsbac_list_lol_item_t *head; + struct rsbac_list_lol_item_t *tail; + struct rsbac_list_lol_item_t *curr; + rsbac_list_count_t count; +#ifdef CONFIG_RSBAC_LIST_TRANS + rsbac_ta_number_t ta_copied; + struct rsbac_list_lol_item_t *ta_head; + struct rsbac_list_lol_item_t *ta_tail; + struct rsbac_list_lol_item_t *ta_curr; + rsbac_list_count_t ta_count; +#endif +}; + +/* Since all registrations will be organized in double linked lists, we must + * have list items and a list head. + * The pointer to this item will also be used as list handle. */ + +struct rsbac_list_reg_item_t { + struct rsbac_list_info_t info; + u_int flags; + rsbac_boolean_t dirty; + rsbac_boolean_t no_write; + __u8 hash_bits; + __u16 max_items_per_hash; + rsbac_list_hash_function_t * hash_function; + rsbac_list_compare_function_t *compare; + rsbac_list_get_conv_t *get_conv; + void *def_data; + char name[RSBAC_LIST_MAX_FILENAME + 1]; + kdev_t device; + spinlock_t lock; + struct rsbac_list_rcu_free_head_t * rcu_free; + struct kmem_cache * slab; + char * slabname; +#if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS) + struct proc_dir_entry *proc_entry_p; +#endif + struct rsbac_nanotime_t lastchange; + char old_name_base[RSBAC_LIST_MAX_FILENAME + 1]; +#ifdef CONFIG_RSBAC_LIST_STATS + __u64 read_count; + __u64 write_count; +#endif + struct rsbac_list_reg_item_t *prev; + struct rsbac_list_reg_item_t *next; + struct rsbac_list_reg_item_t *self; + /* The hashed list heads are allocated dynamically! */ + struct rsbac_list_hashed_t * hashed; +}; + +struct rsbac_list_lol_reg_item_t { + struct rsbac_list_lol_info_t info; + u_int flags; + rsbac_boolean_t dirty; + rsbac_boolean_t no_write; + __u8 hash_bits; + __u16 max_items_per_hash; + __u16 max_subitems; + rsbac_list_compare_function_t *compare; + rsbac_list_compare_function_t *subcompare; + rsbac_list_get_conv_t *get_conv; + rsbac_list_get_conv_t *get_subconv; + void *def_data; + void *def_subdata; + char name[RSBAC_LIST_MAX_FILENAME + 1]; + kdev_t device; + spinlock_t lock; + struct rsbac_list_rcu_free_head_lol_t * rcu_free; + rsbac_list_hash_function_t * hash_function; + struct kmem_cache * slab; + char * slabname; + struct kmem_cache * subslab; + char * subslabname; +#if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS) + struct proc_dir_entry *proc_entry_p; +#endif + struct rsbac_nanotime_t lastchange; + char old_name_base[RSBAC_LIST_MAX_FILENAME + 1]; +#ifdef CONFIG_RSBAC_LIST_STATS + __u64 read_count; + __u64 write_count; +#endif + struct rsbac_list_lol_reg_item_t *prev; + struct rsbac_list_lol_reg_item_t *next; + struct rsbac_list_lol_reg_item_t *self; + /* The hashed list heads are allocated dynamically! */ + struct rsbac_list_lol_hashed_t * hashed; +}; + +/* To provide consistency we use spinlocks for all list accesses. The + 'curr' entry is used to avoid repeated lookups for the same item. */ + +struct rsbac_list_reg_head_t { + struct rsbac_list_reg_item_t *head; + struct rsbac_list_reg_item_t *tail; + struct rsbac_list_reg_item_t *curr; + spinlock_t lock; + struct lock_class_key lock_class; + u_int count; +}; + +struct rsbac_list_lol_reg_head_t { + struct rsbac_list_lol_reg_item_t *head; + struct rsbac_list_lol_reg_item_t *tail; + struct rsbac_list_lol_reg_item_t *curr; + spinlock_t lock; + struct lock_class_key lock_class; + u_int count; +}; + +/* Internal helper list of filled write buffers */ + +struct rsbac_list_buffer_t { + struct rsbac_list_buffer_t * next; + u_int len; + char data[0]; +}; + +#define RSBAC_LIST_BUFFER_SIZE 8192 +#define RSBAC_LIST_BUFFER_DATA_SIZE (RSBAC_LIST_BUFFER_SIZE - sizeof(struct rsbac_list_buffer_t)) + +struct rsbac_list_write_item_t { + struct rsbac_list_write_item_t *prev; + struct rsbac_list_write_item_t *next; + struct rsbac_list_reg_item_t *list; + struct rsbac_list_buffer_t *buffer; + char name[RSBAC_LIST_MAX_FILENAME + 1]; + kdev_t device; +}; + +struct rsbac_list_write_head_t { + struct rsbac_list_write_item_t *head; + struct rsbac_list_write_item_t *tail; + u_int count; +}; + +struct rsbac_list_lol_write_item_t { + struct rsbac_list_lol_write_item_t *prev; + struct rsbac_list_lol_write_item_t *next; + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_buffer_t *buffer; + char name[RSBAC_LIST_MAX_FILENAME + 1]; + kdev_t device; +}; + +struct rsbac_list_lol_write_head_t { + struct rsbac_list_lol_write_item_t *head; + struct rsbac_list_lol_write_item_t *tail; + u_int count; +}; + + +/* Data structs for file timeout book keeping list filelist */ +struct rsbac_list_filelist_desc_t { + char filename[RSBAC_LIST_MAX_FILENAME + 1]; +}; + +struct rsbac_list_filelist_data_t { + rsbac_time_t timestamp; + rsbac_time_t max_age; +}; + +struct rsbac_list_ta_data_t { + rsbac_time_t start; + rsbac_time_t timeout; + rsbac_uid_t commit_uid; + char name[RSBAC_LIST_TA_MAX_NAMELEN]; + char password[RSBAC_LIST_TA_MAX_PASSLEN]; +}; + +struct rsbac_list_rcu_free_head_t { + /* rcu _must_ stay first */ + struct rcu_head rcu; + struct kmem_cache * slab; + struct rsbac_list_rcu_free_item_t * head; + struct rsbac_list_item_t * item_chain; +}; + +struct rsbac_list_rcu_free_head_lol_t { + /* rcu _must_ stay first */ + struct rcu_head rcu; + struct kmem_cache * slab; + struct kmem_cache * subslab; + struct rsbac_list_rcu_free_item_t * head; + struct rsbac_list_rcu_free_item_t * subhead; + struct rsbac_list_lol_item_t * lol_item_chain; + struct rsbac_list_item_t * lol_item_subchain; +}; + +struct rsbac_list_rcu_free_item_t { + struct rsbac_list_rcu_free_item_t * next; + void * mem; +}; + +#endif diff --git a/include/rsbac/getname.h b/include/rsbac/getname.h new file mode 100644 index 000000000000..f64fe6e55153 --- /dev/null +++ b/include/rsbac/getname.h @@ -0,0 +1,107 @@ +/******************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: */ +/* Amon Ott */ +/* Getname functions for all parts*/ +/* Last modified: 23/Aug/2016 */ +/******************************** */ + +#ifndef __RSBAC_GETNAME_H +#define __RSBAC_GETNAME_H + +#include +#ifdef CONFIG_RSBAC_XSTATS +#include +#endif + +#if defined(__KERNEL__) && defined(CONFIG_RSBAC_LOG_FULL_PATH) +#include +#if (CONFIG_RSBAC_MAX_PATH_LEN > 2000) +#undef CONFIG_RSBAC_MAX_PATH_LEN +#define CONFIG_RSBAC_MAX_PATH_LEN 2000 +#endif +#if (CONFIG_RSBAC_MAX_PATH_LEN < RSBAC_MAXNAMELEN) +#undef CONFIG_RSBAC_MAX_PATH_LEN +#define CONFIG_RSBAC_MAX_PATH_LEN RSBAC_MAXNAMELEN +#endif +#endif + +extern char * get_request_name(char * , enum rsbac_adf_request_t); + +extern enum rsbac_adf_request_t get_request_nr(const char *); + +extern char * get_result_name(char * , enum rsbac_adf_req_ret_t); + +extern enum rsbac_adf_req_ret_t get_result_nr(const char *); + +extern enum rsbac_switch_target_t get_attr_module(enum rsbac_attribute_t attr); + +extern char * get_attribute_name(char * , enum rsbac_attribute_t); + +extern char * get_attribute_value_name( char * attr_val_name, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t * attr_val_p); + +extern enum rsbac_attribute_t get_attribute_nr(const char *); + +/* Returns rsbac_kmalloc'd "current->comm, path-to-program" + * or NULL, if alloc failed. + * Caller must rsbac_kfree after use. + */ +extern char * rsbac_get_program_name(void); + +extern char * get_target_name(char * , enum rsbac_target_t, + char * , union rsbac_target_id_t); + +extern char * get_target_name_only(char * target_type_name, + enum rsbac_target_t target); + +extern enum rsbac_target_t get_target_nr(const char *); + +extern char * get_ipc_target_name(char *, + enum rsbac_ipc_type_t); + +extern enum rsbac_ipc_type_t get_ipc_target_nr(const char *); + +extern char * get_scd_type_name(char *, + enum rsbac_scd_type_t); + +extern enum rsbac_scd_type_t get_scd_type_nr(const char *); + +extern char * get_switch_target_name(char *, + enum rsbac_switch_target_t); + +extern enum rsbac_switch_target_t get_switch_target_nr(const char *); + +extern char * get_error_name(char *, + int); + +#ifndef __KERNEL__ +extern char * get_attribute_param(char * , enum rsbac_attribute_t); +#endif + +extern char * get_log_level_name(char *, + enum rsbac_log_level_t); + +extern enum rsbac_log_level_t get_log_level_nr(const char *); + +#ifdef __KERNEL__ +int rsbac_lookup_full_path(struct dentry * dentry_p, char path[], int maxlen, int pseudonymize); + +static inline int rsbac_get_full_path(struct dentry * dentry_p, char path[], int maxlen) +{ + return rsbac_lookup_full_path(dentry_p, path, maxlen, 1); +} +#endif + +char * get_cap_name(char * name, + u_int value); + +int get_cap_nr(const char * name); + +#ifdef CONFIG_RSBAC_XSTATS +char *rsbac_get_syscall_name(char *syscall_name, + enum rsbac_syscall_t syscall); +#endif + +#endif diff --git a/include/rsbac/helpers.h b/include/rsbac/helpers.h new file mode 100644 index 000000000000..38763b0ff1ac --- /dev/null +++ b/include/rsbac/helpers.h @@ -0,0 +1,159 @@ +/************************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2013: Amon Ott */ +/* Helper functions for all parts */ +/* Last modified: 14/Jan/2013 */ +/************************************* */ + +#ifndef __RSBAC_HELPER_H +#define __RSBAC_HELPER_H + +#include +#include +#include +#ifdef __KERNEL__ +#include +#endif + +char * inttostr(char[], int); + +char * ulongtostr(char[], u_long); + +/* convert u_long_long to binary string representation for MAC module */ +char * u64tostrmac(char[], __u64); + +char * u32tostrcap(char * str, __u32 i); +__u32 strtou32cap(char * str, __u32 * i_p); + +int rsbac_get_vset_num(char * sourcename, rsbac_um_set_t * vset_p); + +#ifndef __KERNEL__ +void locale_init(void); + +int rsbac_lib_version(void); +int rsbac_u32_compare(__u32 * a, __u32 * b); +int rsbac_u32_void_compare(const void *a, const void *b); + +int rsbac_user_compare(const void * a, const void * b); +int rsbac_group_compare(const void * a, const void * b); +int rsbac_nettemp_id_compare(const void * a, const void * b); + +int rsbac_dev_compare(const void * desc1, + const void * desc2); + +char * get_user_name(rsbac_uid_t user, char * name); + +char * get_group_name(rsbac_gid_t group, char * name); + +int rsbac_get_uid_name(rsbac_uid_t * uid, char * name, char * sourcename); + +int rsbac_get_fullname(char * fullname, rsbac_uid_t uid); + +static inline int rsbac_get_uid(rsbac_uid_t * uid, char * sourcename) + { + return rsbac_get_uid_name(uid, NULL, sourcename); + } + +int rsbac_get_gid_name(rsbac_gid_t * gid, char * name, char * sourcename); + +static inline int rsbac_get_gid(rsbac_gid_t * gid, char * sourcename) + { + return rsbac_get_gid_name(gid, NULL, sourcename); + } + +/* covert u_long_long to binary string representation for log array */ +char * u64tostrlog(char[], __u64); +/* and back */ +__u64 strtou64log(char[], __u64 *); + +/* convert u_long_long to binary string representation for MAC module */ +/* and back */ +__u64 strtou64mac(char[], __u64 *); + +/* covert u_long_long to binary string representation for RC module */ +char * u64tostrrc(char[], __u64); +/* and back */ +__u64 strtou64rc(char[], __u64 *); + +/* covert u_long_long to binary string representation for RC module / rights */ +char *u64tostrrcr(char[], __u64); +/* and back */ +__u64 strtou64rcr(char[], __u64 *); + +/* ACL back */ +__u64 strtou64acl(char[], __u64 *); + +char *devdesctostr(char *str, struct rsbac_dev_desc_t dev); + +int strtodevdesc(char *str, struct rsbac_dev_desc_t * dev_p); +#endif + +/* covert u_long_long to binary string representation for ACL module */ +char *u64tostracl(char[], __u64); + +char *longtostr(char[], long); + +#ifdef __KERNEL__ +#include + +#ifdef CONFIG_RSBAC_UM_VIRTUAL +rsbac_um_set_t rsbac_get_vset(void); +#else + +static inline rsbac_um_set_t rsbac_get_vset(void) +{ + return 0; +} +#endif + +int rsbac_get_owner(rsbac_uid_t *user_p); + +static inline int rsbac_get_user(void *kern_p, void __user *user_p, unsigned long size) +{ + if (kern_p && user_p && (size > 0)) { + return copy_from_user(kern_p, user_p, size); + } + return 0; +} + +static inline int rsbac_put_user(void *kern_p, void __user *user_p, unsigned long size) +{ + if (kern_p && user_p && (size > 0)) { + return copy_to_user(user_p, kern_p, size); + } + return 0; +} + +static inline struct filename * rsbac_getname(const char __user * name) +{ + return getname(name); +} + +static inline void rsbac_putname(struct filename *name) +{ + putname(name); +} + +static inline int clear_user_buf(char *ubuf, int len) +{ + if (len > 0) { + return clear_user(ubuf, len); + } + return 0; +} + +void rsbac_get_attr_error(char *, enum rsbac_adf_request_t); + +void rsbac_ds_get_error(const char * function, enum rsbac_attribute_t attr); +void rsbac_ds_get_error_num(const char * function, enum rsbac_attribute_t attr, int err); +void rsbac_ds_set_error(const char * function, enum rsbac_attribute_t attr); +void rsbac_ds_set_error_num(const char * function, enum rsbac_attribute_t attr, int err); + +#ifdef CONFIG_RSBAC_RC +void rsbac_rc_ds_get_error(const char *function, enum rsbac_rc_item_t item); +void rsbac_rc_ds_set_error(const char *function, enum rsbac_rc_item_t item); +#endif + +#endif /* KERNEL */ + +#endif diff --git a/include/rsbac/hooks.h b/include/rsbac/hooks.h new file mode 100644 index 000000000000..10cd794dc031 --- /dev/null +++ b/include/rsbac/hooks.h @@ -0,0 +1,24 @@ +/******************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2006: */ +/* Amon Ott */ +/* Common include file set */ +/* Last modified: 31/Mar/2006 */ +/******************************* */ + +#ifndef __RSBAC_HOOKS_H +#define __RSBAC_HOOKS_H + +#ifdef CONFIG_RSBAC +#include +#include +#include +#include +#include +//#include +//#include +#else +#define rsbac_kthreads_init() do {} while(0) +#endif + +#endif diff --git a/include/rsbac/jail.h b/include/rsbac/jail.h new file mode 100644 index 000000000000..73d321b7ede7 --- /dev/null +++ b/include/rsbac/jail.h @@ -0,0 +1,16 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2007: */ +/* Amon Ott */ +/* Global definitions for JAIL module */ +/* Last modified: 29/Jan/2007 */ +/************************************ */ + +#ifndef __RSBAC_JAIL_H +#define __RSBAC_JAIL_H + +extern rsbac_jail_id_t rsbac_jail_syslog_jail_id; + +rsbac_boolean_t rsbac_jail_exists(rsbac_jail_id_t jail_id); + +#endif diff --git a/include/rsbac/jail_getname.h b/include/rsbac/jail_getname.h new file mode 100644 index 000000000000..01a301fcc5cf --- /dev/null +++ b/include/rsbac/jail_getname.h @@ -0,0 +1,14 @@ +/********************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2005: */ +/* Amon Ott */ +/* Getname functions for JAIL module */ +/* Last modified: 27/May/2005 */ +/********************************** */ + +#ifndef __RSBAC_JAIL_GETNAME_H +#define __RSBAC_JAIL_GETNAME_H + +void rsbac_jail_log_missing_cap(int cap); + +#endif diff --git a/include/rsbac/lists.h b/include/rsbac/lists.h new file mode 100644 index 000000000000..72efd410a9c3 --- /dev/null +++ b/include/rsbac/lists.h @@ -0,0 +1,959 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: Amon Ott */ +/* Generic List Management */ +/* Last modified: 07/Jan/2016 */ +/*************************************************** */ + +/* Note: lol = list of lists, a two-level list structure */ + +#ifndef __RSBAC_LISTS_H +#define __RSBAC_LISTS_H + +#include +#include + +#define RSBAC_LIST_VERSION 3 + +typedef void *rsbac_list_handle_t; +typedef __u32 rsbac_list_key_t; + +/* Maximum length for list (file)names */ +#define RSBAC_LIST_MAX_FILENAME 15 + +/* Limit for max_age_in_seconds: ca. 10 years */ +#define RSBAC_LIST_MAX_AGE_LIMIT (3600 * 24 * 366 * 10) + +/* Maximum desc_size + data_size: 8K - some space for metadata */ +#define RSBAC_LIST_MAX_ITEM_SIZE (8192 - 64) + +#define RSBAC_LIST_MIN_MAX_HASH_BITS 3 +/* This must never be > 31 or we badly break the hash functions + * and kmalloc + */ +#define RSBAC_LIST_MAX_MAX_HASH_BITS 18 + +/* standard hash functions */ +u_int rsbac_list_hash_u32(void * desc, __u8 hash_bits); +u_int rsbac_list_hash_fd(void * desc, __u8 hash_bits); +u_int rsbac_list_hash_old_fd(void * desc, __u8 hash_bits); +u_int rsbac_list_hash_pid(void * desc, __u8 hash_bits); +u_int rsbac_list_hash_uid(void * desc, __u8 hash_bits); +u_int rsbac_list_hash_gid(void * desc, __u8 hash_bits); +u_int rsbac_list_hash_ipc(void * desc, __u8 hash_bits); +u_int rsbac_list_hash_dev(void * desc, __u8 hash_bits); +u_int rsbac_list_hash_nettemp(void * desc, __u8 hash_bits); +u_int rsbac_list_hash_netobj(void * desc, __u8 hash_bits); + +/****************************/ +/* List Registration Flags: */ + +/* Make persistent, i.e., save to and restore from disk */ +#define RSBAC_LIST_PERSIST 1 + +/* Ignore old list contents (still checks key, if list exists on disk) */ +#define RSBAC_LIST_IGNORE_OLD 2 + +/* Ignore old list contents, if version upconversion is not supported + * (no get_conv, or get_conv returned NULL) - without this flag, registration fails, if + * list cannot be converted. + */ +#define RSBAC_LIST_IGNORE_UNSUPP_VERSION 4 + +/* Temporarily disallow writing list to disk, e.g. for upgrade tests */ +#define RSBAC_LIST_NO_WRITE 8 + +/* Provide a binary backup file as /proc/rsbac-info/backup/filename */ +#define RSBAC_LIST_BACKUP 16 + +/* Use provided default data, return it for unexisting items and + automatically create and cleanup items with default data as necessary. + (only items with 0 ttl (unlimited) get removed) + (lol items with default data only get removed, if they have no subitems) */ +#define RSBAC_LIST_DEF_DATA 32 + +/* Use provided default subitem data, return it for unexisting subitems and + automatically create and cleanup subitems with default data as necessary. + (only subitems with 0 ttl (unlimited) get removed) */ +#define RSBAC_LIST_DEF_SUBDATA 64 + +/* Replicate list to replication partners. + Must be enabled in config. */ +#define RSBAC_LIST_REPLICATE 128 + +/* Allow automatic online resizing of the list hashing table. + Requires that the provided hash function uses the hash_bits parameter. */ +#define RSBAC_LIST_AUTO_HASH_RESIZE 256 + +/* Disable limit of RSBAC_LIST_MAX_NR_ITEMS items per single list. */ +#define RSBAC_LIST_NO_MAX 512 + +/* Disable warning if max_entries prevents adding of items */ +#define RSBAC_LIST_NO_MAX_WARN 1024 + +/* Use own slab for this list */ +#define RSBAC_LIST_OWN_SLAB 2048 + +/* Maximum number of items per single list, the total limit is at + * RSBAC_LIST_MAX_NR_ITEMS * (2^hash_bits). + * Limits can be disabled per list with RSBAC_LIST_NO_MAX flag and + * changed with rsbac_list_max_items() and rsbac_list_lol_max_items(). + * In fact, size is still limited to the sanity value + * RSBAC_LIST_MAX_NR_ITEMS_LIMIT, defined in gen_lists.h. + */ + +#define RSBAC_LIST_MAX_NR_ITEMS 10000 +#define RSBAC_LIST_MAX_NR_SUBITEMS 10000 + +/****************************/ +/* Function prototypes */ + +/* Function to compare two descriptors, returns 0, if equal, a negative value, + * if desc1 < desc2 and a positive value, if desc1 > desc2 (like memcmp). + * Used for lookup and list optimization. + * Note: Non-0 values are only used for list optimization and do not necessarily + * imply a real order of values. + */ +typedef int rsbac_list_compare_function_t(void *desc1, void *desc2); + +int rsbac_list_compare_u32(void * desc1, void * desc2); + +/* Function to compare two datas, returns 0, if equal, and another value, + * if not. + * Used for lookup by data. + * Note: list optimization is based on descriptors, so data lookup is always + * linear search from first to last element in list order. + */ +typedef int rsbac_list_data_compare_function_t(void *data1, void *data2); + +/* Function to compare two descs with a parameter, returns TRUE, + * if item is selected, and FALSE, if not. + * Used for selected lists of descriptors. + */ +typedef int rsbac_list_desc_selector_function_t(void *desc, void * param); + +/* conversion function to upconvert old on-disk descs and datas to actual version */ +/* must return 0 on success or error otherwise */ +/* Attention: if old or new data_size is 0, the respective data pointer is NULL! */ +typedef int rsbac_list_conv_function_t(void *old_desc, + void *old_data, + void *new_desc, void *new_data); + +/* callback function to return an upconvert function for on-disk-version, if versions differ */ +/* Note: Lists implementation does not assume anything about your version number apart + from being of type rsbac_version_t. Use it as you like. */ +typedef rsbac_list_conv_function_t *rsbac_list_get_conv_t(rsbac_version_t + old_version); + +/* hash function to return a hash for the descriptor in the range 0 to (1 << hash_bits) - 1 */ +typedef u_int rsbac_list_hash_function_t(void * desc, __u8 hash_bits); + +/* get generic list registration version */ +rsbac_version_t rsbac_list_version(void); + + +/* List info: This struct will be written to disk */ +/* + * list_version: a simple __u32 version number for the list. If old on-disk version is + different, conversion is tried (depending on flags and get_conv function) + * key: secret __u32 key, which must be the same as in on-disk version, if persistent + * desc_size: size of the descriptor (error is returned, if list exists and value differs) + internally reset to sizeof(__u32) for u32 call variants + * data_size: size of data (error is returned, if list exists and value differs) + set to 0 for sets without data + * subdesc_size: size of the descriptor of the sublist (error is returned, if list exists + and value differs), internally reset to sizeof(__u32) for u32 call variants + * subdata_size: size of sublist data (error is returned, if list exists and value differs) + set to 0 for sets without data + * max_age: seconds until unchanged list file (no add or remove) will be purged. + Maximum value is RSBAC_LIST_MAX_AGE_LIMIT (s.a.), use 0 for unlimited lifetime. + (purging not yet implemented - only reused without key, please cleanup by hand) + */ +struct rsbac_list_info_t { + rsbac_version_t version; + rsbac_list_key_t key; + __u32 desc_size; + __u32 data_size; + rsbac_time_t max_age; +}; + +struct rsbac_list_lol_info_t { + rsbac_version_t version; + rsbac_list_key_t key; + __u32 desc_size; + __u32 data_size; + __u32 subdesc_size; + __u32 subdata_size; + rsbac_time_t max_age; +}; + + +/* register a new list */ +/* + * If list with same name exists in memory, error -RSBAC_EEXISTS is returned. + * If list with same name and key exists on device, it is restored depending on + the flags. + * If list with same name, but different key exists on disk, access is denied + (error -EPERM). + * + * ds_version: for binary modules, must be RSBAC_LIST_VERSION. If version + differs, return error. + * handle_p: for all list accesses, an opaque handle is put into *handle_p. + * flags: see flag values + * compare: for lookup and list optimization, can be NULL, then + memcmp(desc1, desc2, desc_size) is used + * subcompare: for item lookup and optimization of sublist, can be NULL, then + memcmp(desc1, desc2, desc_size) is used + * get_conv: function to deliver conversion function for given version + * get_subconv: function to deliver sublist item conversion function for given + version + * def_data: default data value for flag RSBAC_LIST_DEF_DATA + (if NULL, flag is cleared) + * def_subdata: default subdata value for flag RSBAC_LIST_DEF_SUBDATA + (if NULL, flag is cleared) + * name: the on-disk name, should be distinct and max. 7 or 8.2 chars + (maxlen of RSBAC_LIST_MAX_FILENAME supported) (only used for statistics, if + non-persistent) + * device: the device to read list from or to save list to - use 0 for root dev + (ignored, if non-persistent) + * hash_bits: Number of bits of hashes for this list, minimum is 1, + maximum is rsbac_list_max_hash_bits, + which is derived from CONFIG_RSBAC_LIST_MAX_HASH_BITS and must not be more than 31 + Number of hashes is 2^hash_bits. + If > maximum, it will be reduced to maximum automatically. + * hash_function: Hash function(desc,hash_bits), must always return a value + from 0 to 2^hash_bits - 1. + * old_base_name: If not NULL and persistent list with name cannot be read, + try to read all old_base_name with n from 0 to 31. + */ + +int rsbac_list_register_hashed(rsbac_version_t ds_version, + rsbac_list_handle_t * handle_p, + struct rsbac_list_info_t *info_p, + u_int flags, + rsbac_list_compare_function_t * compare, + rsbac_list_get_conv_t * get_conv, + void *def_data, + char *name, kdev_t device, + __u8 hash_bits, + rsbac_list_hash_function_t hash_function, + char * old_base_name); + +int rsbac_list_lol_register_hashed(rsbac_version_t ds_version, + rsbac_list_handle_t * handle_p, + struct rsbac_list_lol_info_t *info_p, + u_int flags, + rsbac_list_compare_function_t * compare, + rsbac_list_compare_function_t * subcompare, + rsbac_list_get_conv_t * get_conv, + rsbac_list_get_conv_t * get_subconv, + void *def_data, + void *def_subdata, + char *name, kdev_t device, + __u8 hash_bits, + rsbac_list_hash_function_t hash_function, + char * old_base_name); + +/* Old and simpler registration function, sets hash_bits to 0, + * hash_function to NULL and old_base_name to NULL. + */ + +int rsbac_list_register(rsbac_version_t ds_version, + rsbac_list_handle_t * handle_p, + struct rsbac_list_info_t *info_p, + u_int flags, + rsbac_list_compare_function_t * compare, + rsbac_list_get_conv_t * get_conv, + void *def_data, char *name, kdev_t device); + +int rsbac_list_lol_register(rsbac_version_t ds_version, + rsbac_list_handle_t * handle_p, + struct rsbac_list_lol_info_t *info_p, + u_int flags, + rsbac_list_compare_function_t * compare, + rsbac_list_compare_function_t * subcompare, + rsbac_list_get_conv_t * get_conv, + rsbac_list_get_conv_t * get_subconv, + void *def_data, + void *def_subdata, char *name, kdev_t device); + +/* destroy list */ +/* list is destroyed, disk file is deleted */ +/* list must have been opened with register */ +int rsbac_list_destroy(rsbac_list_handle_t * handle_p, + rsbac_list_key_t key); + +int rsbac_list_lol_destroy(rsbac_list_handle_t * handle_p, + rsbac_list_key_t key); + +/* detach from list */ +/* list is saved (if persistent) and removed from memory. Call register for new access. */ +/* Must not be called with spinlock held. */ + +int rsbac_list_detach(rsbac_list_handle_t * handle_p, + rsbac_list_key_t key); + +int rsbac_list_lol_detach(rsbac_list_handle_t * handle_p, + rsbac_list_key_t key); + +/* set list's no_write flag */ +/* TRUE: do not write to disk, FALSE: writing allowed */ +int rsbac_list_no_write + (rsbac_list_handle_t handle, rsbac_list_key_t key, + rsbac_boolean_t no_write); + +int rsbac_list_lol_no_write + (rsbac_list_handle_t handle, rsbac_list_key_t key, + rsbac_boolean_t no_write); + +/* Set max_items_per_hash */ +int rsbac_list_max_items(rsbac_list_handle_t handle, rsbac_list_key_t key, + u_int max_items); + +int rsbac_list_lol_max_items(rsbac_list_handle_t handle, rsbac_list_key_t key, + u_int max_items, u_int max_subitems); + +/* Single list checking, good for cleanup of items with ttl in the past. */ +/* This functionality is also included in the big rsbac_check(). */ + +int rsbac_list_check(rsbac_list_handle_t handle, const int correct); + +int rsbac_list_lol_check(rsbac_list_handle_t handle, const int correct); + +/* Transaction Support */ +#ifdef CONFIG_RSBAC_LIST_TRANS +int rsbac_list_ta_begin(rsbac_time_t ttl, + rsbac_list_ta_number_t * ta_number_p, + rsbac_uid_t commit_uid, + char * name, char *password); + +int rsbac_list_ta_refresh(rsbac_time_t ttl, + rsbac_list_ta_number_t ta_number, + char *password); + +int rsbac_list_ta_commit(rsbac_list_ta_number_t ta_number, char *password); + +int rsbac_list_ta_forget(rsbac_list_ta_number_t ta_number, char *password); + +/* Returns TRUE, if transaction ta_number exists, and FALSE, if not. */ +int rsbac_list_ta_exist(rsbac_list_ta_number_t ta_number); +#endif + +/* add with time-to-live - after this time in seconds the item gets automatically removed */ +/* set to 0 for unlimited (default), RSBAC_LIST_TTL_KEEP to keep previous setting */ +int rsbac_ta_list_add_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t ttl, void *desc, void *data); + +static inline int rsbac_list_add_ttl(rsbac_list_handle_t handle, + rsbac_time_t ttl, void *desc, void *data) +{ + return rsbac_ta_list_add_ttl(0, handle, ttl, desc, data); +} + +static inline int rsbac_list_add(rsbac_list_handle_t handle, void *desc, void *data) +{ + return rsbac_ta_list_add_ttl(0, handle, RSBAC_LIST_TTL_KEEP, desc, + data); +} + +/* Add list of lists sublist item, item for desc must exist */ +int rsbac_ta_list_lol_subadd_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t ttl, + void *desc, void *subdesc, void *subdata); + +static inline int rsbac_list_lol_subadd_ttl(rsbac_list_handle_t handle, + rsbac_time_t ttl, + void *desc, void *subdesc, void *subdata) +{ + return rsbac_ta_list_lol_subadd_ttl(0, handle, ttl, desc, subdesc, + subdata); +} + +static inline int rsbac_list_lol_subadd(rsbac_list_handle_t handle, + void *desc, void *subdesc, void *subdata) +{ + return rsbac_ta_list_lol_subadd_ttl(0, handle, RSBAC_LIST_TTL_KEEP, + desc, subdesc, subdata); +} + +/* add with time-to-live - after this time in seconds the item gets automatically removed */ +int rsbac_ta_list_lol_add_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t ttl, void *desc, void *data); + +static inline int rsbac_list_lol_add_ttl(rsbac_list_handle_t handle, + rsbac_time_t ttl, void *desc, void *data) +{ + return rsbac_ta_list_lol_add_ttl(0, handle, ttl, desc, data); +} + +static inline int rsbac_list_lol_add(rsbac_list_handle_t handle, void *desc, void *data) +{ + return rsbac_ta_list_lol_add_ttl(0, handle, RSBAC_LIST_TTL_KEEP, + desc, data); +} + +/* remove item */ +int rsbac_ta_list_remove(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc); + +static inline int rsbac_list_remove(rsbac_list_handle_t handle, void *desc) +{ + return rsbac_ta_list_remove(0, handle, desc); +} + +/* remove all items */ +int rsbac_ta_list_remove_all(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle); + +static inline int rsbac_list_remove_all(rsbac_list_handle_t handle) +{ + return rsbac_ta_list_remove_all(0, handle); +} + +/* remove item from sublist - also succeeds, if item for desc or subdesc does not exist */ +int rsbac_ta_list_lol_subremove(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, void *subdesc); + +static inline int rsbac_list_lol_subremove(rsbac_list_handle_t handle, + void *desc, void *subdesc) +{ + return rsbac_ta_list_lol_subremove(0, handle, desc, subdesc); +} + +int rsbac_ta_list_lol_subremove_count(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, u_long count); + + +/* remove same subitem from all sublists */ +int rsbac_ta_list_lol_subremove_from_all(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *subdesc); + +static inline int rsbac_list_lol_subremove_from_all(rsbac_list_handle_t handle, + void *subdesc) +{ + return rsbac_ta_list_lol_subremove_from_all(0, handle, subdesc); +} + +/* remove all subitems from list */ +int rsbac_ta_list_lol_subremove_all(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc); + +static inline int rsbac_list_lol_subremove_all(rsbac_list_handle_t handle, void *desc) +{ + return rsbac_ta_list_lol_subremove_all(0, handle, desc); +} + +int rsbac_ta_list_lol_remove(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc); + +static inline int rsbac_list_lol_remove(rsbac_list_handle_t handle, void *desc) +{ + return rsbac_ta_list_lol_remove(0, handle, desc); +} + +int rsbac_ta_list_lol_remove_all(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle); + +static inline int rsbac_list_lol_remove_all(rsbac_list_handle_t handle) +{ + return rsbac_ta_list_lol_remove_all(0, handle); +} + + +/* get item data */ +/* Item data is copied - we cannot give a pointer, because item could be + * removed */ +/* also get time-to-live - after this time in seconds the item gets automatically removed */ +/* both ttl_p and data can be NULL, they are then simply not returned */ +int rsbac_ta_list_get_data_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, void *data); + +static inline int rsbac_list_get_data_ttl(rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, void *desc, void *data) +{ + return rsbac_ta_list_get_data_ttl(0, handle, ttl_p, desc, data); +} + +static inline int rsbac_list_get_data(rsbac_list_handle_t handle, void *desc, void *data) +{ + return rsbac_ta_list_get_data_ttl(0, handle, NULL, desc, data); +} + +/* get data from a subitem */ +/* also get time-to-live - after this time in seconds the item gets automatically removed */ +/* both ttl_p and data can be NULL, they are then simply not returned */ +int rsbac_ta_list_lol_get_subdata_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, + void *subdesc, void *subdata); + +static inline int rsbac_list_lol_get_subdata_ttl(rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, + void *subdesc, void *subdata) +{ + return rsbac_ta_list_lol_get_subdata_ttl(0, handle, + ttl_p, desc, subdesc, + subdata); +} + +static inline int rsbac_list_lol_get_subdata(rsbac_list_handle_t handle, + void *desc, void *subdesc, void *subdata) +{ + return rsbac_ta_list_lol_get_subdata_ttl(0, handle, NULL, desc, + subdesc, subdata); +} + +/* also get time-to-live - after this time in seconds the item gets automatically removed */ +/* both ttl_p and data can be NULL, they are then simply not returned */ +int rsbac_ta_list_lol_get_data_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, void *data); + +static inline int rsbac_list_lol_get_data_ttl(rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, void *data) +{ + return rsbac_ta_list_lol_get_data_ttl(0, handle, ttl_p, desc, + data); +} + +static inline int rsbac_list_lol_get_data(rsbac_list_handle_t handle, + void *desc, void *data) +{ + return rsbac_ta_list_lol_get_data_ttl(0, handle, NULL, desc, data); +} + +/* get item desc by data */ +/* Item desc is copied - we cannot give a pointer, because item could be + * removed. + * If no compare function is provided (NULL value), memcmp is used. + * Note: The data value given here is always used as second parameter to the + * compare function, so you can use different types for storage and + * lookup. + */ +int rsbac_ta_list_get_desc_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare); + +static inline int rsbac_ta_list_get_desc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare) +{ + return rsbac_ta_list_get_desc_ttl(ta_number, handle, NULL, desc, data, compare); +} + +static inline int rsbac_list_get_desc(rsbac_list_handle_t handle, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare) +{ + return rsbac_ta_list_get_desc_ttl(0, handle, NULL, desc, data, compare); +} + +int rsbac_ta_list_get_desc_selector_ttl( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param); + +static inline int rsbac_ta_list_get_desc_selector( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + return rsbac_ta_list_get_desc_selector_ttl(ta_number, handle, NULL, desc, data, compare, selector, param); +} + +int rsbac_ta_list_lol_get_desc_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare); + +static inline int rsbac_ta_list_lol_get_desc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare) +{ + return rsbac_ta_list_lol_get_desc_ttl(ta_number, handle, NULL, desc, data, compare); +} + +static inline int rsbac_list_lol_get_desc(rsbac_list_handle_t handle, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare) +{ + return rsbac_ta_list_lol_get_desc_ttl(0, handle, NULL, desc, data, compare); +} + +int rsbac_ta_list_lol_get_desc_selector_ttl( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param); + +static inline int rsbac_ta_list_lol_get_desc_selector( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + return rsbac_ta_list_lol_get_desc_selector_ttl(ta_number, handle, NULL, desc, data, compare, selector, param); +} + +/* get maximum desc (uses compare function) */ +int rsbac_ta_list_get_max_desc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc); + +static inline int rsbac_list_get_max_desc(rsbac_list_handle_t handle, void *desc) +{ + return rsbac_ta_list_get_max_desc(0, handle, desc); +} + +int rsbac_ta_list_lol_get_max_subdesc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, void *subdesc); + +/* get next desc (uses compare function) */ +int rsbac_ta_list_get_next_desc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *old_desc, void *next_desc); + +static inline int rsbac_list_get_next_desc(rsbac_list_handle_t handle, void *old_desc, + void *next_desc) +{ + return rsbac_ta_list_get_next_desc(0, handle, old_desc, next_desc); +} + +int rsbac_ta_list_get_next_desc_selector( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *old_desc, + void *next_desc, + rsbac_list_desc_selector_function_t selector, + void * param); + +int rsbac_ta_list_lol_get_next_desc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *old_desc, void *next_desc); + +static inline int rsbac_list_lol_get_next_desc(rsbac_list_handle_t handle, + void *old_desc, void *next_desc) +{ + return rsbac_ta_list_lol_get_next_desc(0, handle, old_desc, + next_desc); +} + +int rsbac_ta_list_lol_get_next_desc_selector( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *old_desc, + void *next_desc, + rsbac_list_desc_selector_function_t selector, + void * param); + +/* does item exist? */ +/* returns TRUE, if item exists, FALSE, if not or error */ +int rsbac_ta_list_exist(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc); + +static inline int rsbac_list_exist(rsbac_list_handle_t handle, void *desc) +{ + return rsbac_ta_list_exist(0, handle, desc); +} + +int rsbac_ta_list_lol_subexist(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, void *subdesc); + +static inline int rsbac_list_lol_subexist(rsbac_list_handle_t handle, + void *desc, void *subdesc) +{ + return rsbac_ta_list_lol_subexist(0, handle, desc, subdesc); +} + +int rsbac_ta_list_lol_exist(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc); + +static inline int rsbac_list_lol_exist(rsbac_list_handle_t handle, void *desc) +{ + return rsbac_ta_list_lol_exist(0, handle, desc); +} + +/* + * Note: The subdesc/data value given here is always used as second parameter to the + * given subdesc compare function, so you can use different types for storage and + * lookup. If compare is NULL, call is forwarded to rsbac_list_lol_subexist. + * Warning: This function does not use the list optimization when searching the sublist! + */ +int rsbac_ta_list_lol_subexist_compare(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, + void *subdesc, + rsbac_list_compare_function_t + compare); + +static inline int rsbac_list_lol_subexist_compare(rsbac_list_handle_t handle, + void *desc, + void *subdesc, + rsbac_list_compare_function_t compare) +{ + return rsbac_ta_list_lol_subexist_compare(0, handle, + desc, subdesc, compare); +} + +/* count number of elements */ +/* returns number of elements or negative error code */ +long rsbac_ta_list_count(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle); + +static inline long rsbac_list_count(rsbac_list_handle_t handle) +{ + return rsbac_ta_list_count(0, handle); +} + +long rsbac_ta_list_lol_subcount(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc); + +static inline long rsbac_list_lol_subcount(rsbac_list_handle_t handle, void *desc) +{ + return rsbac_ta_list_lol_subcount(0, handle, desc); +} + +long rsbac_ta_list_lol_all_subcount(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle); + +static inline long rsbac_list_lol_all_subcount(rsbac_list_handle_t handle) +{ + return rsbac_ta_list_lol_all_subcount(0, handle); +} + +long rsbac_ta_list_lol_count(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle); + +static inline long rsbac_list_lol_count(rsbac_list_handle_t handle) +{ + return rsbac_ta_list_lol_count(0, handle); +} + + +/* Get array of all descriptors */ +/* Returns number of elements or negative error code */ +/* If return value > 0, *array_p contains a pointer to a rsbac_kmalloc'd array + of descs, otherwise *array_p is set to NULL. If *array_p has been set, + caller must call rsbac_kfree(*array_p) after use! */ + +long rsbac_ta_list_get_all_desc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void **array_p); + +static inline long rsbac_list_get_all_desc(rsbac_list_handle_t handle, void **array_p) +{ + return rsbac_ta_list_get_all_desc(0, handle, array_p); +} + +long rsbac_ta_list_get_all_desc_selector ( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void **array_p, + rsbac_list_desc_selector_function_t selector, + void * param); + +long rsbac_ta_list_lol_get_all_subdesc_ttl(rsbac_list_ta_number_t + ta_number, + rsbac_list_handle_t handle, + void *desc, void **array_p, + rsbac_time_t ** ttl_array_p); + +static inline long rsbac_list_lol_get_all_subdesc(rsbac_list_handle_t handle, + void *desc, + void **array_p) +{ + return rsbac_ta_list_lol_get_all_subdesc_ttl(0, handle, + desc, array_p, NULL); +} + +static inline long rsbac_list_lol_get_all_subdesc_ttl(rsbac_list_handle_t handle, + void *desc, + void **array_p, + rsbac_time_t ** ttl_array_p) +{ + return rsbac_ta_list_lol_get_all_subdesc_ttl(0, + handle, + desc, + array_p, ttl_array_p); +} + +long rsbac_ta_list_lol_get_all_desc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void **array_p); + +static inline long rsbac_list_lol_get_all_desc(rsbac_list_handle_t handle, + void **array_p) +{ + return rsbac_ta_list_lol_get_all_desc(0, handle, array_p); +} + +long rsbac_ta_list_lol_get_all_desc_selector ( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void **array_p, + rsbac_list_desc_selector_function_t selector, + void * param); + +/* Get array of all datas */ +/* Returns number of elements or negative error code */ +/* If return value > 0, *array_p contains a pointer to a rsbac_kmalloc'd array + of datas, otherwise *array_p is set to NULL. If *array_p has been set, + caller must call rsbac_kfree(*array_p) after use! */ + +long rsbac_ta_list_get_all_data(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void **array_p); + +static inline long rsbac_list_get_all_data(rsbac_list_handle_t handle, void **array_p) +{ + return rsbac_ta_list_get_all_data(0, handle, array_p); +} + +long rsbac_ta_list_lol_get_all_subdata(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, void **array_p); + +static inline long rsbac_list_lol_get_all_subdata(rsbac_list_handle_t handle, + void *desc, void **array_p) +{ + return rsbac_ta_list_lol_get_all_subdata(0, handle, desc, array_p); +} + +long rsbac_ta_list_lol_get_all_data(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void **array_p); + +static inline long rsbac_list_lol_get_all_data(rsbac_list_handle_t handle, + void **array_p) +{ + return rsbac_ta_list_lol_get_all_data(0, handle, array_p); +} + +/* Get item size */ + +int rsbac_list_get_item_size(rsbac_list_handle_t handle); + +int rsbac_list_lol_get_subitem_size(rsbac_list_handle_t handle); + +int rsbac_list_lol_get_item_size(rsbac_list_handle_t handle); + +/* Get array of all items */ +/* Returns number of items or negative error code */ +/* If return value > 0, *array_p contains a pointer to a rsbac_kmalloc'd array + of items, where desc and data are placed directly behind each other. + If *array_p has been set, caller must call rsbac_kfree(*array_p) after use! */ + +long rsbac_ta_list_get_all_items_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void **array_p, + rsbac_time_t ** ttl_array_p); + +static inline long rsbac_list_get_all_items_ttl(rsbac_list_handle_t handle, + void **array_p, + rsbac_time_t ** ttl_array_p) +{ + return rsbac_ta_list_get_all_items_ttl(0, handle, array_p, + ttl_array_p); +} + +static inline long rsbac_list_get_all_items(rsbac_list_handle_t handle, void **array_p) +{ + return rsbac_ta_list_get_all_items_ttl(0, handle, array_p, NULL); +} + +long rsbac_ta_list_lol_get_all_subitems_ttl(rsbac_list_ta_number_t + ta_number, + rsbac_list_handle_t handle, + void *desc, void **array_p, + rsbac_time_t ** ttl_array_p); + +static inline long rsbac_list_lol_get_all_subitems_ttl(rsbac_list_handle_t handle, + void *desc, + void **array_p, + rsbac_time_t ** ttl_array_p) +{ + return rsbac_ta_list_lol_get_all_subitems_ttl(0, handle, desc, + array_p, + ttl_array_p); +} + +static inline long rsbac_list_lol_get_all_subitems(rsbac_list_handle_t handle, + void *desc, void **array_p) +{ + return rsbac_ta_list_lol_get_all_subitems_ttl(0, handle, desc, + array_p, NULL); +} + +long rsbac_ta_list_lol_get_all_items(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void **array_p); + +static inline long rsbac_list_lol_get_all_items(rsbac_list_handle_t handle, + void **array_p) +{ + return rsbac_ta_list_lol_get_all_items(0, handle, array_p); +} + +/* Copy a complete list + * Both lists must have been registered with same desc and data sizes, + * hash_bits may differ. Old target list items are removed before copying. + * If ta_number is set and transactions are enabled, the complete + * target list content is in the same transaction. Forgetting the + * transaction will restore the old to_list. + */ + +long rsbac_list_copy(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t from_handle, + rsbac_list_handle_t to_handle); + +long rsbac_list_lol_copy(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t from_handle, + rsbac_list_handle_t to_handle); + +/* Get the current number of hashes - may vary when resized */ +int rsbac_list_get_hash_bits(rsbac_list_handle_t handle); + +int rsbac_list_lol_get_hash_bits(rsbac_list_handle_t handle); + +#endif +/* end of lists.h */ diff --git a/include/rsbac/log_cap.h b/include/rsbac/log_cap.h new file mode 100644 index 000000000000..82195bf262e8 --- /dev/null +++ b/include/rsbac/log_cap.h @@ -0,0 +1,14 @@ +/********************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 2005: */ +/* Amon Ott */ +/* Missing Cap logging */ +/* Last modified: 27/May/2005 */ +/********************************** */ + +#ifndef __RSBAC_LOG_CAP_H +#define __RSBAC_LOG_CAP_H + +void rsbac_log_missing_cap(int cap); + +#endif diff --git a/include/rsbac/lsm.h b/include/rsbac/lsm.h new file mode 100644 index 000000000000..1136dc016fa0 --- /dev/null +++ b/include/rsbac/lsm.h @@ -0,0 +1,16 @@ +/************************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 2003: Amon Ott */ +/* file system */ +/* Helper functions for all parts */ +/* Last modified: 28/Jul/2003 */ +/************************************* */ + +#ifndef __RSBAC_LSM_H +#define __RSBAC_LSM_H + +#include + +int rsbac_lsm_register(void); + +#endif diff --git a/include/rsbac/mac.h b/include/rsbac/mac.h new file mode 100644 index 000000000000..9598a6a0312d --- /dev/null +++ b/include/rsbac/mac.h @@ -0,0 +1,134 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2013: */ +/* Amon Ott */ +/* API: Data structures */ +/* and functions for Access */ +/* Control Information / MAC */ +/* Last modified: 09/Aug/2013 */ +/************************************ */ + +#ifndef __RSBAC_MAC_H +#define __RSBAC_MAC_H + +#include +#include + +/***************************************************/ +/* General Prototypes */ +/***************************************************/ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac_error.h. */ + +/****************************************************************************/ +/* Initialization, including ACI restoration for all mounted devices from */ +/* disk. After this call, all ACI is kept in memory for performance reasons,*/ +/* but user and file/dir object ACI are written to disk on every change. */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +extern int rsbac_init_mac(void); +#else +extern int rsbac_init_mac(void) __init; +#endif + +/* mounting and umounting */ +int rsbac_mount_mac(kdev_t kdev); +int rsbac_umount_mac(kdev_t kdev); + +/* Some information about the current status is also available */ +extern int rsbac_stats_mac(void); + +/* Status checking */ +extern int rsbac_check_mac(int correct, int check_inode); + +/* RSBAC attribute saving to disk can be triggered from outside + * param: call lock_kernel() before writing? + */ +#if defined(CONFIG_RSBAC_AUTO_WRITE) +extern int rsbac_write_mac(rsbac_boolean_t); +#endif /* CONFIG_RSBAC_AUTO_WRITE */ + +/************************************************* */ +/* Access functions */ +/************************************************* */ + +/* All these procedures handle the semaphores to protect the targets during */ +/* access. */ +/* Trying to access a never created or removed set returns an error! */ + +/* rsbac_mac_add_to_truset */ +/* Add a set member to a set sublist. Set behaviour: also returns success, */ +/* if member was already in set! */ + +int rsbac_mac_add_to_p_truset( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + rsbac_uid_t member, + rsbac_time_t ttl); + +int rsbac_mac_add_to_f_truset( + rsbac_list_ta_number_t ta_number, + rsbac_mac_file_t file, + rsbac_uid_t member, + rsbac_time_t ttl); + +/* rsbac_mac_remove_from_truset */ +/* Remove a set member from a sublist. Set behaviour: Returns no error, if */ +/* member is not in list. */ + +int rsbac_mac_remove_from_p_truset( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + rsbac_uid_t member); + +int rsbac_mac_remove_from_f_truset( + rsbac_list_ta_number_t ta_number, + rsbac_mac_file_t file, + rsbac_uid_t member); + +/* rsbac_mac_clear_truset */ +/* Remove all set members from a sublist. Set behaviour: Returns no error, */ +/* if list is empty. */ + +int rsbac_mac_clear_p_truset( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid); + +int rsbac_mac_clear_f_truset( + rsbac_list_ta_number_t ta_number, + rsbac_mac_file_t file); + +/* rsbac_mac_truset_member */ +/* Return truth value, whether member is in set */ + +rsbac_boolean_t rsbac_mac_p_truset_member(rsbac_pid_t pid, + rsbac_uid_t member); + +/* rsbac_mac_remove_truset */ +/* Remove a full set. For cleanup, if object is deleted. */ +/* To empty an existing set use rsbac_mac_clear_truset. */ + +int rsbac_mac_remove_p_trusets(rsbac_pid_t pid); + +int rsbac_mac_remove_f_trusets(rsbac_mac_file_t file); + +int rsbac_mac_copy_fp_truset(rsbac_mac_file_t file, + rsbac_pid_t p_tru_set_id); + +int rsbac_mac_copy_pp_truset(rsbac_pid_t old_p_set_id, + rsbac_pid_t new_p_set_id); + +int rsbac_mac_get_f_trulist( + rsbac_list_ta_number_t ta_number, + rsbac_mac_file_t file, + rsbac_uid_t **trulist_p, + rsbac_time_t **ttllist_p); + +int rsbac_mac_get_p_trulist( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + rsbac_uid_t **trulist_p, + rsbac_time_t **ttllist_p); + +#endif diff --git a/include/rsbac/mac_data_structures.h b/include/rsbac/mac_data_structures.h new file mode 100644 index 000000000000..4567a44efefc --- /dev/null +++ b/include/rsbac/mac_data_structures.h @@ -0,0 +1,54 @@ +/**************************************/ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: */ +/* Amon Ott */ +/* Data structures / MAC */ +/* Last modified: 07/Jan/2016 */ +/**************************************/ + +#ifndef __RSBAC_MAC_DATA_STRUC_H +#define __RSBAC_MAC_DATA_STRUC_H + +#include +#include +#include + +/**********************************************/ +/* Capability lists */ +/**********************************************/ + +#define RSBAC_MAC_LIST_KEY 626281 + +#define RSBAC_MAC_P_LIST_VERSION 1 +#define RSBAC_MAC_P_LIST_NAME "macptru" + +#define RSBAC_MAC_FD_FILENAME "macfdtru" +#define RSBAC_MAC_FD_OLD_FILENAME "macfdtru." +#define RSBAC_MAC_NR_TRU_FD_LIST_HASH_BITS 2 +#define RSBAC_MAC_FD_LIST_VERSION 2 +#define RSBAC_MAC_FD_OLD_LIST_VERSION 1 + +/* The list of devices is also a double linked list, so we define list */ +/* items and a list head. */ + +struct rsbac_mac_device_list_item_t { + kdev_t id; /* set to 0 before deletion */ + u_int mount_count; + rsbac_list_handle_t handle; + struct rsbac_mac_device_list_item_t *prev; + struct rsbac_mac_device_list_item_t *next; +}; + +/* To provide consistency we use spinlocks for all list accesses. The */ +/* 'curr' entry is used to avoid repeated lookups for the same item. */ + +struct rsbac_mac_device_list_head_t { + struct rsbac_mac_device_list_item_t *head; + struct rsbac_mac_device_list_item_t *tail; + struct rsbac_mac_device_list_item_t *curr; + spinlock_t lock; + struct lock_class_key lock_class; + u_int count; +}; + +#endif diff --git a/include/rsbac/net_getname.h b/include/rsbac/net_getname.h new file mode 100644 index 000000000000..e0c7a70232b6 --- /dev/null +++ b/include/rsbac/net_getname.h @@ -0,0 +1,50 @@ +/********************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2003: */ +/* Amon Ott */ +/* Getname functions for CAP module */ +/* Last modified: 22/Dec/2003 */ +/********************************** */ + +#ifndef __RSBAC_NET_GETNAME_H +#define __RSBAC_NET_GETNAME_H + +#include + +#define RSBAC_NET_PROTO_MAX 256 +#define RSBAC_NET_TYPE_MAX 11 + +#ifdef __KERNEL__ +extern int rsbac_net_str_to_inet(char * str, __u32 * addr); +#else +#ifndef AF_MAX +#define AF_MAX 32 +#endif +#endif + +extern char * rsbac_get_net_temp_syscall_name(char * name, + enum rsbac_net_temp_syscall_t value); + +extern char * rsbac_get_net_family_name(char * name, + u_int value); + +extern char * rsbac_get_net_netlink_family_name(char * name, + u_int value); + +extern char * rsbac_get_net_protocol_name(char * name, + u_int value); + +extern char * rsbac_get_net_type_name(char * name, + u_int value); + +#ifndef __KERNEL__ +enum rsbac_net_temp_syscall_t rsbac_get_net_temp_syscall_nr(const char * name); + +int rsbac_get_net_family_nr(const char * name); + +int rsbac_get_net_protocol_nr(const char * name); + +int rsbac_get_net_type_nr(const char * name); +#endif + +#endif diff --git a/include/rsbac/network.h b/include/rsbac/network.h new file mode 100644 index 000000000000..fbf3a89400ad --- /dev/null +++ b/include/rsbac/network.h @@ -0,0 +1,91 @@ +/************************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2004: */ +/* Amon Ott */ +/* Network helper functions */ +/* Last modified: 07/Dec/2004 */ +/************************************* */ + +#ifndef __RSBAC_NETWORK_H +#define __RSBAC_NETWORK_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* functions */ + +int rsbac_ta_net_list_all_netdev(rsbac_list_ta_number_t ta_number, rsbac_netdev_id_t ** id_pp); + +static inline int rsbac_net_list_all_netdev(rsbac_netdev_id_t ** id_pp) + { + return rsbac_ta_net_list_all_netdev(0, id_pp); + } + +//__u32 rsbac_net_make_mask_u32(__u8 valid_bits); + +int rsbac_net_compare_data(void * data1, void * data2); + +int rsbac_net_get_id( + rsbac_list_ta_number_t ta_number, + struct rsbac_net_description_t * desc_p, + rsbac_net_temp_id_t * id_p); + +// void rsbac_net_obj_cleanup(rsbac_net_obj_id_t netobj); + +int rsbac_ta_net_lookup_templates( + rsbac_list_ta_number_t ta_number, + struct rsbac_net_obj_desc_t * netobj_p, + rsbac_net_temp_id_t * local_temp_p, + rsbac_net_temp_id_t * remote_temp_p); + +static inline int rsbac_net_lookup_templates( + struct rsbac_net_obj_desc_t * netobj_p, + rsbac_net_temp_id_t * local_temp_p, + rsbac_net_temp_id_t * remote_temp_p) + { + return rsbac_ta_net_lookup_templates(0, netobj_p, local_temp_p, remote_temp_p); + } + +/* Does template exist? Returns TRUE if yes, FALSE if no */ +int rsbac_ta_net_template_exists(rsbac_list_ta_number_t ta_number, + rsbac_net_temp_id_t id); + +int rsbac_ta_net_template( + rsbac_list_ta_number_t ta_number, + enum rsbac_net_temp_syscall_t call, + rsbac_net_temp_id_t id, + union rsbac_net_temp_syscall_data_t * data_p); + +static inline int rsbac_net_template(enum rsbac_net_temp_syscall_t call, + rsbac_net_temp_id_t id, + union rsbac_net_temp_syscall_data_t * data_p) + { + return rsbac_ta_net_template(0, call, id, data_p); + } + +int rsbac_ta_net_list_all_template(rsbac_list_ta_number_t ta_number, + rsbac_net_temp_id_t ** id_pp); + +static inline int rsbac_net_list_all_template(rsbac_net_temp_id_t ** id_pp) + { + return rsbac_ta_net_list_all_template(0, id_pp); + } + +int rsbac_ta_net_template_exist(rsbac_list_ta_number_t ta_number, rsbac_net_temp_id_t temp); + +static inline int rsbac_net_template_exist(rsbac_net_temp_id_t temp) + { + return rsbac_ta_net_template_exist(0, temp); + } + +/* Whether request should be checked for remote endpoint */ +int rsbac_net_remote_request(enum rsbac_adf_request_t request); + +#endif diff --git a/include/rsbac/network_types.h b/include/rsbac/network_types.h new file mode 100644 index 000000000000..c8a0ab8d30fe --- /dev/null +++ b/include/rsbac/network_types.h @@ -0,0 +1,154 @@ +/************************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2009: */ +/* Amon Ott */ +/* Network access control data structs */ +/* Last modified: 03/Feb/2009 */ +/************************************* */ + +#ifndef __RSBAC_NETWORK_TYPES_H +#define __RSBAC_NETWORK_TYPES_H + +#define RSBAC_NET_ANY 0 +#define RSBAC_NET_NETLINK_PROTO_ANY 255 + +#define RSBAC_NET_UNKNOWN 0 + +#define RSBAC_NET_TEMP_VERSION 2 +#define RSBAC_NET_TEMP_OLD_VERSION 1 +#define RSBAC_NET_TEMP_KEY 0x815affe +#define RSBAC_NET_TEMP_NAME "nettemp" + +typedef __u32 rsbac_net_temp_id_t; + +#define RSBAC_NET_MAX_ADDRESS_LEN 128 +#define RSBAC_NET_TEMP_NAMELEN 16 + +#define RSBAC_NET_MAX_PORT 65535 + +#define RSBAC_NET_NR_INET_ADDR 25 +#define RSBAC_NET_NR_PORTS 10 + +struct rsbac_net_temp_port_range_t { + __u16 min; + __u16 max; +}; + +struct rsbac_net_temp_inet_addr_t { + __u32 addr[RSBAC_NET_NR_INET_ADDR]; + __u8 valid_bits[RSBAC_NET_NR_INET_ADDR]; + __u8 nr_addr; +}; + +struct rsbac_net_temp_other_addr_t { + char addr[RSBAC_NET_MAX_ADDRESS_LEN]; + __u8 valid_len; +}; + +struct rsbac_net_temp_ports_t { + struct rsbac_net_temp_port_range_t ports[RSBAC_NET_NR_PORTS]; + __u8 nr_ports; +}; + +union rsbac_net_temp_addr_t { + struct rsbac_net_temp_inet_addr_t inet; + struct rsbac_net_temp_other_addr_t other; +}; + +struct rsbac_net_temp_data_t { + /* must be first for alignment */ + union rsbac_net_temp_addr_t address; + __u8 address_family; + __u8 type; + __u8 protocol; + rsbac_netdev_id_t netdev; + struct rsbac_net_temp_ports_t ports; /* for those address families that support them */ + char name[RSBAC_NET_TEMP_NAMELEN]; +}; + +struct rsbac_net_temp_old_data_t { + /* must be first for alignment */ + char address[RSBAC_NET_MAX_ADDRESS_LEN]; + __u8 address_family; + __u8 valid_len; /* Bytes for AF_UNIX, Bits for all others */ + __u8 type; + __u8 protocol; + rsbac_netdev_id_t netdev; + __u16 min_port; /* for those address families that support them */ + __u16 max_port; + char name[RSBAC_NET_TEMP_NAMELEN]; +}; + +#define RSBAC_NET_TEMP_LNET_ID 100101 +#define RSBAC_NET_TEMP_LNET_ADDRESS "127.0.0.0" +#define RSBAC_NET_TEMP_LAN_ID 100102 +#define RSBAC_NET_TEMP_LAN_ADDRESS "192.168.0.0" +#define RSBAC_NET_TEMP_AUTO_ID 100105 +#define RSBAC_NET_TEMP_AUTO_ADDRESS "0.0.0.0" +#define RSBAC_NET_TEMP_INET_ID 100110 +#define RSBAC_NET_TEMP_ALL_ID ((rsbac_net_temp_id_t) -1) + +/* default templates moved into aci_data_structures.c */ + +struct rsbac_net_description_t { + __u8 address_family; + void *address; + __u8 address_len; + __u8 type; + __u8 protocol; + rsbac_netdev_id_t netdev; + __u16 port; +}; + +enum rsbac_net_temp_syscall_t { + NTS_new_template, + NTS_copy_template, + NTS_delete_template, + NTS_check_id, + NTS_get_address, + NTS_get_address_family, + NTS_get_type, + NTS_get_protocol, + NTS_get_netdev, + NTS_get_ports, + NTS_get_name, + NTS_set_address, + NTS_set_address_family, + NTS_set_type, + NTS_set_protocol, + NTS_set_netdev, + NTS_set_ports, + NTS_set_name, + NTS_none +}; + +union rsbac_net_temp_syscall_data_t { + rsbac_net_temp_id_t id; + union rsbac_net_temp_addr_t address; + __u8 address_family; + __u8 type; + __u8 protocol; + rsbac_netdev_id_t netdev; + struct rsbac_net_temp_ports_t ports; /* for those address families that support them */ + char name[RSBAC_NET_TEMP_NAMELEN]; +}; + +/* + * Display an IP address in readable format. + */ + +#ifndef NIPQUAD +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] + +#define HIPQUAD(addr) \ + ((unsigned char *)&addr)[3], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[0] +#endif + +#endif diff --git a/include/rsbac/pax.h b/include/rsbac/pax.h new file mode 100644 index 000000000000..a4bacc7740a9 --- /dev/null +++ b/include/rsbac/pax.h @@ -0,0 +1,21 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2004: Amon Ott */ +/* API: */ +/* Functions for Access */ +/* Control Information / PAX */ +/* Last modified: 12/Jan/2004 */ +/************************************ */ + +#ifndef __RSBAC_PAX_H +#define __RSBAC_PAX_H + +#include + +/***************************************************/ +/* General Prototypes */ +/***************************************************/ + +void rsbac_pax_set_flags_func(struct linux_binprm * bprm); + +#endif diff --git a/include/rsbac/pax_getname.h b/include/rsbac/pax_getname.h new file mode 100644 index 000000000000..e6611d715292 --- /dev/null +++ b/include/rsbac/pax_getname.h @@ -0,0 +1,20 @@ +/********************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2004: */ +/* Amon Ott */ +/* Getname functions for CAP module */ +/* Last modified: 06/Jan/2004 */ +/********************************** */ + +#ifndef __RSBAC_PAX_GETNAME_H +#define __RSBAC_PAX_GETNAME_H + +#include + +char * pax_print_flags(char * string, rsbac_pax_flags_t flags); + +#ifndef __KERNEL__ +rsbac_pax_flags_t pax_strtoflags(char * string, rsbac_pax_flags_t init_flags); +#endif + +#endif diff --git a/include/rsbac/proc_fs.h b/include/rsbac/proc_fs.h new file mode 100644 index 000000000000..8b1e39be0203 --- /dev/null +++ b/include/rsbac/proc_fs.h @@ -0,0 +1,20 @@ +/************************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2001: Amon Ott */ +/* proc fs functions */ +/* Last modified: 17/Jul/2001 */ +/************************************* */ + +#ifndef __RSBAC_PROC_FS_H +#define __RSBAC_PROC_FS_H + +#include + +#ifndef PROC_BLOCK_SIZE +#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ +#endif + +extern struct proc_dir_entry * proc_rsbac_root_p; +extern struct proc_dir_entry * proc_rsbac_backup_p; + +#endif diff --git a/include/rsbac/rc.h b/include/rsbac/rc.h new file mode 100644 index 000000000000..8efdbbb93370 --- /dev/null +++ b/include/rsbac/rc.h @@ -0,0 +1,104 @@ +/******************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2009: */ +/* Amon Ott */ +/* API: Data structures */ +/* and functions for Access */ +/* Control Information / RC */ +/* Last modified: 15/Oct/2009 */ +/******************************* */ + +#ifndef __RSBAC_RC_H +#define __RSBAC_RC_H + +#include +#include + +/***************************************************/ +/* General Prototypes */ +/***************************************************/ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac_error.h. */ + +/****************************************************************************/ +/* Initialization, including ACI restoration for all mounted devices from */ +/* disk. After this call, all ACI is kept in memory for performance reasons.*/ + +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_init_rc(void); +#else +int rsbac_init_rc(void) __init; +#endif + +/* Find the boot role */ +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_rc_get_boot_role(rsbac_rc_role_id_t * role_p); +#else +int rsbac_rc_get_boot_role(rsbac_rc_role_id_t * role_p) __init; +#endif + +/* Some information about the current status is also available */ + +int rsbac_stats_rc(void); + +/************************************************* */ +/* Access functions */ +/************************************************* */ + +/* All these procedures handle the spinlocks to protect the targets during */ +/* access. */ + +/* All roles are always there, so instead of creation, we supply a copy for */ +/* initialization. There is always the well-defined role general to copy */ +int rsbac_rc_copy_role(rsbac_list_ta_number_t ta_number, + rsbac_rc_role_id_t from_role, + rsbac_rc_role_id_t to_role); + +int rsbac_rc_copy_type(rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + rsbac_rc_type_id_t from_type, + rsbac_rc_type_id_t to_type); + +/* Getting item values */ +int rsbac_rc_get_item(rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t tid, + union rsbac_rc_target_id_t subtid, + enum rsbac_rc_item_t item, + union rsbac_rc_item_value_t *value_p, + rsbac_time_t * ttl_p); + +/* Setting item values */ +int rsbac_rc_set_item(rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t tid, + union rsbac_rc_target_id_t subtid, + enum rsbac_rc_item_t item, + union rsbac_rc_item_value_t value, rsbac_time_t ttl); + +/* Checking role's compatibility */ +rsbac_boolean_t rsbac_rc_check_comp(rsbac_rc_role_id_t role, + union rsbac_rc_target_id_t subtid, + enum rsbac_rc_item_t item, + enum rsbac_rc_special_rights_t right); + +/* Checking whether role exists */ +rsbac_boolean_t rsbac_rc_role_exists(rsbac_list_ta_number_t ta_number, + rsbac_rc_role_id_t role); + +rsbac_boolean_t rsbac_rc_type_exists(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + rsbac_rc_type_id_t type); + +/* Get list of defined items. Returns number or negative error. + * Allocates array via rsbac_kmalloc, if number > 0 - rsbac_kfree after use! */ +int rsbac_rc_get_list(rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t tid, + enum rsbac_rc_item_t item, + __u32 ** array_pp, rsbac_time_t ** ttl_array_pp); + +int rsbac_rc_select_fd_create_type(rsbac_rc_type_id_t type); + +#endif diff --git a/include/rsbac/rc_data_structures.h b/include/rsbac/rc_data_structures.h new file mode 100644 index 000000000000..022497db2e1f --- /dev/null +++ b/include/rsbac/rc_data_structures.h @@ -0,0 +1,352 @@ +/*********************************/ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: */ +/* Amon Ott */ +/* Data structures for Role */ +/* Compatibility module */ +/* Last modified: 07/Jan/2016 */ +/*********************************/ + + +#ifndef __RSBAC_RC_DATA_STRUC_H +#define __RSBAC_RC_DATA_STRUC_H + +#ifdef __KERNEL__ /* only include in kernel code */ +#include +#include +#endif /* __KERNEL__ */ + +/* First of all we define dirname and filenames for saving the roles to disk. */ +/* The path must be a valid single dir name! Each mounted device gets its */ +/* own file set, residing in 'DEVICE_ROOT/RSBAC_ACI_PATH/'. */ +/* All user access to these files will be denied. */ +/* Backups are kept in FILENAMEb. */ + +#ifdef __KERNEL__ +#define RSBAC_RC_LIST_KEY 77788855 + +#define RSBAC_RC_NR_ROLE_LIST_HASH_BITS 2 +#define RSBAC_RC_NR_TYPE_LIST_HASH_BITS 2 + +/* roles */ +#define RSBAC_RC_ROLE_FILENAME "rc_r" + +/* roles we are compatible with ( = we can change to) */ +#define RSBAC_RC_ROLE_RC_FILENAME "rc_rc" + +/* roles we may administrate (replaces admin_type) */ +#define RSBAC_RC_ROLE_ADR_FILENAME "rc_adr" + +/* roles we may read and assign to users, if they were in one of these before. */ +#define RSBAC_RC_ROLE_ASR_FILENAME "rc_asr" + +/* file/dir/fifo/symlink types for new items, by parent efftype */ +/* If not found, use old global value def_fd_create_type */ +#define RSBAC_RC_ROLE_DFDC_FILENAME "rc_dfdc" + +/* file/dir/fifo/symlink types and requests we are compatible with */ +#define RSBAC_RC_ROLE_TCFD_FILENAME "rc_tcfd" + +/* dev types and requests we are compatible with */ +#define RSBAC_RC_ROLE_TCDV_FILENAME "rc_tcdv" + +/* user types and requests we are compatible with */ +#define RSBAC_RC_ROLE_TCUS_FILENAME "rc_tcus" + +/* process types and requests we are compatible with */ +#define RSBAC_RC_ROLE_TCPR_FILENAME "rc_tcpr" + +/* IPC types and requests we are compatible with */ +#define RSBAC_RC_ROLE_TCIP_FILENAME "rc_tcip" + +/* SCD types and requests we are compatible with */ +#define RSBAC_RC_ROLE_TCSC_FILENAME "rc_tcsc" + +/* group types and requests we are compatible with */ +#define RSBAC_RC_ROLE_TCGR_FILENAME "rc_tcgr" + +/* NETDEV types and requests we are compatible with */ +#define RSBAC_RC_ROLE_TCND_FILENAME "rc_tcnd" + +/* NETTEMP types and requests we are compatible with */ +#define RSBAC_RC_ROLE_TCNT_FILENAME "rc_tcnt" + +/* NETOBJ types and requests we are compatible with */ +#define RSBAC_RC_ROLE_TCNO_FILENAME "rc_tcno" + +#define RSBAC_RC_ROLE_LIST_VERSION 5 +#define RSBAC_RC_ROLE_OLD_LIST_VERSION 4 +#define RSBAC_RC_ROLE_OLD_OLD_LIST_VERSION 3 +#define RSBAC_RC_ROLE_OLD_OLD_OLD_LIST_VERSION 2 +#define RSBAC_RC_ROLE_OLD_OLD_OLD_OLD_LIST_VERSION 1 +#define RSBAC_RC_ROLE_RC_LIST_VERSION 1 +#define RSBAC_RC_ROLE_ADR_LIST_VERSION 1 +#define RSBAC_RC_ROLE_ASR_LIST_VERSION 1 +#define RSBAC_RC_ROLE_DFDC_LIST_VERSION 1 +#define RSBAC_RC_ROLE_TCFD_LIST_VERSION 2 +#define RSBAC_RC_ROLE_TCDV_LIST_VERSION 2 +#define RSBAC_RC_ROLE_TCUS_LIST_VERSION 2 +#define RSBAC_RC_ROLE_TCPR_LIST_VERSION 2 +#define RSBAC_RC_ROLE_TCIP_LIST_VERSION 2 +#define RSBAC_RC_ROLE_TCSC_LIST_VERSION 2 +#define RSBAC_RC_ROLE_TCGR_LIST_VERSION 2 +#define RSBAC_RC_ROLE_TCND_LIST_VERSION 2 +#define RSBAC_RC_ROLE_TCNT_LIST_VERSION 2 +#define RSBAC_RC_ROLE_TCNO_LIST_VERSION 2 +#define RSBAC_RC_ROLE_TCFD_OLD_LIST_VERSION 1 +#define RSBAC_RC_ROLE_TCDV_OLD_LIST_VERSION 1 +#define RSBAC_RC_ROLE_TCUS_OLD_LIST_VERSION 1 +#define RSBAC_RC_ROLE_TCPR_OLD_LIST_VERSION 1 +#define RSBAC_RC_ROLE_TCIP_OLD_LIST_VERSION 1 +#define RSBAC_RC_ROLE_TCSC_OLD_LIST_VERSION 1 +#define RSBAC_RC_ROLE_TCGR_OLD_LIST_VERSION 1 +#define RSBAC_RC_ROLE_TCND_OLD_LIST_VERSION 1 +#define RSBAC_RC_ROLE_TCNT_OLD_LIST_VERSION 1 +#define RSBAC_RC_ROLE_TCNO_OLD_LIST_VERSION 1 + +#define RSBAC_RC_TYPE_FD_FILENAME "rc_tfd" +#define RSBAC_RC_TYPE_DEV_FILENAME "rc_tdv" +#define RSBAC_RC_TYPE_IPC_FILENAME "rc_tip" +#define RSBAC_RC_TYPE_USER_FILENAME "rc_tus" +#define RSBAC_RC_TYPE_PROCESS_FILENAME "rc_tpr" +#define RSBAC_RC_TYPE_GROUP_FILENAME "rc_tgr" +#define RSBAC_RC_TYPE_NETDEV_FILENAME "rc_tnd" +#define RSBAC_RC_TYPE_NETTEMP_FILENAME "rc_tnt" +#define RSBAC_RC_TYPE_NETOBJ_FILENAME "rc_tno" + +#define RSBAC_RC_TYPE_FD_LIST_VERSION 1 +#define RSBAC_RC_TYPE_DEV_LIST_VERSION 1 +#define RSBAC_RC_TYPE_IPC_LIST_VERSION 1 +#define RSBAC_RC_TYPE_USER_LIST_VERSION 1 +#define RSBAC_RC_TYPE_PROCESS_LIST_VERSION 1 +#define RSBAC_RC_TYPE_GROUP_LIST_VERSION 1 +#define RSBAC_RC_TYPE_NETDEV_LIST_VERSION 1 +#define RSBAC_RC_TYPE_NETTEMP_LIST_VERSION 1 +#define RSBAC_RC_TYPE_NETOBJ_LIST_VERSION 1 +#endif /* __KERNEL__ */ + +/* + * The following structures provide the role model data structures. + * All RSBAC_RC_NR_ROLES roles and RSBAC_RC_NR_TYPES x target-no. types + * and SCD-type definitions are kept in arrays and saved to disk as such. + */ + +/*************************************** + * Roles * + ***************************************/ + +/* Caution: whenever role struct changes, version and old_version must be increased! */ + +struct rsbac_rc_role_entry_t { + rsbac_enum_t admin_type; /* role admin: none, system or role admin? */ + char name[RSBAC_RC_NAME_LEN]; + rsbac_rc_type_id_t def_fd_create_type; + rsbac_rc_type_id_t def_user_create_type; + rsbac_rc_type_id_t def_process_create_type; + rsbac_rc_type_id_t def_process_chown_type; + rsbac_rc_type_id_t def_process_execute_type; + rsbac_rc_type_id_t def_ipc_create_type; + rsbac_rc_type_id_t def_group_create_type; + rsbac_rc_type_id_t def_unixsock_create_type; + rsbac_enum_t boot_role; + rsbac_enum_t req_reauth; +}; + +struct rsbac_rc_old_role_entry_t { + rsbac_enum_t admin_type; /* role admin: none, system or role admin? */ + char name[RSBAC_RC_NAME_LEN]; + rsbac_rc_type_id_t def_fd_create_type; + rsbac_rc_type_id_t def_user_create_type; + rsbac_rc_type_id_t def_process_create_type; + rsbac_rc_type_id_t def_process_chown_type; + rsbac_rc_type_id_t def_process_execute_type; + rsbac_rc_type_id_t def_ipc_create_type; + rsbac_rc_type_id_t def_group_create_type; + rsbac_enum_t boot_role; + rsbac_enum_t req_reauth; +}; + +struct rsbac_rc_old_old_role_entry_t { + rsbac_enum_t admin_type; /* role admin: none, system or role admin? */ + char name[RSBAC_RC_NAME_LEN]; + rsbac_rc_type_id_t def_fd_create_type; + rsbac_rc_type_id_t def_user_create_type; + rsbac_rc_type_id_t def_process_create_type; + rsbac_rc_type_id_t def_process_chown_type; + rsbac_rc_type_id_t def_process_execute_type; + rsbac_rc_type_id_t def_ipc_create_type; + rsbac_rc_type_id_t def_group_create_type; + rsbac_enum_t boot_role; +}; + +struct rsbac_rc_old_old_old_role_entry_t { + rsbac_enum_t admin_type; /* role admin: none, system or role admin? */ + char name[RSBAC_RC_NAME_LEN]; + rsbac_rc_type_id_t def_fd_create_type; + rsbac_rc_type_id_t def_user_create_type; + rsbac_rc_type_id_t def_process_create_type; + rsbac_rc_type_id_t def_process_chown_type; + rsbac_rc_type_id_t def_process_execute_type; + rsbac_rc_type_id_t def_ipc_create_type; + rsbac_enum_t boot_role; +}; + +struct rsbac_rc_old_old_old_old_role_entry_t { + rsbac_enum_t admin_type; /* role admin: none, system or role admin? */ + char name[RSBAC_RC_NAME_LEN]; + rsbac_rc_type_id_t def_fd_create_type; + rsbac_rc_type_id_t def_process_create_type; + rsbac_rc_type_id_t def_process_chown_type; + rsbac_rc_type_id_t def_process_execute_type; + rsbac_rc_type_id_t def_ipc_create_type; +}; + +#define RSBAC_RC_NR_ROLE_ENTRY_ITEMS 25 +#define RSBAC_RC_ROLE_ENTRY_ITEM_LIST { \ + RI_role_comp, \ + RI_admin_roles, \ + RI_assign_roles, \ + RI_type_comp_fd, \ + RI_type_comp_dev, \ + RI_type_comp_user, \ + RI_type_comp_process, \ + RI_type_comp_ipc, \ + RI_type_comp_scd, \ + RI_type_comp_group, \ + RI_type_comp_netdev, \ + RI_type_comp_nettemp, \ + RI_type_comp_netobj, \ + RI_admin_type, \ + RI_name, \ + RI_def_fd_create_type, \ + RI_def_fd_ind_create_type, \ + RI_def_user_create_type, \ + RI_def_process_create_type, \ + RI_def_process_chown_type, \ + RI_def_process_execute_type, \ + RI_def_ipc_create_type, \ + RI_def_group_create_type, \ + RI_boot_role, \ + RI_req_reauth \ + } + +/*************************************** + * Type names * + ***************************************/ + +/* Caution: whenever role struct changes, version and old_version must be increased! */ + +/* #define RSBAC_RC_OLD_TYPE_VERSION 1 */ +#define RSBAC_RC_TYPE_VERSION 1 + +struct rsbac_rc_type_fd_entry_t { + char name[RSBAC_RC_NAME_LEN]; + __u8 need_secdel; /* rsbac_boolean_t */ +}; + +#define RSBAC_RC_NR_TYPE_ENTRY_ITEMS 10 +#define RSBAC_RC_TYPE_ENTRY_ITEM_LIST { \ + RI_type_fd_name, \ + RI_type_dev_name, \ + RI_type_ipc_name, \ + RI_type_scd_name, \ + RI_type_process_name, \ + RI_type_group_name, \ + RI_type_netdev_name, \ + RI_type_nettemp_name, \ + RI_type_netobj_name, \ + RI_type_fd_need_secdel \ + } + +/**********************************************/ +/* Default values */ +/**********************************************/ + +#define RSBAC_RC_GENERAL_ROLE_ENTRY \ + { \ + .admin_type = RC_no_admin, \ + .name = "General User", \ + .def_fd_create_type = RC_type_inherit_parent, \ + .def_user_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_process_create_type = RC_type_inherit_parent, \ + .def_process_chown_type = RC_type_use_new_role_def_create, \ + .def_process_execute_type = RC_type_inherit_parent, \ + .def_ipc_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_group_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_unixsock_create_type = RC_type_use_fd, \ + .boot_role = FALSE, \ + .req_reauth = FALSE, \ + } + +#define RSBAC_RC_ROLE_ADMIN_ROLE_ENTRY \ + { \ + .admin_type = RC_role_admin, \ + .name = "Role Admin", \ + .def_fd_create_type = RC_type_inherit_parent, \ + .def_user_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_process_create_type = RC_type_inherit_parent, \ + .def_process_chown_type = RC_type_use_new_role_def_create, \ + .def_process_execute_type = RC_type_inherit_parent, \ + .def_ipc_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_group_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_unixsock_create_type = RC_type_use_fd, \ + .boot_role = FALSE, \ + .req_reauth = FALSE, \ + } + +#define RSBAC_RC_SYSTEM_ADMIN_ROLE_ENTRY \ + { \ + .admin_type = RC_system_admin, \ + .name = "System Admin", \ + .def_fd_create_type = RC_type_inherit_parent, \ + .def_user_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_process_create_type = RC_type_inherit_parent, \ + .def_process_chown_type = RC_type_use_new_role_def_create, \ + .def_process_execute_type = RC_type_inherit_parent, \ + .def_ipc_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_group_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_unixsock_create_type = RC_type_use_fd, \ + .boot_role = FALSE, \ + .req_reauth = FALSE, \ + } + +#define RSBAC_RC_BOOT_ROLE_ENTRY \ + { \ + .admin_type = RC_no_admin, \ + .name = "System Boot", \ + .def_fd_create_type = RC_type_inherit_parent, \ + .def_user_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_process_create_type = RC_type_inherit_parent, \ + .def_process_chown_type = RC_type_use_new_role_def_create, \ + .def_process_execute_type = RC_type_inherit_parent, \ + .def_ipc_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_group_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_unixsock_create_type = RC_type_use_fd, \ + .boot_role = TRUE, \ + .req_reauth = FALSE, \ + } + +#define RSBAC_RC_AUDITOR_ROLE_ENTRY \ + { \ + .admin_type = RC_no_admin, \ + .name = "Auditor", \ + .def_fd_create_type = RC_type_inherit_parent, \ + .def_user_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_process_create_type = RC_type_inherit_parent, \ + .def_process_chown_type = RC_type_use_new_role_def_create, \ + .def_process_execute_type = RC_type_inherit_parent, \ + .def_ipc_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_group_create_type = RSBAC_RC_GENERAL_TYPE, \ + .def_unixsock_create_type = RC_type_use_fd, \ + .boot_role = FALSE, \ + .req_reauth = FALSE, \ + } + +/**********************************************/ +/* Declarations */ +/**********************************************/ + +#ifdef __KERNEL__ +#endif /* __KERNEL__ */ + +#endif /* __RSBAC_RC_DATA_STRUC_H */ diff --git a/include/rsbac/rc_getname.h b/include/rsbac/rc_getname.h new file mode 100644 index 000000000000..562fa20987aa --- /dev/null +++ b/include/rsbac/rc_getname.h @@ -0,0 +1,44 @@ +/******************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999: Amon Ott */ +/* Getname functions for RC parts */ +/* Last modified: 18/Jan/99 */ +/******************************** */ + +#ifndef __RSBAC_RC_GETNAME_H +#define __RSBAC_RC_GETNAME_H + +#include + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +char *get_rc_target_name(char *name, enum rsbac_rc_target_t value); + +enum rsbac_rc_target_t get_rc_target_nr(const char *name); + +char *get_rc_admin_name(char *name, enum rsbac_rc_admin_type_t value); + +enum rsbac_rc_admin_type_t get_rc_admin_nr(const char *name); + +char *get_rc_scd_type_name(char *name, enum rsbac_rc_scd_type_t value); + +enum rsbac_rc_scd_type_t get_rc_scd_type_nr(const char *name); + +char *get_rc_item_name(char *name, enum rsbac_rc_item_t value); + +enum rsbac_rc_item_t get_rc_item_nr(const char *name); + +#ifndef __KERNEL__ +char *get_rc_item_param(char *name, enum rsbac_rc_item_t value); +#endif + +char *get_rc_special_right_name(char *name, + enum rsbac_rc_special_rights_t value); + +#ifndef __KERNEL__ +enum rsbac_rc_special_rights_t get_rc_special_right_nr(const char *name); +#endif + +#endif diff --git a/include/rsbac/rc_types.h b/include/rsbac/rc_types.h new file mode 100644 index 000000000000..29b1855df9b8 --- /dev/null +++ b/include/rsbac/rc_types.h @@ -0,0 +1,387 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: Amon Ott */ +/* API: Data types for */ +/* Role Compatibility Module */ +/* Last modified: 17/Feb/2016 */ +/************************************ */ + +#ifndef __RSBAC_RC_TYPES_H +#define __RSBAC_RC_TYPES_H + +#include + +/***** RC *****/ + +#define RSBAC_RC_GENERAL_ROLE 0 +#define RSBAC_RC_ROLE_ADMIN_ROLE 1 +#define RSBAC_RC_SYSTEM_ADMIN_ROLE 2 +#define RSBAC_RC_AUDITOR_ROLE 3 +#define RSBAC_RC_BOOT_ROLE 999999 +#define RSBAC_RC_GENERAL_TYPE 0 +#define RSBAC_RC_SEC_TYPE 1 +#define RSBAC_RC_SYS_TYPE 2 +#define RSBAC_RC_KERNEL_P_TYPE 999999 + +#define RSBAC_RC_NAME_LEN 16 +#define RSBAC_RC_ALL_REQUESTS ((rsbac_rc_request_vector_t) -1) + +#define RSBAC_RC_OLD_SPECIAL_RIGHT_BASE 48 +#define RSBAC_RC_SPECIAL_RIGHT_BASE 56 + +enum rsbac_rc_special_rights_t { RCR_ADMIN = RSBAC_RC_SPECIAL_RIGHT_BASE, + RCR_ASSIGN, + RCR_ACCESS_CONTROL, + RCR_SUPERVISOR, + RCR_MODIFY_AUTH, + RCR_CHANGE_AUTHED_OWNER, + RCR_SELECT, + RCR_MODIFY_UDF, + RCR_NONE +}; + +typedef __u64 rsbac_rc_rights_vector_t; +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +typedef __u64 __attribute__((aligned(4))) rsbac_rc_rights_vector_ia32_t; +#endif + +/* backwards compatibility only! */ +typedef __u64 rsbac_rc_role_vector_t; +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +typedef __u64 __attribute__((aligned(4))) rsbac_rc_role_vector_ia32_t; +#endif + +#define RSBAC_RC_RIGHTS_VECTOR(x) ((rsbac_rc_rights_vector_t) 1 << (x)) +#define RSBAC_RC_ROLE_VECTOR(x) ((rsbac_rc_role_vector_t) 1 << (x)) +#define RSBAC_RC_TYPE_VECTOR(x) ((rsbac_rc_type_vector_t) 1 << (x)) + +#define RSBAC_RC_SPECIAL_RIGHTS_VECTOR (\ + RSBAC_RC_RIGHTS_VECTOR(RCR_ADMIN) | \ + RSBAC_RC_RIGHTS_VECTOR(RCR_ASSIGN) | \ + RSBAC_RC_RIGHTS_VECTOR(RCR_ACCESS_CONTROL) | \ + RSBAC_RC_RIGHTS_VECTOR(RCR_SUPERVISOR) | \ + RSBAC_RC_RIGHTS_VECTOR(RCR_MODIFY_AUTH) | \ + RSBAC_RC_RIGHTS_VECTOR(RCR_CHANGE_AUTHED_OWNER) | \ + RSBAC_RC_RIGHTS_VECTOR(RCR_SELECT) | \ + RSBAC_RC_RIGHTS_VECTOR(RCR_MODIFY_UDF) \ + ) + +#define RSBAC_RC_SUPERVISOR_RIGHT_VECTOR (\ + RSBAC_RC_RIGHTS_VECTOR(RCR_SUPERVISOR) | \ + ) + +#define RSBAC_RC_ALL_RIGHTS_VECTOR (RSBAC_ALL_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR) + +#define RSBAC_RC_PROCESS_RIGHTS_VECTOR (RSBAC_PROCESS_REQUEST_VECTOR | \ + RSBAC_RC_RIGHTS_VECTOR(R_CONNECT) | \ + RSBAC_RC_RIGHTS_VECTOR(R_ACCEPT) | \ + RSBAC_RC_RIGHTS_VECTOR(R_SEND) | \ + RSBAC_RC_RIGHTS_VECTOR(R_RECEIVE) \ +) + +#define RSBAC_RC_DEFAULT_RIGHTS_VECTOR 0 + +#define RSBAC_RC_GEN_RIGHTS_VECTOR RSBAC_RC_DEFAULT_RIGHTS_VECTOR + +typedef __u32 rsbac_rc_role_id_t; +typedef __u32 rsbac_rc_type_id_t; +typedef rsbac_request_vector_t rsbac_rc_request_vector_t; + +enum rsbac_rc_admin_type_t { RC_no_admin, RC_role_admin, RC_system_admin, + RC_none }; + +/* + * System Control Types, including general SCD types + * (start at 32 to allow future SCD types, max is 63) + */ +#define RST_min 32 +enum rsbac_rc_scd_type_t { RST_auth_administration = RST_min, + RST_udf_administration, + RST_none +}; + +/* what should always be there to keep system functional */ +#ifdef CONFIG_RSBAC_USER_MOD_IOPERM +#define RSBAC_RC_GENERAL_COMP_SCD { \ + 0, \ + 0, \ + 0, \ + 0, \ + /* ST_ioports */ ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA), \ + /* ST_rlimit */ RSBAC_REQUEST_VECTOR(GET_STATUS_DATA) | RSBAC_REQUEST_VECTOR(MODIFY_SYSTEM_DATA), \ + /* ST_swap */ 0, \ + /* ST_syslog */ 0, \ + /* ST_rsbac */ 0, \ + /* ST_rsbac_log */ 0, \ + /* ST_other */ ( \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + ), \ + /* ST_kmem */ 0, \ + /* ST_network */ ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA), \ + /* 13 = ST_none */ 0 \ + } +#else +#define RSBAC_RC_GENERAL_COMP_SCD { \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + /* ST_rlimit */ RSBAC_REQUEST_VECTOR(GET_STATUS_DATA) | RSBAC_REQUEST_VECTOR(MODIFY_SYSTEM_DATA), \ + /* ST_swap */ 0, \ + /* ST_syslog */ 0, \ + /* ST_rsbac */ 0, \ + /* ST_rsbac_log */ 0, \ + /* ST_other */ ( \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + ), \ + /* ST_kmem */ 0, \ + /* ST_network */ ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA), \ + /* ST_firewall */ 0, \ + /* ST_priority */ 0, \ + /* 15 = ST_none */ 0 \ + } +#endif + +#define RSBAC_RC_ROLEADM_COMP_SCD { \ + /* 0 = ST_time_structs */ 0, \ + /* ST_clock */ 0, \ + /* ST_host_id */ 0, \ + /* ST_net_id */ 0, \ + /* ST_ioports */ 0, \ + /* ST_rlimit */ RSBAC_SCD_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR, \ + /* ST_swap */ 0, \ + /* ST_syslog */ 0, \ + /* ST_rsbac */ RSBAC_SCD_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR, \ + /* ST_rsbac_log */ RSBAC_SCD_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR, \ + /* ST_other */ ( \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + | ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) \ + | ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) \ + | ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) \ + | ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) \ + ) | RSBAC_RC_SPECIAL_RIGHTS_VECTOR, \ + /* ST_kmem */ 0, \ + /* ST_network */ ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | RSBAC_RC_SPECIAL_RIGHTS_VECTOR, \ + /* ST_firewall */ ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | RSBAC_RC_SPECIAL_RIGHTS_VECTOR, \ + /* ST_nice */ 0, \ + /* 15 = ST_none */ 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + /* 20 */ 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + /* 30 */ 0, \ + 0, \ + /* 32 = RST_auth_admin */ RSBAC_SCD_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR, \ + /* 33 = RST_udf_admin */ RSBAC_SCD_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR, \ + /* 34 = RST_none */ 0 \ + } + +#define RSBAC_RC_SYSADM_COMP_SCD { \ + /* 0 = ST_time_structs */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* ST_clock */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* ST_host_id */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* ST_net_id */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* ST_ioports */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* ST_rlimit */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* ST_swap */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* ST_syslog */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* ST_rsbac */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* ST_rsbac_log */ 0, \ + /* ST_other */ ( \ + ((rsbac_request_vector_t) 1 << R_ADD_TO_KERNEL) \ + | ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) \ + | ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + | ((rsbac_request_vector_t) 1 << R_MOUNT) \ + | ((rsbac_request_vector_t) 1 << R_REMOVE_FROM_KERNEL) \ + | ((rsbac_request_vector_t) 1 << R_UMOUNT) \ + | ((rsbac_request_vector_t) 1 << R_SHUTDOWN) \ + ), \ + /* ST_kmem */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* ST_network */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* ST_firewall */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* ST_priority */ RSBAC_SCD_REQUEST_VECTOR & RSBAC_SYSTEM_REQUEST_VECTOR, \ + /* 15 = ST_none */ 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + /* 20 */ 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + /* 30 */ 0, \ + 0, \ + /* 32 = RST_auth_admin */ 0, \ + /* 33 = RST_udf_admin */ 0, \ + /* 34 = RST_none */ 0 \ + } +#ifdef CONFIG_RSBAC_USER_MOD_IOPERM +#define RSBAC_RC_AUDITOR_COMP_SCD { \ + 0, \ + 0, \ + 0, \ + 0, \ + /* ST_ioports */ ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA), \ + /* ST_rlimit */ RSBAC_REQUEST_VECTOR(GET_STATUS_DATA) | RSBAC_REQUEST_VECTOR(MODIFY_SYSTEM_DATA), \ + /* ST_swap */ 0, \ + /* ST_syslog */ 0, \ + /* ST_rsbac */ 0, \ + /* ST_rsbac_log */ ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA), \ + /* ST_other */ ( \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + ), \ + /* ST_kmem */ 0, \ + /* ST_network */ ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA), \ + /* ST_firewall */ 0, \ + /* ST_priority */ 0, \ + /* 15 = ST_none */ 0 \ + } +#else +#define RSBAC_RC_AUDITOR_COMP_SCD { \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + /* ST_rlimit */ RSBAC_REQUEST_VECTOR(GET_STATUS_DATA) | RSBAC_REQUEST_VECTOR(MODIFY_SYSTEM_DATA), \ + /* ST_swap */ 0, \ + /* ST_syslog */ 0, \ + /* ST_rsbac */ 0, \ + /* ST_rsbac_log */ ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA), \ + /* ST_other */ ( \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + ), \ + /* ST_kmem */ 0, \ + /* ST_network */ ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA), \ + /* ST_firewall */ 0, \ + /* ST_priority */ 0, \ + /* 15 = ST_none */ 0 \ + } +#endif + + +#define RC_type_inherit_process ((rsbac_rc_type_id_t) -1) +#define RC_type_inherit_parent ((rsbac_rc_type_id_t) -2) +#define RC_type_no_create ((rsbac_rc_type_id_t) -3) +#define RC_type_no_execute ((rsbac_rc_type_id_t) -4) +#define RC_type_use_new_role_def_create ((rsbac_rc_type_id_t) -5) /* for process chown (setuid) */ +#define RC_type_no_chown ((rsbac_rc_type_id_t) -6) +#define RC_type_use_fd ((rsbac_rc_type_id_t) -7) +#define RC_type_min_special ((rsbac_rc_type_id_t) -7) +#define RC_type_max_value ((rsbac_rc_type_id_t) -32) + +#define RC_role_inherit_user ((rsbac_rc_role_id_t) -1) +#define RC_role_inherit_process ((rsbac_rc_role_id_t) -2) +#define RC_role_inherit_parent ((rsbac_rc_role_id_t) -3) +#define RC_role_inherit_up_mixed ((rsbac_rc_role_id_t) -4) +#define RC_role_use_force_role ((rsbac_rc_role_id_t) -5) +#define RC_role_min_special ((rsbac_rc_role_id_t) -5) +#define RC_role_max_value ((rsbac_rc_role_id_t) -32) + +#define RC_default_force_role RC_role_inherit_parent +#define RC_default_root_dir_force_role RC_role_inherit_up_mixed +#define RC_default_init_force_role RC_role_inherit_user +#define RC_default_initial_role RC_role_inherit_parent +#define RC_default_root_dir_initial_role RC_role_use_force_role + +/****************************************************************************/ +/* RC ACI types */ +/****************************************************************************/ + +enum rsbac_rc_target_t { RT_ROLE, RT_TYPE, RT_NONE }; + +union rsbac_rc_target_id_t { + rsbac_rc_role_id_t role; + rsbac_rc_type_id_t type; +}; + +enum rsbac_rc_item_t { RI_role_comp, + RI_admin_roles, + RI_assign_roles, + RI_type_comp_fd, + RI_type_comp_dev, + RI_type_comp_user, + RI_type_comp_process, + RI_type_comp_ipc, + RI_type_comp_scd, + RI_type_comp_group, + RI_type_comp_netdev, + RI_type_comp_nettemp, + RI_type_comp_netobj, + RI_admin_type, + RI_name, + RI_def_fd_create_type, + RI_def_fd_ind_create_type, + RI_def_user_create_type, + RI_def_process_create_type, + RI_def_process_chown_type, + RI_def_process_execute_type, + RI_def_ipc_create_type, + RI_def_group_create_type, + RI_def_unixsock_create_type, + RI_boot_role, + RI_req_reauth, + RI_type_fd_name, + RI_type_dev_name, + RI_type_ipc_name, + RI_type_user_name, + RI_type_process_name, + RI_type_group_name, + RI_type_netdev_name, + RI_type_nettemp_name, + RI_type_netobj_name, + RI_type_fd_need_secdel, + RI_type_scd_name, /* Pseudo, using get_rc_scd_name() */ + RI_remove_role, + RI_def_fd_ind_create_type_remove, + RI_type_fd_remove, + RI_type_dev_remove, + RI_type_ipc_remove, + RI_type_user_remove, + RI_type_process_remove, + RI_type_group_remove, + RI_type_netdev_remove, + RI_type_nettemp_remove, + RI_type_netobj_remove, +#ifdef __KERNEL__ +#endif + RI_none +}; + +union rsbac_rc_item_value_t { + rsbac_rc_rights_vector_t rights; + enum rsbac_rc_admin_type_t admin_type; + char name[RSBAC_RC_NAME_LEN]; + rsbac_rc_role_id_t role_id; + rsbac_rc_type_id_t type_id; + rsbac_boolean_t need_secdel; + rsbac_boolean_t comp; + rsbac_boolean_t boot_role; + rsbac_boolean_t req_reauth; +#ifdef __KERNEL__ +#endif + u_char u_char_dummy; + int dummy; + u_int u_dummy; + long long_dummy; + long long long_long_dummy; +}; + +#endif diff --git a/include/rsbac/reg.h b/include/rsbac/reg.h new file mode 100644 index 000000000000..cd276a54f8ff --- /dev/null +++ b/include/rsbac/reg.h @@ -0,0 +1,152 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2012: Amon Ott */ +/* API: for REG */ +/* Module Registration */ +/* Last modified: 07/May/2012 */ +/************************************ */ + +#ifndef __RSBAC_REG_H +#define __RSBAC_REG_H + +#include +#include + +#define RSBAC_REG_VERSION 1 + +/***************************************************/ +/* Types */ +/***************************************************/ + +#define RSBAC_REG_NAME_LEN 30 + +/* Decision function */ +typedef \ + int rsbac_reg_request_func_t ( enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +/* Attribute setting / notification function */ +typedef \ + int rsbac_reg_set_attr_func_t ( enum rsbac_adf_request_t, + rsbac_pid_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_target_t, + union rsbac_target_id_t, + enum rsbac_attribute_t, + union rsbac_attribute_value_t, + rsbac_uid_t); /* process owner */ + +/* Whether module wants this file to be overwritten on delete / truncate */ +typedef rsbac_boolean_t rsbac_reg_need_overwrite_func_t(struct dentry * dentry_p); + +/* + * rsbac_reg_write_func_t + * + * Called by rsbac_write function to save all dirty lists, must return number + * of files written or negative error. If auto_write is active, this function + * will be called regularly and allows for asynchronous data writing to disk. + * + * If need_lock is TRUE, a lock_kernel() / unlock_kernel() pair must be used + * around the write function. + */ +typedef int rsbac_reg_write_func_t(rsbac_boolean_t need_lock); + +/* Called on every mount, allows updating of fs based data */ +typedef int rsbac_reg_mount_func_t(kdev_t kdev); + +/* Called on every umount, allows updating of fs based data */ +typedef int rsbac_reg_umount_func_t(kdev_t kdev); + +/* Called on rsbac_reg syscalls for handle syscall_handle */ +/* Generic Syscall interface - note: data is a user space pointer! */ +typedef int rsbac_reg_syscall_func_t(void __user * data); + +/* Status and data structures integrity checking, called from sys_rsbac_check */ +/* correct: if TRUE, errors are corrected, else just report */ +/* check_inode: for inode number based data, check, if inode still exists */ +typedef int rsbac_reg_check_func_t(int correct, int check_inode); + +/*********/ + +struct rsbac_reg_entry_t + { + rsbac_reg_handle_t handle; + char name[RSBAC_REG_NAME_LEN+1]; + rsbac_reg_request_func_t * request_func; + rsbac_reg_set_attr_func_t * set_attr_func; + rsbac_reg_need_overwrite_func_t * need_overwrite_func; + rsbac_reg_write_func_t * write_func; + rsbac_reg_mount_func_t * mount_func; + rsbac_reg_umount_func_t * umount_func; + rsbac_reg_check_func_t * check_func; + rsbac_boolean_t switch_on; /* turned on initially? */ + }; + +struct rsbac_reg_syscall_entry_t + { + rsbac_reg_handle_t registration_handle; + rsbac_reg_handle_t dispatcher_handle; + char name[RSBAC_REG_NAME_LEN+1]; + rsbac_reg_syscall_func_t * syscall_func; + }; + +/***************************************************/ +/* Prototypes */ +/***************************************************/ + +/* See rsbac/types.h for types */ + +/* + * Register an ADF decision module + * Returns given positive handle or negative error code from rsbac/error.h + * Errors: -RSBAC_EINVALIDVALUE (all functions are empty or handle is not positive) + * -RSBAC_EEXISTS (handle exists - choose another one) + * -RSBAC_ECOULDNOTADDITEM (no entry available) + * -RSBAC_EINVALIDVERSION (wrong REG version) + */ + +rsbac_reg_handle_t rsbac_reg_register( rsbac_version_t version, + struct rsbac_reg_entry_t entry); + +/* + * Switch module on or off - for 'normal' modules this is done by general + * function. This is a dummy, if module switching is disabled. + * Returns 0 on success or -EINVALIDTARGET, if handle is invalid. + */ + +int rsbac_reg_switch (rsbac_reg_handle_t handle, rsbac_boolean_t value); + +/* + * Unregister an ADF decision module + * Returns 0 on success or -EINVALIDTARGET, if handle is invalid. + */ + +int rsbac_reg_unregister(rsbac_reg_handle_t handle); + + +/* + * Register a system call + * Returns given positive handle or negative error code from rsbac/error.h + * Errors: -RSBAC_EINVALIDVALUE (function is empty or handle is not positive) + * -RSBAC_EEXISTS (handle exists - choose another one) + * -RSBAC_ECOULDNOTADDITEM (no entry available) + * -RSBAC_EINVALIDVERSION (wrong REG version) + */ + +rsbac_reg_handle_t rsbac_reg_register_syscall( rsbac_version_t version, + struct rsbac_reg_syscall_entry_t entry); + +/* + * Unregister a system call + * Returns 0 on success or -EINVALIDTARGET, if handle is invalid. + */ + +int rsbac_reg_unregister_syscall(rsbac_reg_handle_t handle); + +#endif diff --git a/include/rsbac/reg_main.h b/include/rsbac/reg_main.h new file mode 100644 index 000000000000..c6fe1c43f988 --- /dev/null +++ b/include/rsbac/reg_main.h @@ -0,0 +1,70 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2005: Amon Ott */ +/* REG - Module Registration */ +/* Internal declarations and types */ +/* Last modified: 22/Jul/2005 */ +/************************************ */ + +#ifndef __RSBAC_REG_MAIN_H +#define __RSBAC_REG_MAIN_H + +#include +#include +#include + +#define RSBAC_REG_PROC_NAME "reg_entries" + +/***************************************************/ +/* Types */ +/***************************************************/ + +#ifdef __KERNEL__ + +/* Since all registrations will be organized in double linked lists, we must */ +/* have list items and a list head. */ + +struct rsbac_reg_list_item_t + { + struct rsbac_reg_entry_t entry; + struct rsbac_reg_list_item_t * prev; + struct rsbac_reg_list_item_t * next; + }; + +struct rsbac_reg_sc_list_item_t + { + struct rsbac_reg_syscall_entry_t entry; + struct rsbac_reg_sc_list_item_t * prev; + struct rsbac_reg_sc_list_item_t * next; + }; + +/* To provide consistency we use spinlocks for all list accesses. The */ +/* 'curr' entry is used to avoid repeated lookups for the same item. */ + +struct rsbac_reg_list_head_t + { + struct rsbac_reg_list_item_t * head; + struct rsbac_reg_list_item_t * tail; + struct rsbac_reg_list_item_t * curr; + spinlock_t lock; + int readers; + u_int count; + }; + +struct rsbac_reg_sc_list_head_t + { + struct rsbac_reg_sc_list_item_t * head; + struct rsbac_reg_sc_list_item_t * tail; + struct rsbac_reg_sc_list_item_t * curr; + spinlock_t lock; + int readers; + u_int count; + }; + +#endif /* __KERNEL__ */ + +/***************************************************/ +/* Prototypes */ +/***************************************************/ + +#endif diff --git a/include/rsbac/repl_lists.h b/include/rsbac/repl_lists.h new file mode 100644 index 000000000000..a377685a5c11 --- /dev/null +++ b/include/rsbac/repl_lists.h @@ -0,0 +1,18 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2005: Amon Ott */ +/* Generic lists - internal structures */ +/* Last modified: 04/Apr/2005 */ +/*************************************************** */ + +#ifndef __RSBAC_REPL_LISTS_H +#define __RSBAC_REPL_LISTS_H + +#include + +#define RSBAC_LIST_REPL_PROC_NAME "repl_lists" +#define RSBAC_LIST_REPL_PARTNER_VERSION 1 +#define RSBAC_LIST_REPL_PARTNER_KEY 0x3632f7ae +#define RSBAC_LIST_REPL_PARTNER_FILENAME "replpar" + +#endif diff --git a/include/rsbac/repl_types.h b/include/rsbac/repl_types.h new file mode 100644 index 000000000000..860d258a6544 --- /dev/null +++ b/include/rsbac/repl_types.h @@ -0,0 +1,28 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2005: Amon Ott */ +/* Generic lists - internal structures */ +/* Last modified: 04/Apr/2005 */ +/*************************************************** */ + +#ifndef __RSBAC_REPL_TYPES_H +#define __RSBAC_REPL_TYPES_H + +#include + +#define RSBAC_LIST_REPL_NAME_LEN 16 +#define RSBAC_LIST_REPL_CRYPTKEY_LEN 256 +#define RSBAC_LIST_REPL_CRYPTALGO_LEN 64 + +typedef __u32 rsbac_list_repl_partner_number_t; + +struct rsbac_list_repl_partner_entry_t + { + char name[RSBAC_LIST_REPL_NAME_LEN]; + __u32 ip_addr; + char crypt_algo[RSBAC_LIST_REPL_CRYPTALGO_LEN]; + char crypt_key[RSBAC_LIST_REPL_CRYPTKEY_LEN]; + __u32 crypt_key_len; + }; + +#endif diff --git a/include/rsbac/request_groups.h b/include/rsbac/request_groups.h new file mode 100644 index 000000000000..3812f5e3c937 --- /dev/null +++ b/include/rsbac/request_groups.h @@ -0,0 +1,426 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2010: Amon Ott */ +/* Groups of ADF request for */ +/* administration */ +/* Last modified: 08/Apr/2010 */ +/************************************ */ + +#ifndef __RSBAC_REQUEST_GROUPS_H +#define __RSBAC_REQUEST_GROUPS_H + +#define RSBAC_READ_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_CHDIR) | \ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_SEARCH) | \ + ((rsbac_request_vector_t) 1 << R_TERMINATE) | \ + ((rsbac_request_vector_t) 1 << R_AUTHENTICATE) \ + ) + +#define RSBAC_WRITE_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_ALTER) | \ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CLONE) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_LINK_HARD) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ACCESS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_RENAME) | \ + ((rsbac_request_vector_t) 1 << R_SEND_SIGNAL) | \ + ((rsbac_request_vector_t) 1 << R_TRACE) | \ + ((rsbac_request_vector_t) 1 << R_TRUNCATE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_IOCTL) | \ + ((rsbac_request_vector_t) 1 << R_LOCK) | \ + ((rsbac_request_vector_t) 1 << R_MOVETO) \ + ) + +#define RSBAC_READ_WRITE_REQUEST_VECTOR (\ + RSBAC_READ_REQUEST_VECTOR | \ + ((rsbac_request_vector_t) 1 << R_ALTER) | \ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CLONE) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_LINK_HARD) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ACCESS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_RENAME) | \ + ((rsbac_request_vector_t) 1 << R_SEND_SIGNAL) | \ + ((rsbac_request_vector_t) 1 << R_TRACE) | \ + ((rsbac_request_vector_t) 1 << R_TRUNCATE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_BIND) | \ + ((rsbac_request_vector_t) 1 << R_LISTEN) | \ + ((rsbac_request_vector_t) 1 << R_ACCEPT) | \ + ((rsbac_request_vector_t) 1 << R_CONNECT) | \ + ((rsbac_request_vector_t) 1 << R_SEND) | \ + ((rsbac_request_vector_t) 1 << R_RECEIVE) | \ + ((rsbac_request_vector_t) 1 << R_NET_SHUTDOWN) | \ + ((rsbac_request_vector_t) 1 << R_IOCTL) | \ + ((rsbac_request_vector_t) 1 << R_LOCK) | \ + ((rsbac_request_vector_t) 1 << R_MOVETO) \ + ) + +#define RSBAC_READ_WRITE_OPEN_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) \ + ) + +#define RSBAC_EXECUTE_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + ) + + +#define RSBAC_SYSTEM_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_ADD_TO_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MOUNT) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_REMOVE_FROM_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_SHUTDOWN) | \ + ((rsbac_request_vector_t) 1 << R_UMOUNT) \ + ) + +#define RSBAC_SECURITY_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) \ + ) + +#define RSBAC_FD_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_ADD_TO_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHDIR) | \ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_LINK_HARD) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ACCESS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MOUNT) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_REMOVE_FROM_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_RENAME) | \ + ((rsbac_request_vector_t) 1 << R_SEARCH) | \ + ((rsbac_request_vector_t) 1 << R_TRUNCATE) | \ + ((rsbac_request_vector_t) 1 << R_UMOUNT) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) | \ + ((rsbac_request_vector_t) 1 << R_LISTEN) | \ + ((rsbac_request_vector_t) 1 << R_ACCEPT) | \ + ((rsbac_request_vector_t) 1 << R_CONNECT) | \ + ((rsbac_request_vector_t) 1 << R_SEND) | \ + ((rsbac_request_vector_t) 1 << R_RECEIVE) | \ + ((rsbac_request_vector_t) 1 << R_NET_SHUTDOWN) | \ + ((rsbac_request_vector_t) 1 << R_IOCTL) | \ + ((rsbac_request_vector_t) 1 << R_LOCK) | \ + ((rsbac_request_vector_t) 1 << R_MOVETO) \ + ) + +#define RSBAC_DEV_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_ADD_TO_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MOUNT) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_REMOVE_FROM_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_UMOUNT) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_SEND) | \ + ((rsbac_request_vector_t) 1 << R_IOCTL) \ + ) + +#define RSBAC_IPC_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_ALTER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_NET_SHUTDOWN) | \ + ((rsbac_request_vector_t) 1 << R_BIND) | \ + ((rsbac_request_vector_t) 1 << R_LISTEN) | \ + ((rsbac_request_vector_t) 1 << R_ACCEPT) | \ + ((rsbac_request_vector_t) 1 << R_CONNECT) | \ + ((rsbac_request_vector_t) 1 << R_SEND) | \ + ((rsbac_request_vector_t) 1 << R_RECEIVE) | \ + ((rsbac_request_vector_t) 1 << R_IOCTL) | \ + ((rsbac_request_vector_t) 1 << R_LOCK) \ + ) + +#define RSBAC_SCD_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) \ + ) + +#define RSBAC_USER_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_RENAME) | \ + ((rsbac_request_vector_t) 1 << R_SEARCH) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_AUTHENTICATE) \ + ) + +#define RSBAC_GROUP_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_RENAME) | \ + ((rsbac_request_vector_t) 1 << R_SEARCH) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) \ + ) + +#define RSBAC_PROCESS_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CLONE) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_SEND_SIGNAL) | \ + ((rsbac_request_vector_t) 1 << R_TERMINATE) | \ + ((rsbac_request_vector_t) 1 << R_TRACE) \ + ) + +#define RSBAC_NETDEV_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_BIND) \ + ) + +#define RSBAC_NETTEMP_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) \ + ) + +#define RSBAC_NETOBJ_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_NET_SHUTDOWN) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_BIND) | \ + ((rsbac_request_vector_t) 1 << R_LISTEN) | \ + ((rsbac_request_vector_t) 1 << R_ACCEPT) | \ + ((rsbac_request_vector_t) 1 << R_CONNECT) | \ + ((rsbac_request_vector_t) 1 << R_SEND) | \ + ((rsbac_request_vector_t) 1 << R_RECEIVE) | \ + ((rsbac_request_vector_t) 1 << R_IOCTL) \ + ) + +#define RSBAC_NONE_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_ADD_TO_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_REMOVE_FROM_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_SHUTDOWN) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) | \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) \ + ) + +#define RSBAC_ALL_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_ADD_TO_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_ALTER) | \ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHDIR) | \ + ((rsbac_request_vector_t) 1 << R_CLONE) | \ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) | \ + ((rsbac_request_vector_t) 1 << R_DELETE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_LINK_HARD) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ACCESS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_SYSTEM_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MOUNT) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_READ_ATTRIBUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_READ_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_REMOVE_FROM_KERNEL) | \ + ((rsbac_request_vector_t) 1 << R_RENAME) | \ + ((rsbac_request_vector_t) 1 << R_SEARCH) | \ + ((rsbac_request_vector_t) 1 << R_SEND_SIGNAL) | \ + ((rsbac_request_vector_t) 1 << R_SHUTDOWN) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_LOG) | \ + ((rsbac_request_vector_t) 1 << R_SWITCH_MODULE) | \ + ((rsbac_request_vector_t) 1 << R_TERMINATE) | \ + ((rsbac_request_vector_t) 1 << R_TRACE) | \ + ((rsbac_request_vector_t) 1 << R_TRUNCATE) | \ + ((rsbac_request_vector_t) 1 << R_UMOUNT) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_MAP_EXEC) | \ + ((rsbac_request_vector_t) 1 << R_BIND) | \ + ((rsbac_request_vector_t) 1 << R_LISTEN) | \ + ((rsbac_request_vector_t) 1 << R_ACCEPT) | \ + ((rsbac_request_vector_t) 1 << R_CONNECT) | \ + ((rsbac_request_vector_t) 1 << R_SEND) | \ + ((rsbac_request_vector_t) 1 << R_RECEIVE) | \ + ((rsbac_request_vector_t) 1 << R_NET_SHUTDOWN) | \ + ((rsbac_request_vector_t) 1 << R_IOCTL) | \ + ((rsbac_request_vector_t) 1 << R_LOCK) | \ + ((rsbac_request_vector_t) 1 << R_MOVETO) \ + ) + +/* NW specials */ + +/* NWS == RSBAC_ACL_SUPERVISOR_RIGHT_VECTOR in ACL types */ + +#define RSBAC_NWR_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_EXECUTE) | \ + ((rsbac_request_vector_t) 1 << R_READ_OPEN) \ + ) + +#define RSBAC_NWW_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_ALTER) | \ + ((rsbac_request_vector_t) 1 << R_APPEND_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_TRUNCATE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE) | \ + ((rsbac_request_vector_t) 1 << R_WRITE_OPEN) | \ + ((rsbac_request_vector_t) 1 << R_MOVETO) \ + ) + +#define RSBAC_NWC_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_CREATE) \ + ) + +#define RSBAC_NWE_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_DELETE) \ + ) + +/* NWA == RSBAC_ACL_ACCESS_CONTROL_RIGHT_VECTOR in ACL types */ + +#define RSBAC_NWF_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_CHDIR) | \ + ((rsbac_request_vector_t) 1 << R_CLOSE) | \ + ((rsbac_request_vector_t) 1 << R_GET_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_GET_STATUS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_READ) | \ + ((rsbac_request_vector_t) 1 << R_SEARCH) \ + ) + +#define RSBAC_NWM_REQUEST_VECTOR (\ + ((rsbac_request_vector_t) 1 << R_CHANGE_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_GROUP) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_EFF_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_CHANGE_DAC_FS_OWNER) | \ + ((rsbac_request_vector_t) 1 << R_LINK_HARD) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_ACCESS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_MODIFY_PERMISSIONS_DATA) | \ + ((rsbac_request_vector_t) 1 << R_RENAME) \ + ) + +#endif diff --git a/include/rsbac/res_getname.h b/include/rsbac/res_getname.h new file mode 100644 index 000000000000..37512adf2777 --- /dev/null +++ b/include/rsbac/res_getname.h @@ -0,0 +1,20 @@ +/********************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 2002: */ +/* Amon Ott */ +/* Getname functions for RES module */ +/* Last modified: 22/Nov/2002 */ +/********************************** */ + +#ifndef __RSBAC_RES_GETNAME_H +#define __RSBAC_RES_GETNAME_H + +#include + +#ifndef __KERNEL__ +char * get_res_name(char * name, + u_int value); +int get_res_nr(const char * name); +#endif + +#endif diff --git a/include/rsbac/rkmem.h b/include/rsbac/rkmem.h new file mode 100644 index 000000000000..b0f5f487712f --- /dev/null +++ b/include/rsbac/rkmem.h @@ -0,0 +1,76 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2015: Amon Ott */ +/* Memory allocation */ +/* Last modified: 19/Dec/2015 */ +/*************************************************** */ + +#ifndef __RSBAC_RKMEM_H +#define __RSBAC_RKMEM_H + +#include +#include +#include + +#define RSBAC_MAX_KMALLOC KMALLOC_MAX_SIZE +#define RSBAC_MAX_SLABNAME 32 + +/* alloc mem spinlock safe with GFP_ATOMIC */ +void * rsbac_kmalloc (size_t size); +void * rsbac_kmalloc_clear (size_t size); + +/* alloc outside locks with GFP_KERNEL */ +void * rsbac_kmalloc_unlocked (size_t size); +void * rsbac_kmalloc_clear_unlocked (size_t size); + +void rsbac_kfree (const void * objp); + +/* Separate slabs for RSBAC */ + +/* name must stay available until after destroy, keep locally */ +static inline struct kmem_cache * rsbac_slab_create( + const char * name, + size_t size) { + return kmem_cache_create(name, size, 0, 0, NULL); +} +static inline struct kmem_cache * rsbac_slab_create_rcu( + const char * name, + size_t size) { + return kmem_cache_create(name, size, 0, SLAB_TYPESAFE_BY_RCU, NULL); +} + +/* remember to free up name after calling, if it has been allocated */ +static inline void rsbac_slab_destroy(struct kmem_cache * cache) +{ + kmem_cache_destroy(cache); +} + +static inline void * rsbac_smalloc(struct kmem_cache * cache) +{ + return kmem_cache_alloc(cache, GFP_ATOMIC); +} + +static inline void * rsbac_smalloc_clear(struct kmem_cache * cache) +{ + return kmem_cache_alloc(cache, GFP_ATOMIC | __GFP_ZERO); +} + +static inline void * rsbac_smalloc_unlocked(struct kmem_cache * cache) +{ + return kmem_cache_alloc(cache, GFP_KERNEL); +} + +static inline void * rsbac_smalloc_clear_unlocked(struct kmem_cache * cache) +{ + return kmem_cache_alloc(cache, GFP_KERNEL | __GFP_ZERO); +} + +static inline void rsbac_sfree(struct kmem_cache * cache, void * mem) +{ + if (cache) + kmem_cache_free(cache, mem); + else + rsbac_kfree(mem); +} + +#endif diff --git a/include/rsbac/syscall_rsbac.h b/include/rsbac/syscall_rsbac.h new file mode 100644 index 000000000000..8ceb81dc4321 --- /dev/null +++ b/include/rsbac/syscall_rsbac.h @@ -0,0 +1,37 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* */ +/* Author and (c) 1999-2004: */ +/* Amon Ott */ +/* */ +/* System Calls */ +/* */ +/* Last modified: 13/Apr/2004 */ +/************************************ */ + +#ifndef __RSBAC_SYSCALL_RSBAC_H +#define __RSBAC_SYSCALL_RSBAC_H + +/* to keep include/asm-alpha/unistd.h happy */ +//#define __LIBRARY__ + +#include +#include +#include + +#ifdef __PIC__ +#undef _syscall3 +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ + type name(type1 arg1,type2 arg2,type3 arg3) \ +{\ + return syscall(__NR_##name, arg1, arg2, arg3);\ +} +#endif + +static inline _syscall3(int, rsbac, + rsbac_version_t, version, + enum rsbac_syscall_t, call, + union rsbac_syscall_arg_t *, arg_p); + +#define sys_rsbac(a,b,c) rsbac(a,b,c) +#endif diff --git a/include/rsbac/syscalls.h b/include/rsbac/syscalls.h new file mode 100644 index 000000000000..f7c943af52ba --- /dev/null +++ b/include/rsbac/syscalls.h @@ -0,0 +1,1860 @@ +/************************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: */ +/* Amon Ott */ +/* Syscall wrapper functions for all */ +/* parts */ +/* Last modified: 19/Sep/2016 */ +/************************************* */ + +#ifndef __RSBAC_SYSCALLS_H +#define __RSBAC_SYSCALLS_H + +#include +#include +#include +#include +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +#include +#endif + +enum rsbac_syscall_t + { + RSYS_version, + RSYS_stats, + RSYS_check, + RSYS_get_attr, + RSYS_get_attr_n, + RSYS_set_attr, + RSYS_set_attr_n, + RSYS_remove_target, + RSYS_remove_target_n, + RSYS_net_list_all_netdev, + RSYS_net_template, + RSYS_net_list_all_template, + RSYS_switch, + RSYS_get_switch, + RSYS_adf_log_switch, + RSYS_get_adf_log, + RSYS_write, + RSYS_log, + RSYS_mac_set_curr_level, + RSYS_mac_get_curr_level, + RSYS_mac_get_max_level, + RSYS_mac_get_min_level, + RSYS_mac_add_p_tru, + RSYS_mac_remove_p_tru, + RSYS_mac_add_f_tru, + RSYS_mac_remove_f_tru, + RSYS_mac_get_f_trulist, + RSYS_mac_get_p_trulist, + RSYS_stats_pm, + RSYS_pm, + RSYS_pm_change_current_task, + RSYS_pm_create_file, + RSYS_daz_flush_cache, + RSYS_rc_copy_role, + RSYS_rc_copy_type, + RSYS_rc_get_item, + RSYS_rc_set_item, + RSYS_rc_change_role, + RSYS_rc_get_eff_rights_n, + RSYS_rc_get_list, + RSYS_auth_add_p_cap, + RSYS_auth_remove_p_cap, + RSYS_auth_add_f_cap, + RSYS_auth_remove_f_cap, + RSYS_auth_get_f_caplist, + RSYS_auth_get_p_caplist, + RSYS_acl, + RSYS_acl_n, + RSYS_acl_get_rights, + RSYS_acl_get_rights_n, + RSYS_acl_get_tlist, + RSYS_acl_get_tlist_n, + RSYS_acl_get_mask, + RSYS_acl_get_mask_n, + RSYS_acl_group, + RSYS_reg, + RSYS_jail, + RSYS_init, + RSYS_rc_get_current_role, + RSYS_um_auth_name, + RSYS_um_auth_uid, + RSYS_um_add_user, + RSYS_um_add_group, + RSYS_um_add_gm, + RSYS_um_mod_user, + RSYS_um_mod_group, + RSYS_um_get_user_item, + RSYS_um_get_group_item, + RSYS_um_remove_user, + RSYS_um_remove_group, + RSYS_um_remove_gm, + RSYS_um_user_exists, + RSYS_um_group_exists, + RSYS_um_get_next_user, + RSYS_um_get_user_list, + RSYS_um_get_gm_list, + RSYS_um_get_gm_user_list, + RSYS_um_get_group_list, + RSYS_um_get_uid, + RSYS_um_get_gid, + RSYS_um_set_pass, + RSYS_um_set_pass_name, + RSYS_um_set_group_pass, + RSYS_um_check_account, + RSYS_um_check_account_name, + RSYS_list_ta_begin, + RSYS_list_ta_refresh, + RSYS_list_ta_commit, + RSYS_list_ta_forget, + RSYS_list_all_dev, + RSYS_acl_list_all_dev, + RSYS_list_all_user, + RSYS_acl_list_all_user, + RSYS_list_all_group, + RSYS_acl_list_all_group, + RSYS_list_all_ipc, + RSYS_rc_select_fd_create_type, + RSYS_um_select_vset, + RSYS_um_add_onetime, + RSYS_um_add_onetime_name, + RSYS_um_remove_all_onetime, + RSYS_um_remove_all_onetime_name, + RSYS_um_count_onetime, + RSYS_um_count_onetime_name, + RSYS_list_ta_begin_name, + RSYS_um_get_max_history, + RSYS_um_get_max_history_name, + RSYS_um_set_max_history, + RSYS_um_set_max_history_name, + RSYS_udf_flush_cache, + RSYS_api_min_version, + RSYS_api_max_version, + RSYS_none + }; + + +struct rsys_check_t + { + int correct; + int check_inode; + }; + +struct rsys_get_attr_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t module; + rsbac_enum_t target; + union rsbac_target_id_t __user * tid; + rsbac_enum_t attr; + union rsbac_attribute_value_t __user * value; + int inherit; + }; + +struct rsys_get_attr_n_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t module; + rsbac_enum_t target; + char __user * t_name; + rsbac_enum_t attr; + union rsbac_attribute_value_t __user * value; + int inherit; + }; + +struct rsys_set_attr_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t module; + rsbac_enum_t target; + union rsbac_target_id_t __user * tid; + rsbac_enum_t attr; + union rsbac_attribute_value_t __user * value; + }; + +struct rsys_set_attr_n_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t module; + rsbac_enum_t target; + char __user * t_name; + rsbac_enum_t attr; + union rsbac_attribute_value_t __user * value; + }; + +struct rsys_remove_target_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + union rsbac_target_id_t __user * tid; + }; + +struct rsys_remove_target_n_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + char __user * t_name; + }; + +struct rsys_net_list_all_netdev_t + { + rsbac_list_ta_number_t ta_number; + rsbac_netdev_id_t __user * id_p; + u_long maxnum; + }; + +struct rsys_net_template_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t call; + rsbac_net_temp_id_t id; + union rsbac_net_temp_syscall_data_t __user * data_p; + }; + +struct rsys_net_list_all_template_t + { + rsbac_list_ta_number_t ta_number; + rsbac_net_temp_id_t __user * id_p; + u_long maxnum; + }; + +struct rsys_switch_t + { + rsbac_enum_t module; + int value; + }; + +struct rsys_get_switch_t + { + rsbac_enum_t module; + int __user * value_p; + int __user * switchable_p; + }; + +struct rsys_adf_log_switch_t + { + rsbac_enum_t request; + rsbac_enum_t target; + u_int value; + }; + +struct rsys_get_adf_log_t + { + rsbac_enum_t request; + rsbac_enum_t target; + u_int __user * value_p; + }; + +struct rsys_log_t + { + int type; + char __user * buf; + int len; + }; + +struct rsys_mac_set_curr_level_t + { + rsbac_security_level_t level; + rsbac_mac_category_vector_t __user * categories_p; + }; + +struct rsys_mac_get_curr_level_t + { + rsbac_security_level_t __user * level_p; + rsbac_mac_category_vector_t __user * categories_p; + }; + +struct rsys_mac_get_max_level_t + { + rsbac_security_level_t __user * level_p; + rsbac_mac_category_vector_t __user * categories_p; + }; + +struct rsys_mac_get_min_level_t + { + rsbac_security_level_t __user * level_p; + rsbac_mac_category_vector_t __user * categories_p; + }; + +struct rsys_mac_add_p_tru_t + { + rsbac_list_ta_number_t ta_number; + rsbac_upid_t pid; + rsbac_uid_t uid; + rsbac_time_t ttl; + }; + +struct rsys_mac_remove_p_tru_t + { + rsbac_list_ta_number_t ta_number; + rsbac_upid_t pid; + rsbac_uid_t uid; + }; + +struct rsys_mac_add_f_tru_t + { + rsbac_list_ta_number_t ta_number; + char __user * filename; + rsbac_uid_t uid; + rsbac_time_t ttl; + }; + +struct rsys_mac_remove_f_tru_t + { + rsbac_list_ta_number_t ta_number; + char __user * filename; + rsbac_uid_t uid; + }; + +struct rsys_mac_get_f_trulist_t + { + rsbac_list_ta_number_t ta_number; + char __user * filename; + rsbac_uid_t __user * trulist; + rsbac_time_t __user * ttllist; + u_int maxnum; + }; + +struct rsys_mac_get_p_trulist_t + { + rsbac_list_ta_number_t ta_number; + rsbac_upid_t pid; + rsbac_uid_t __user * trulist; + rsbac_time_t __user * ttllist; + u_int maxnum; + }; + +struct rsys_rc_copy_role_t + { + rsbac_list_ta_number_t ta_number; + rsbac_rc_role_id_t from_role; + rsbac_rc_role_id_t to_role; + }; + +struct rsys_rc_copy_type_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + rsbac_rc_type_id_t from_type; + rsbac_rc_type_id_t to_type; + }; + +struct rsys_rc_get_item_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + union rsbac_rc_target_id_t __user * tid_p; + union rsbac_rc_target_id_t __user * subtid_p; + rsbac_enum_t item; + union rsbac_rc_item_value_t __user * value_p; + rsbac_time_t __user * ttl_p; + }; + +struct rsys_rc_set_item_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + union rsbac_rc_target_id_t __user * tid_p; + union rsbac_rc_target_id_t __user * subtid_p; + rsbac_enum_t item; + union rsbac_rc_item_value_t __user * value_p; + rsbac_time_t ttl; + }; + +struct rsys_rc_get_list_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + union rsbac_rc_target_id_t __user * tid_p; + rsbac_enum_t item; + u_int maxnum; + __u32 __user * array_p; + rsbac_time_t __user * ttl_array_p; + }; + +struct rsys_rc_change_role_t + { + rsbac_rc_role_id_t role; + char __user * pass; + }; + +struct rsys_rc_get_eff_rights_n_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + char __user * t_name; + rsbac_rc_request_vector_t __user * request_vector_p; + rsbac_time_t __user * ttl_p; + }; + +struct rsys_rc_get_current_role_t + { + rsbac_rc_role_id_t __user * role_p; + }; + +struct rsys_auth_add_p_cap_t + { + rsbac_list_ta_number_t ta_number; + rsbac_upid_t pid; + rsbac_enum_t cap_type; + struct rsbac_auth_cap_range_t cap_range; + rsbac_time_t ttl; + }; + +struct rsys_auth_remove_p_cap_t + { + rsbac_list_ta_number_t ta_number; + rsbac_upid_t pid; + rsbac_enum_t cap_type; + struct rsbac_auth_cap_range_t cap_range; + }; + +struct rsys_auth_add_f_cap_t + { + rsbac_list_ta_number_t ta_number; + char __user * filename; + rsbac_enum_t cap_type; + struct rsbac_auth_cap_range_t cap_range; + rsbac_time_t ttl; + }; + +struct rsys_auth_remove_f_cap_t + { + rsbac_list_ta_number_t ta_number; + char __user * filename; + rsbac_enum_t cap_type; + struct rsbac_auth_cap_range_t cap_range; + }; + +struct rsys_auth_get_f_caplist_t + { + rsbac_list_ta_number_t ta_number; + char __user * filename; + rsbac_enum_t cap_type; + struct rsbac_auth_cap_range_t __user * caplist; + rsbac_time_t __user * ttllist; + u_int maxnum; + }; + +struct rsys_auth_get_p_caplist_t + { + rsbac_list_ta_number_t ta_number; + rsbac_upid_t pid; + rsbac_enum_t cap_type; + struct rsbac_auth_cap_range_t __user * caplist; + rsbac_time_t __user * ttllist; + u_int maxnum; + }; + +struct rsys_acl_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t call; + struct rsbac_acl_syscall_arg_t __user * arg; + }; + +struct rsys_acl_n_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t call; + struct rsbac_acl_syscall_n_arg_t __user * arg; + }; + +struct rsys_acl_get_rights_t + { + rsbac_list_ta_number_t ta_number; + struct rsbac_acl_syscall_arg_t __user * arg; + rsbac_acl_rights_vector_t __user * rights_p; + u_int effective; + }; + +struct rsys_acl_get_rights_n_t + { + rsbac_list_ta_number_t ta_number; + struct rsbac_acl_syscall_n_arg_t __user * arg; + rsbac_acl_rights_vector_t __user * rights_p; + u_int effective; + }; + +struct rsys_acl_get_tlist_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + union rsbac_target_id_t __user * tid; + struct rsbac_acl_entry_t __user * entry_array; + rsbac_time_t __user * ttl_array; + u_int maxnum; + }; + +struct rsys_acl_get_tlist_n_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + char __user * t_name; + struct rsbac_acl_entry_t __user * entry_array; + rsbac_time_t __user * ttl_array; + u_int maxnum; + }; + +struct rsys_acl_get_mask_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + union rsbac_target_id_t __user * tid; + rsbac_acl_rights_vector_t __user * mask_p; + }; + +struct rsys_acl_get_mask_n_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + char __user * t_name; + rsbac_acl_rights_vector_t __user * mask_p; + }; + +struct rsys_acl_group_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t call; + union rsbac_acl_group_syscall_arg_t __user * arg_p; + }; + +struct rsys_reg_t + { + long handle; + void __user * arg; + }; + +struct rsys_jail_t + { + rsbac_version_t version; + char __user * path; + rsbac_jail_ip_t ip; + rsbac_jail_flags_t flags; + rsbac_cap_vector_t max_caps; + rsbac_jail_scd_vector_t scd_get; + rsbac_jail_scd_vector_t scd_modify; + }; + +struct rsys_init_t + { + char __user * root_dev; + }; + +struct rsys_um_auth_name_t + { + char __user * name; + char __user * pass; + }; + +struct rsys_um_auth_uid_t + { + rsbac_uid_t uid; + char __user * pass; + }; + +struct rsys_um_add_user_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t uid; + struct rsbac_um_user_entry_t __user * entry_p; + char __user * pass; + rsbac_time_t ttl; + }; + +struct rsys_um_add_group_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_t gid; + struct rsbac_um_group_entry_t __user * entry_p; + char __user * pass; + rsbac_time_t ttl; + }; + +struct rsys_um_add_gm_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t uid; + rsbac_gid_num_t gid; + rsbac_time_t ttl; + }; + +struct rsys_um_mod_user_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t uid; + rsbac_enum_t mod; + union rsbac_um_mod_data_t __user * data_p; + }; + +struct rsys_um_mod_group_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_t gid; + rsbac_enum_t mod; + union rsbac_um_mod_data_t __user * data_p; + }; + +struct rsys_um_get_user_item_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t uid; + rsbac_enum_t mod; + union rsbac_um_mod_data_t __user * data_p; + }; + +struct rsys_um_get_group_item_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_t gid; + rsbac_enum_t mod; + union rsbac_um_mod_data_t __user * data_p; + }; + +struct rsys_um_remove_user_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t uid; + }; + +struct rsys_um_remove_group_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_t gid; + }; + +struct rsys_um_remove_gm_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t uid; + rsbac_gid_num_t gid; + }; + +struct rsys_um_user_exists_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t uid; + }; + +struct rsys_um_group_exists_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_t gid; + }; + +struct rsys_um_get_next_user_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t old_user; + rsbac_uid_t __user * next_user_p; + }; + +struct rsys_um_get_user_list_t + { + rsbac_list_ta_number_t ta_number; + rsbac_um_set_t vset; + rsbac_uid_t __user * user_array; + u_int maxnum; + }; + +struct rsys_um_get_gm_list_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t user; + rsbac_gid_num_t __user * group_array; + u_int maxnum; + }; + +struct rsys_um_get_gm_user_list_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_t group; + rsbac_uid_num_t __user * user_array; + u_int maxnum; + }; + +struct rsys_um_get_group_list_t + { + rsbac_list_ta_number_t ta_number; + rsbac_um_set_t vset; + rsbac_gid_t __user * group_array; + u_int maxnum; + }; + +struct rsys_um_get_uid_t + { + rsbac_list_ta_number_t ta_number; + char __user * name; + rsbac_uid_t __user * uid_p; + }; + +struct rsys_um_get_gid_t + { + rsbac_list_ta_number_t ta_number; + char __user * name; + rsbac_gid_t __user * gid_p; + }; + +struct rsys_um_set_pass_t + { + rsbac_uid_t uid; + char __user * old_pass; + char __user * new_pass; + }; + +struct rsys_um_set_pass_name_t + { + char __user * name; + char __user * old_pass; + char __user * new_pass; + }; + +struct rsys_um_add_onetime_t + { + rsbac_uid_t uid; + char __user * old_pass; + char __user * new_pass; + rsbac_time_t ttl; + }; + +struct rsys_um_add_onetime_name_t + { + char __user * name; + char __user * old_pass; + char __user * new_pass; + rsbac_time_t ttl; + }; + +struct rsys_um_remove_all_onetime_t + { + rsbac_uid_t uid; + char __user * old_pass; + }; + +struct rsys_um_remove_all_onetime_name_t + { + char __user * name; + char __user * old_pass; + }; + +struct rsys_um_count_onetime_t + { + rsbac_uid_t uid; + char __user * old_pass; + }; + +struct rsys_um_count_onetime_name_t + { + char __user * name; + char __user * old_pass; + }; + +struct rsys_um_set_group_pass_t + { + rsbac_gid_t gid; + char __user * new_pass; + }; + +struct rsys_um_check_account_t + { + rsbac_uid_t uid; + }; + +struct rsys_um_check_account_name_t + { + char __user * name; + }; + +struct rsys_um_get_max_history_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t uid; + }; + +struct rsys_um_get_max_history_name_t + { + rsbac_list_ta_number_t ta_number; + char __user * name; + }; + +struct rsys_um_set_max_history_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t uid; + __u8 max_history; + }; + +struct rsys_um_set_max_history_name_t + { + rsbac_list_ta_number_t ta_number; + char __user * name; + __u8 max_history; + }; + +struct rsys_um_select_vset_t + { + rsbac_um_set_t vset; + }; + +struct rsys_list_ta_begin_t + { + rsbac_time_t ttl; + rsbac_list_ta_number_t __user * ta_number_p; + rsbac_uid_t commit_uid; + char __user * password; + }; + +struct rsys_list_ta_begin_name_t + { + rsbac_time_t ttl; + rsbac_list_ta_number_t __user * ta_number_p; + rsbac_uid_t commit_uid; + char __user * name; + char __user * password; + }; + +struct rsys_list_ta_refresh_t + { + rsbac_time_t ttl; + rsbac_list_ta_number_t ta_number; + char __user * password; + }; + +struct rsys_list_ta_commit_t + { + rsbac_list_ta_number_t ta_number; + char __user * password; + }; + +struct rsys_list_ta_forget_t + { + rsbac_list_ta_number_t ta_number; + char __user * password; + }; + +struct rsys_list_all_dev_t + { + rsbac_list_ta_number_t ta_number; + struct rsbac_dev_desc_t __user * id_p; + u_long maxnum; + }; + +struct rsys_acl_list_all_dev_t + { + rsbac_list_ta_number_t ta_number; + struct rsbac_dev_desc_t __user * id_p; + u_long maxnum; + }; + +struct rsys_list_all_user_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t __user * id_p; + u_long maxnum; + }; + +struct rsys_acl_list_all_user_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_t __user * id_p; + u_long maxnum; + }; + +struct rsys_list_all_group_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_t __user * id_p; + u_long maxnum; + }; + +struct rsys_acl_list_all_group_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_t __user * id_p; + u_long maxnum; + }; + +struct rsys_list_all_ipc_t { + rsbac_list_ta_number_t ta_number; + struct rsbac_ipc_t __user *id_p; + u_long maxnum; +}; + +struct rsys_rc_select_fd_create_type_t { + rsbac_rc_type_id_t type; +}; + +union rsbac_syscall_arg_t + { + struct rsys_check_t check; + struct rsys_get_attr_t get_attr; + struct rsys_get_attr_n_t get_attr_n; + struct rsys_set_attr_t set_attr; + struct rsys_set_attr_n_t set_attr_n; + struct rsys_remove_target_t remove_target; + struct rsys_remove_target_n_t remove_target_n; + struct rsys_net_list_all_netdev_t net_list_all_netdev; + struct rsys_net_template_t net_template; + struct rsys_net_list_all_template_t net_list_all_template; + struct rsys_switch_t switch_module; + struct rsys_get_switch_t get_switch_module; + struct rsys_adf_log_switch_t adf_log_switch; + struct rsys_get_adf_log_t get_adf_log; + struct rsys_log_t log; + struct rsys_mac_set_curr_level_t mac_set_curr_level; + struct rsys_mac_get_curr_level_t mac_get_curr_level; + struct rsys_mac_get_max_level_t mac_get_max_level; + struct rsys_mac_get_min_level_t mac_get_min_level; + struct rsys_mac_add_p_tru_t mac_add_p_tru; + struct rsys_mac_remove_p_tru_t mac_remove_p_tru; + struct rsys_mac_add_f_tru_t mac_add_f_tru; + struct rsys_mac_remove_f_tru_t mac_remove_f_tru; + struct rsys_mac_get_f_trulist_t mac_get_f_trulist; + struct rsys_mac_get_p_trulist_t mac_get_p_trulist; + struct rsys_rc_copy_role_t rc_copy_role; + struct rsys_rc_copy_type_t rc_copy_type; + struct rsys_rc_get_item_t rc_get_item; + struct rsys_rc_set_item_t rc_set_item; + struct rsys_rc_get_list_t rc_get_list; + struct rsys_rc_change_role_t rc_change_role; + struct rsys_rc_get_eff_rights_n_t rc_get_eff_rights_n; + struct rsys_rc_get_current_role_t rc_get_current_role; + struct rsys_auth_add_p_cap_t auth_add_p_cap; + struct rsys_auth_remove_p_cap_t auth_remove_p_cap; + struct rsys_auth_add_f_cap_t auth_add_f_cap; + struct rsys_auth_remove_f_cap_t auth_remove_f_cap; + struct rsys_auth_get_f_caplist_t auth_get_f_caplist; + struct rsys_auth_get_p_caplist_t auth_get_p_caplist; + struct rsys_acl_t acl; + struct rsys_acl_n_t acl_n; + struct rsys_acl_get_rights_t acl_get_rights; + struct rsys_acl_get_rights_n_t acl_get_rights_n; + struct rsys_acl_get_tlist_t acl_get_tlist; + struct rsys_acl_get_tlist_n_t acl_get_tlist_n; + struct rsys_acl_get_mask_t acl_get_mask; + struct rsys_acl_get_mask_n_t acl_get_mask_n; + struct rsys_acl_group_t acl_group; + struct rsys_reg_t reg; + struct rsys_jail_t jail; + struct rsys_init_t init; + struct rsys_um_auth_name_t um_auth_name; + struct rsys_um_auth_uid_t um_auth_uid; + struct rsys_um_add_user_t um_add_user; + struct rsys_um_add_group_t um_add_group; + struct rsys_um_add_gm_t um_add_gm; + struct rsys_um_mod_user_t um_mod_user; + struct rsys_um_mod_group_t um_mod_group; + struct rsys_um_get_user_item_t um_get_user_item; + struct rsys_um_get_group_item_t um_get_group_item; + struct rsys_um_remove_user_t um_remove_user; + struct rsys_um_remove_group_t um_remove_group; + struct rsys_um_remove_gm_t um_remove_gm; + struct rsys_um_user_exists_t um_user_exists; + struct rsys_um_group_exists_t um_group_exists; + struct rsys_um_get_next_user_t um_get_next_user; + struct rsys_um_get_user_list_t um_get_user_list; + struct rsys_um_get_gm_list_t um_get_gm_list; + struct rsys_um_get_gm_user_list_t um_get_gm_user_list; + struct rsys_um_get_group_list_t um_get_group_list; + struct rsys_um_get_uid_t um_get_uid; + struct rsys_um_get_gid_t um_get_gid; + struct rsys_um_set_pass_t um_set_pass; + struct rsys_um_set_pass_name_t um_set_pass_name; + struct rsys_um_add_onetime_t um_add_onetime; + struct rsys_um_add_onetime_name_t um_add_onetime_name; + struct rsys_um_remove_all_onetime_t um_remove_all_onetime; + struct rsys_um_remove_all_onetime_name_t um_remove_all_onetime_name; + struct rsys_um_count_onetime_t um_count_onetime; + struct rsys_um_count_onetime_name_t um_count_onetime_name; + struct rsys_um_set_group_pass_t um_set_group_pass; + struct rsys_um_check_account_t um_check_account; + struct rsys_um_check_account_name_t um_check_account_name; + struct rsys_um_get_max_history_t um_get_max_history; + struct rsys_um_get_max_history_name_t um_get_max_history_name; + struct rsys_um_set_max_history_t um_set_max_history; + struct rsys_um_set_max_history_name_t um_set_max_history_name; + struct rsys_list_ta_begin_t list_ta_begin; + struct rsys_list_ta_begin_name_t list_ta_begin_name; + struct rsys_list_ta_refresh_t list_ta_refresh; + struct rsys_list_ta_commit_t list_ta_commit; + struct rsys_list_ta_forget_t list_ta_forget; + struct rsys_list_all_dev_t list_all_dev; + struct rsys_acl_list_all_dev_t acl_list_all_dev; + struct rsys_list_all_user_t list_all_user; + struct rsys_acl_list_all_user_t acl_list_all_user; + struct rsys_list_all_group_t list_all_group; + struct rsys_acl_list_all_group_t acl_list_all_group; + struct rsys_list_all_ipc_t list_all_ipc; + struct rsys_rc_select_fd_create_type_t rc_select_fd_create_type; + struct rsys_um_select_vset_t um_select_vset; + int dummy; + }; + +/* + * 32 Bit emulation support on x86_64 system + */ + +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +struct rsys_check_ia32_t + { + __s32 correct; + __s32 check_inode; + } __attribute__ ((aligned (4))); + +struct rsys_get_attr_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t module; + rsbac_enum_t target; + __u32 tid; + rsbac_enum_t attr; + __u32 value; + __s32 inherit; + } __attribute__ ((aligned (4))); + +struct rsys_get_attr_n_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t module; + rsbac_enum_t target; + __u32 t_name; + rsbac_enum_t attr; + __u32 value; + __s32 inherit; + } __attribute__ ((aligned (4))); + +struct rsys_set_attr_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t module; + rsbac_enum_t target; + __u32 tid; + rsbac_enum_t attr; + __u32 value; + } __attribute__ ((aligned (4))); + +struct rsys_set_attr_n_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t module; + rsbac_enum_t target; + __u32 t_name; + rsbac_enum_t attr; + __u32 value; + } __attribute__ ((aligned (4))); + +struct rsys_remove_target_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + __u32 tid; + } __attribute__ ((aligned (4))); + +struct rsys_remove_target_n_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + __u32 t_name; + } __attribute__ ((aligned (4))); + +struct rsys_net_list_all_netdev_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 id_p; + compat_u64 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_net_template_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t call; + rsbac_net_temp_id_t id; + __u32 data_p; + } __attribute__ ((aligned (4))); + +struct rsys_net_list_all_template_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 id_p; + compat_u64 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_switch_ia32_t + { + rsbac_enum_t module; + __s32 value; + } __attribute__ ((aligned (4))); + +struct rsys_get_switch_ia32_t + { + rsbac_enum_t module; + __u32 value_p; + __u32 switchable_p; + } __attribute__ ((aligned (4))); + +struct rsys_adf_log_switch_ia32_t + { + rsbac_enum_t request; + rsbac_enum_t target; + __u32 value; + } __attribute__ ((aligned (4))); + +struct rsys_get_adf_log_ia32_t + { + rsbac_enum_t request; + rsbac_enum_t target; + __u32 value_p; + } __attribute__ ((aligned (4))); + +struct rsys_log_ia32_t + { + __u32 type; + __u32 buf; + __u32 len; + } __attribute__ ((aligned (4))); + +struct rsys_mac_set_curr_level_ia32_t + { + rsbac_security_level_t level; + __u32 categories_p; + } __attribute__ ((aligned (4))); + +struct rsys_mac_get_curr_level_ia32_t + { + __u32 level_p; + __u32 categories_p; + } __attribute__ ((aligned (4))); + +struct rsys_mac_get_max_level_ia32_t + { + __u32 level_p; + __u32 categories_p; + } __attribute__ ((aligned (4))); + +struct rsys_mac_get_min_level_ia32_t + { + __u32 level_p; + __u32 categories_p; + } __attribute__ ((aligned (4))); + +struct rsys_mac_add_p_tru_ia32_t + { + rsbac_list_ta_number_t ta_number; + compat_pid_t pid; + rsbac_uid_ia32_t uid; + rsbac_time_t ttl; + } __attribute__ ((aligned (4))); + +struct rsys_mac_remove_p_tru_ia32_t + { + rsbac_list_ta_number_t ta_number; + compat_pid_t pid; + rsbac_uid_ia32_t uid; + } __attribute__ ((aligned (4))); + +struct rsys_mac_add_f_tru_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 filename; + rsbac_uid_ia32_t uid; + rsbac_time_t ttl; + } __attribute__ ((aligned (4))); + +struct rsys_mac_remove_f_tru_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 filename; + rsbac_uid_ia32_t uid; + } __attribute__ ((aligned (4))); + +struct rsys_mac_get_f_trulist_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 filename; + __u32 trulist; + __u32 ttllist; + __u32 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_mac_get_p_trulist_ia32_t + { + rsbac_list_ta_number_t ta_number; + compat_pid_t pid; + __u32 trulist; + __u32 ttllist; + __u32 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_rc_copy_role_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_rc_role_id_t from_role; + rsbac_rc_role_id_t to_role; + } __attribute__ ((aligned (4))); + +struct rsys_rc_copy_type_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + rsbac_rc_type_id_t from_type; + rsbac_rc_type_id_t to_type; + } __attribute__ ((aligned (4))); + +struct rsys_rc_get_item_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + __u32 tid_p; + __u32 subtid_p; + rsbac_enum_t item; + __u32 value_p; + __u32 ttl_p; + } __attribute__ ((aligned (4))); + +struct rsys_rc_set_item_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + __u32 tid_p; + __u32 subtid_p; + rsbac_enum_t item; + __u32 value_p; + rsbac_time_t ttl; + } __attribute__ ((aligned (4))); + +struct rsys_rc_get_list_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + __u32 tid_p; + rsbac_enum_t item; + __u32 maxnum; + __u32 array_p; + __u32 ttl_array_p; + } __attribute__ ((aligned (4))); + +struct rsys_rc_change_role_ia32_t + { + rsbac_rc_role_id_t role; + __u32 pass; + } __attribute__ ((aligned (4))); + +struct rsys_rc_get_eff_rights_n_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + __u32 t_name; + __u32 request_vector_p; + __u32 ttl_p; + } __attribute__ ((aligned (4))); + +struct rsys_rc_get_current_role_ia32_t + { + __u32 role_p; + } __attribute__ ((aligned (4))); + +struct rsys_auth_add_p_cap_ia32_t + { + rsbac_list_ta_number_t ta_number; + compat_pid_t pid; + rsbac_enum_t cap_type; + struct rsbac_auth_cap_range_ia32_t cap_range; + rsbac_time_t ttl; + } __attribute__ ((aligned (4))); + +struct rsys_auth_remove_p_cap_ia32_t + { + rsbac_list_ta_number_t ta_number; + compat_pid_t pid; + rsbac_enum_t cap_type; + struct rsbac_auth_cap_range_ia32_t cap_range; + } __attribute__ ((aligned (4))); + +struct rsys_auth_add_f_cap_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 filename; + rsbac_enum_t cap_type; + struct rsbac_auth_cap_range_ia32_t cap_range; + rsbac_time_t ttl; + } __attribute__ ((aligned (4))); + +struct rsys_auth_remove_f_cap_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 filename; + rsbac_enum_t cap_type; + struct rsbac_auth_cap_range_ia32_t cap_range; + } __attribute__ ((aligned (4))); + +struct rsys_auth_get_f_caplist_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 filename; + rsbac_enum_t cap_type; + __u32 caplist; + __u32 ttllist; + __u32 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_auth_get_p_caplist_ia32_t + { + rsbac_list_ta_number_t ta_number; + compat_pid_t pid; + rsbac_enum_t cap_type; + __u32 caplist; + __u32 ttllist; + __u32 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_acl_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t call; + __u32 arg; + } __attribute__ ((aligned (4))); + +struct rsys_acl_n_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t call; + __u32 arg; + } __attribute__ ((aligned (4))); + +struct rsys_acl_get_rights_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 arg; + __u32 rights_p; + __u32 effective; + } __attribute__ ((aligned (4))); + +struct rsys_acl_get_rights_n_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 arg; + __u32 rights_p; + __u32 effective; + } __attribute__ ((aligned (4))); + +struct rsys_acl_get_tlist_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + __u32 tid; + __u32 entry_array; + __u32 ttl_array; + __u32 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_acl_get_tlist_n_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + __u32 t_name; + __u32 entry_array; + __u32 ttl_array; + __u32 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_acl_get_mask_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + __u32 tid; + __u32 mask_p; + } __attribute__ ((aligned (4))); + +struct rsys_acl_get_mask_n_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t target; + __u32 t_name; + __u32 mask_p; + } __attribute__ ((aligned (4))); + +struct rsys_acl_group_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_enum_t call; + __u32 arg_p; + } __attribute__ ((aligned (4))); + +struct rsys_reg_ia32_t + { + compat_s64 handle; + __u32 arg; + } __attribute__ ((aligned (4))); + +struct rsys_jail_ia32_t + { + rsbac_version_t version; + __u32 path; + rsbac_jail_ip_t ip; + rsbac_jail_flags_t flags; + rsbac_cap_vector_t max_caps; + rsbac_jail_scd_vector_t scd_get; + rsbac_jail_scd_vector_t scd_modify; + } __attribute__ ((aligned (4))); + +struct rsys_init_ia32_t + { + __u32 root_dev; + } __attribute__ ((aligned (4))); + +struct rsys_um_auth_name_ia32_t + { + __u32 name; + __u32 pass; + } __attribute__ ((aligned (4))); + +struct rsys_um_auth_uid_ia32_t + { + rsbac_uid_ia32_t uid; + __u32 pass; + } __attribute__ ((aligned (4))); + +struct rsys_um_add_user_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_ia32_t uid; + __u32 entry_p; + __u32 pass; + rsbac_time_t ttl; + } __attribute__ ((aligned (4))); + +struct rsys_um_add_group_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_ia32_t gid; + __u32 entry_p; + __u32 pass; + rsbac_time_t ttl; + } __attribute__ ((aligned (4))); + +struct rsys_um_add_gm_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_ia32_t uid; + rsbac_gid_num_t gid; + rsbac_time_t ttl; + } __attribute__ ((aligned (4))); + +struct rsys_um_mod_user_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_ia32_t uid; + rsbac_enum_t mod; + __u32 data_p; + } __attribute__ ((aligned (4))); + +struct rsys_um_mod_group_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_ia32_t gid; + rsbac_enum_t mod; + __u32 data_p; + } __attribute__ ((aligned (4))); + +struct rsys_um_get_user_item_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_ia32_t uid; + rsbac_enum_t mod; + __u32 data_p; + } __attribute__ ((aligned (4))); + +struct rsys_um_get_group_item_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_ia32_t gid; + rsbac_enum_t mod; + __u32 data_p; + } __attribute__ ((aligned (4))); + +struct rsys_um_remove_user_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_ia32_t uid; + } __attribute__ ((aligned (4))); + +struct rsys_um_remove_group_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_ia32_t gid; + } __attribute__ ((aligned (4))); + +struct rsys_um_remove_gm_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_ia32_t uid; + rsbac_gid_num_t gid; + } __attribute__ ((aligned (4))); + +struct rsys_um_user_exists_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_ia32_t uid; + } __attribute__ ((aligned (4))); + +struct rsys_um_group_exists_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_ia32_t gid; + } __attribute__ ((aligned (4))); + +struct rsys_um_get_next_user_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_ia32_t old_user; + __u32 next_user_p; + } __attribute__ ((aligned (4))); + +struct rsys_um_get_user_list_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_um_set_t vset; + __u32 user_array; + u_int maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_um_get_gm_list_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_ia32_t user; + __u32 group_array; + u_int maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_um_get_gm_user_list_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_gid_ia32_t group; + __u32 user_array; + u_int maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_um_get_group_list_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_um_set_t vset; + __u32 group_array; + u_int maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_um_get_uid_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 name; + __u32 uid_p; + } __attribute__ ((aligned (4))); + +struct rsys_um_get_gid_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 name; + __u32 gid_p; + } __attribute__ ((aligned (4))); + +struct rsys_um_set_pass_ia32_t + { + rsbac_uid_ia32_t uid; + __u32 old_pass; + __u32 new_pass; + } __attribute__ ((aligned (4))); + +struct rsys_um_set_pass_name_ia32_t + { + __u32 name; + __u32 old_pass; + __u32 new_pass; + } __attribute__ ((aligned (4))); + +struct rsys_um_add_onetime_ia32_t + { + rsbac_uid_ia32_t uid; + __u32 old_pass; + __u32 new_pass; + rsbac_time_t ttl; + } __attribute__ ((aligned (4))); + +struct rsys_um_add_onetime_name_ia32_t + { + __u32 name; + __u32 old_pass; + __u32 new_pass; + rsbac_time_t ttl; + } __attribute__ ((aligned (4))); + +struct rsys_um_remove_all_onetime_ia32_t + { + rsbac_uid_ia32_t uid; + __u32 old_pass; + } __attribute__ ((aligned (4))); + +struct rsys_um_remove_all_onetime_name_ia32_t + { + __u32 name; + __u32 old_pass; + } __attribute__ ((aligned (4))); + +struct rsys_um_count_onetime_ia32_t + { + rsbac_uid_ia32_t uid; + __u32 old_pass; + } __attribute__ ((aligned (4))); + +struct rsys_um_count_onetime_name_ia32_t + { + __u32 name; + __u32 old_pass; + } __attribute__ ((aligned (4))); + +struct rsys_um_set_group_pass_ia32_t + { + rsbac_gid_ia32_t gid; + __u32 new_pass; + } __attribute__ ((aligned (4))); + +struct rsys_um_check_account_ia32_t + { + rsbac_uid_ia32_t uid; + } __attribute__ ((aligned (4))); + +struct rsys_um_check_account_name_ia32_t + { + __u32 name; + } __attribute__ ((aligned (4))); + +struct rsys_um_get_max_history_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_ia32_t uid; + } __attribute__ ((aligned (4))); + +struct rsys_um_get_max_history_name_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 name; + } __attribute__ ((aligned (4))); + +struct rsys_um_set_max_history_ia32_t + { + rsbac_list_ta_number_t ta_number; + rsbac_uid_ia32_t uid; + __u8 max_history; + } __attribute__ ((aligned (4))); + +struct rsys_um_set_max_history_name_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 name; + __u8 max_history; + } __attribute__ ((aligned (4))); + +struct rsys_um_select_vset_ia32_t + { + rsbac_um_set_t vset; + } __attribute__ ((aligned (4))); + +struct rsys_list_ta_begin_ia32_t + { + rsbac_time_t ttl; + __u32 ta_number_p; + rsbac_uid_ia32_t commit_uid; + __u32 password; + } __attribute__ ((aligned (4))); + +struct rsys_list_ta_begin_name_ia32_t + { + rsbac_time_t ttl; + __u32 ta_number_p; + rsbac_uid_ia32_t commit_uid; + __u32 name; + __u32 password; + } __attribute__ ((aligned (4))); + +struct rsys_list_ta_refresh_ia32_t + { + rsbac_time_t ttl; + rsbac_list_ta_number_t ta_number; + __u32 password; + } __attribute__ ((aligned (4))); + +struct rsys_list_ta_commit_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 password; + } __attribute__ ((aligned (4))); + +struct rsys_list_ta_forget_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 password; + } __attribute__ ((aligned (4))); + +struct rsys_list_all_dev_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 id_p; + compat_u64 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_acl_list_all_dev_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 id_p; + compat_u64 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_list_all_user_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 id_p; + compat_u64 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_acl_list_all_user_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 id_p; + compat_u64 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_list_all_group_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 id_p; + compat_u64 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_acl_list_all_group_ia32_t + { + rsbac_list_ta_number_t ta_number; + __u32 id_p; + compat_u64 maxnum; + } __attribute__ ((aligned (4))); + +struct rsys_list_all_ipc_ia32_t +{ + rsbac_list_ta_number_t ta_number; + __u32 id_p; + compat_u64 maxnum; +} __attribute__ ((aligned (4))); + +struct rsys_rc_select_fd_create_type_ia32_t +{ + rsbac_rc_type_id_t type; +} __attribute__ ((aligned (4))); + +union rsbac_syscall_arg_ia32_t + { + struct rsys_check_ia32_t check; + struct rsys_get_attr_ia32_t get_attr; + struct rsys_get_attr_n_ia32_t get_attr_n; + struct rsys_set_attr_ia32_t set_attr; + struct rsys_set_attr_n_ia32_t set_attr_n; + struct rsys_remove_target_ia32_t remove_target; + struct rsys_remove_target_n_ia32_t remove_target_n; + struct rsys_net_list_all_netdev_ia32_t net_list_all_netdev; + struct rsys_net_template_ia32_t net_template; + struct rsys_net_list_all_template_ia32_t net_list_all_template; + struct rsys_switch_ia32_t switch_module; + struct rsys_get_switch_ia32_t get_switch_module; + struct rsys_adf_log_switch_ia32_t adf_log_switch; + struct rsys_get_adf_log_ia32_t get_adf_log; + struct rsys_log_ia32_t log; + struct rsys_mac_set_curr_level_ia32_t mac_set_curr_level; + struct rsys_mac_get_curr_level_ia32_t mac_get_curr_level; + struct rsys_mac_get_max_level_ia32_t mac_get_max_level; + struct rsys_mac_get_min_level_ia32_t mac_get_min_level; + struct rsys_mac_add_p_tru_ia32_t mac_add_p_tru; + struct rsys_mac_remove_p_tru_ia32_t mac_remove_p_tru; + struct rsys_mac_add_f_tru_ia32_t mac_add_f_tru; + struct rsys_mac_remove_f_tru_ia32_t mac_remove_f_tru; + struct rsys_mac_get_f_trulist_ia32_t mac_get_f_trulist; + struct rsys_mac_get_p_trulist_ia32_t mac_get_p_trulist; + struct rsys_rc_copy_role_ia32_t rc_copy_role; + struct rsys_rc_copy_type_ia32_t rc_copy_type; + struct rsys_rc_get_item_ia32_t rc_get_item; + struct rsys_rc_set_item_ia32_t rc_set_item; + struct rsys_rc_get_list_ia32_t rc_get_list; + struct rsys_rc_change_role_ia32_t rc_change_role; + struct rsys_rc_get_eff_rights_n_ia32_t rc_get_eff_rights_n; + struct rsys_rc_get_current_role_ia32_t rc_get_current_role; + struct rsys_auth_add_p_cap_ia32_t auth_add_p_cap; + struct rsys_auth_remove_p_cap_ia32_t auth_remove_p_cap; + struct rsys_auth_add_f_cap_ia32_t auth_add_f_cap; + struct rsys_auth_remove_f_cap_ia32_t auth_remove_f_cap; + struct rsys_auth_get_f_caplist_ia32_t auth_get_f_caplist; + struct rsys_auth_get_p_caplist_ia32_t auth_get_p_caplist; + struct rsys_acl_ia32_t acl; + struct rsys_acl_n_ia32_t acl_n; + struct rsys_acl_get_rights_ia32_t acl_get_rights; + struct rsys_acl_get_rights_n_ia32_t acl_get_rights_n; + struct rsys_acl_get_tlist_ia32_t acl_get_tlist; + struct rsys_acl_get_tlist_n_ia32_t acl_get_tlist_n; + struct rsys_acl_get_mask_ia32_t acl_get_mask; + struct rsys_acl_get_mask_n_ia32_t acl_get_mask_n; + struct rsys_acl_group_ia32_t acl_group; + struct rsys_reg_ia32_t reg; + struct rsys_jail_ia32_t jail; + struct rsys_init_ia32_t init; + struct rsys_um_auth_name_ia32_t um_auth_name; + struct rsys_um_auth_uid_ia32_t um_auth_uid; + struct rsys_um_add_user_ia32_t um_add_user; + struct rsys_um_add_group_ia32_t um_add_group; + struct rsys_um_add_gm_ia32_t um_add_gm; + struct rsys_um_mod_user_ia32_t um_mod_user; + struct rsys_um_mod_group_ia32_t um_mod_group; + struct rsys_um_get_user_item_ia32_t um_get_user_item; + struct rsys_um_get_group_item_ia32_t um_get_group_item; + struct rsys_um_remove_user_ia32_t um_remove_user; + struct rsys_um_remove_group_ia32_t um_remove_group; + struct rsys_um_remove_gm_ia32_t um_remove_gm; + struct rsys_um_user_exists_ia32_t um_user_exists; + struct rsys_um_group_exists_ia32_t um_group_exists; + struct rsys_um_get_next_user_ia32_t um_get_next_user; + struct rsys_um_get_user_list_ia32_t um_get_user_list; + struct rsys_um_get_gm_list_ia32_t um_get_gm_list; + struct rsys_um_get_gm_user_list_ia32_t um_get_gm_user_list; + struct rsys_um_get_group_list_ia32_t um_get_group_list; + struct rsys_um_get_uid_ia32_t um_get_uid; + struct rsys_um_get_gid_ia32_t um_get_gid; + struct rsys_um_set_pass_ia32_t um_set_pass; + struct rsys_um_set_pass_name_ia32_t um_set_pass_name; + struct rsys_um_add_onetime_ia32_t um_add_onetime; + struct rsys_um_add_onetime_name_ia32_t um_add_onetime_name; + struct rsys_um_remove_all_onetime_ia32_t um_remove_all_onetime; + struct rsys_um_remove_all_onetime_name_ia32_t um_remove_all_onetime_name; + struct rsys_um_count_onetime_ia32_t um_count_onetime; + struct rsys_um_count_onetime_name_ia32_t um_count_onetime_name; + struct rsys_um_set_group_pass_ia32_t um_set_group_pass; + struct rsys_um_check_account_ia32_t um_check_account; + struct rsys_um_check_account_name_ia32_t um_check_account_name; + struct rsys_um_get_max_history_ia32_t um_get_max_history; + struct rsys_um_get_max_history_name_ia32_t um_get_max_history_name; + struct rsys_um_set_max_history_ia32_t um_set_max_history; + struct rsys_um_set_max_history_name_ia32_t um_set_max_history_name; + struct rsys_list_ta_begin_ia32_t list_ta_begin; + struct rsys_list_ta_begin_name_ia32_t list_ta_begin_name; + struct rsys_list_ta_refresh_ia32_t list_ta_refresh; + struct rsys_list_ta_commit_ia32_t list_ta_commit; + struct rsys_list_ta_forget_ia32_t list_ta_forget; + struct rsys_list_all_dev_ia32_t list_all_dev; + struct rsys_acl_list_all_dev_ia32_t acl_list_all_dev; + struct rsys_list_all_user_ia32_t list_all_user; + struct rsys_acl_list_all_user_ia32_t acl_list_all_user; + struct rsys_list_all_group_ia32_t list_all_group; + struct rsys_acl_list_all_group_ia32_t acl_list_all_group; + struct rsys_list_all_ipc_ia32_t list_all_ipc; + struct rsys_rc_select_fd_create_type_ia32_t rc_select_fd_create_type; + struct rsys_um_select_vset_ia32_t um_select_vset; + __u32 dummy; + } __attribute__ ((aligned (4))); + +#endif /* CONFIG_IA32_EMULATION || CONFIG_X86_X32 */ + +#endif diff --git a/include/rsbac/types.h b/include/rsbac/types.h new file mode 100644 index 000000000000..e63cbb9ace97 --- /dev/null +++ b/include/rsbac/types.h @@ -0,0 +1,1075 @@ +/*********************************** */ +/* Rule Set Based Access Control */ +/* Author and (c)1999-2017: */ +/* Amon Ott */ +/* API: Data types for attributes */ +/* and standard module calls */ +/* Last modified: 21/Mar/2017 */ +/*********************************** */ + +#ifndef __RSBAC_TYPES_H +#define __RSBAC_TYPES_H + + +/* trigger module dependency for EXPORT_SYMBOL */ +#ifdef CONFIG_MODULES +#endif + +#define RSBAC_VERSION "1.5.1" +#define RSBAC_VERSION_MAJOR 1 +#define RSBAC_VERSION_MID 5 +#define RSBAC_VERSION_MINOR 1 +#define RSBAC_VERSION_NR \ + ((RSBAC_VERSION_MAJOR << 16) | (RSBAC_VERSION_MID << 8) | RSBAC_VERSION_MINOR) +#define RSBAC_VERSION_MAKE_NR(x,y,z) \ + ((x << 16) | (y << 8) | z) + +#define RSBAC_API_MIN_VERSION "1.4.0" +#define RSBAC_API_MIN_VERSION_MAJOR 1 +#define RSBAC_API_MIN_VERSION_MID 4 +#define RSBAC_API_MIN_VERSION_MINOR 0 +#define RSBAC_API_MIN_VERSION_NR \ + ((RSBAC_API_MIN_VERSION_MAJOR << 16) | (RSBAC_API_MIN_VERSION_MID << 8) | RSBAC_API_MIN_VERSION_MINOR) + +#define RSBAC_API_MAX_VERSION "1.5.0" +#define RSBAC_API_MAX_VERSION_MAJOR 1 +#define RSBAC_API_MAX_VERSION_MID 5 +#define RSBAC_API_MAX_VERSION_MINOR 0 +#define RSBAC_API_MAX_VERSION_NR \ + ((RSBAC_API_MAX_VERSION_MAJOR << 16) | (RSBAC_API_MAX_VERSION_MID << 8) | RSBAC_API_MAX_VERSION_MINOR) + +#ifdef __KERNEL__ +#include +#include +#include +#else +#include +#include +#endif + +typedef __u32 rsbac_version_t; +typedef __u64 rsbac_uid_t; /* High 32 Bit virtual set, low uid */ +typedef __u64 rsbac_gid_t; /* High 32 Bit virtual set, low gid */ +typedef __u32 rsbac_old_uid_t; /* Same as user in Linux kernel */ +typedef __u32 rsbac_uid_num_t; /* Same as user in Linux kernel */ +typedef __u32 rsbac_old_gid_t; /* Same as group in Linux kernel */ +typedef __u32 rsbac_gid_num_t; /* Same as user in Linux kernel */ +typedef __u32 rsbac_um_set_t; +typedef __u32 rsbac_time_t; /* Same as time_t in Linux kernel */ +typedef kernel_cap_t rsbac_cap_vector_t; /* Same as kernel_cap_t in Linux kernel */ +typedef __u32 rsbac_cap_old_vector_t; /* Same as kernel_cap_t in Linux kernel */ +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +typedef __u64 __attribute__((aligned(4))) rsbac_uid_ia32_t; /* High 32 Bit virtual set, low uid */ +typedef __u64 __attribute__((aligned(4))) rsbac_gid_ia32_t; /* High 32 Bit virtual set, low gid */ +#endif + +#define RSBAC_UID_SET(x) ((rsbac_um_set_t) (x >> 32)) +#define RSBAC_UID_NUM(x) ((rsbac_uid_num_t) (x & (rsbac_uid_num_t) -1)) +#define RSBAC_GEN_UID(x,y) ((rsbac_uid_t) x << 32 | RSBAC_UID_NUM(y)) +#define RSBAC_GID_SET(x) ((rsbac_um_set_t) (x >> 32)) +#define RSBAC_GID_NUM(x) ((rsbac_gid_num_t) (x & (rsbac_gid_num_t) -1)) +#define RSBAC_GEN_GID(x,y) ((rsbac_gid_t) x << 32 | RSBAC_GID_NUM(y)) +#define RSBAC_UM_VIRTUAL_KEEP ((rsbac_um_set_t) -1) +#define RSBAC_UM_VIRTUAL_ALL ((rsbac_um_set_t) -2) +#define RSBAC_UM_VIRTUAL_MAX ((rsbac_um_set_t) -10) + +typedef __u32 rsbac_list_ta_number_t; + +struct rsbac_nanotime_t + { + rsbac_time_t sec; + __u32 nsec; + }; + +#ifdef __KERNEL__ +#include +#include +#include +#include + +/* version checks */ +#ifndef LINUX_VERSION_CODE +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) +#error "RSBAC: unsupported kernel version" +#endif + +#include +#define RSBAC_MAJOR MAJOR +#define RSBAC_MINOR MINOR +#define RSBAC_MKDEV(major,minor) MKDEV(major,minor) + +static inline rsbac_time_t rsbac_current_time(void) +{ + struct timespec64 ts; + + ktime_get_real_ts64(&ts); + return ts.tv_sec; +} + +static inline void rsbac_get_current_nanotime(struct rsbac_nanotime_t * nanotime) +{ + struct timespec64 ts; + + ktime_get_real_ts64(&ts); + nanotime->sec = ts.tv_sec; + nanotime->nsec = ts.tv_nsec; +} + +#ifndef kdev_t +#define kdev_t dev_t +#endif +#define RSBAC_CURRENT_TIME (rsbac_current_time()) + +#define RSBAC_ZERO_DEV RSBAC_MKDEV(0,0) +#define RSBAC_AUTO_DEV RSBAC_MKDEV(99,99) +#define RSBAC_IS_ZERO_DEV(kdev) (!RSBAC_MAJOR(kdev) && !RSBAC_MINOR(kdev)) +#define RSBAC_IS_AUTO_DEV(kdev) ((RSBAC_MAJOR(kdev) == 99) && (RSBAC_MINOR(kdev) == 99)) + +#ifdef CONFIG_RSBAC_INIT_DELAY +#define R_INIT +#else +#define R_INIT __init +#endif + +#endif + +/* General */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#define rsbac_min(a,b) (((a)<(b))?(a):(b)) +#define rsbac_max(a,b) (((a)>(b))?(a):(b)) + +#define RSBAC_OLD_NO_USER 65533 +#define RSBAC_OLD_ALL_USERS 65532 +#define RSBAC_NO_USER ((rsbac_uid_num_t) -3) +#define RSBAC_ALL_USERS ((rsbac_uid_num_t) -4) +#define RSBAC_NO_GROUP ((rsbac_gid_num_t) -3) +#define RSBAC_ALL_GROUPS ((rsbac_gid_num_t) -4) + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +typedef u_int rsbac_boolean_t; + +typedef __u8 rsbac_boolean_int_t; + +#define RSBAC_IFNAMSIZ 16 +typedef u_char rsbac_netdev_id_t[RSBAC_IFNAMSIZ + 1]; + +#define RSBAC_SEC_DEL_CHUNK_SIZE 65536 + +/* Adjust these, if you have to, but if you do, adjust them all! */ +/* Note: no / allowed, file must be exactly in second level! */ +#define RSBAC_AUTH_LOGIN_PATH "/bin/login" +#define RSBAC_AUTH_LOGIN_PATH_DIR "bin" +#define RSBAC_AUTH_LOGIN_PATH_FILE "login" + +/* These data structures work parallel to the Linux data structures, */ +/* so all data for RSBAC decisions is maintained seperately. */ +/* Any change to RSBAC data will NOT modify any other linux data, */ +/* e.g. userlists, process lists or inodes. */ + +/* Special generic lists time-to-live (ttl) value to keep old setting */ +#define RSBAC_LIST_TTL_KEEP ((rsbac_time_t) -1) + +typedef __u8 rsbac_enum_t; /* internally used for all enums */ + +#define RSBAC_SYSADM_UID 0 +#define RSBAC_BIN_UID 1 +#ifdef CONFIG_RSBAC_SECOFF_UID +#define RSBAC_SECOFF_UID CONFIG_RSBAC_SECOFF_UID +#else +#define RSBAC_SECOFF_UID 400 +#endif +#define RSBAC_AUDITOR_UID (RSBAC_SECOFF_UID+4) + +typedef __u32 rsbac_pseudo_t; /* For Pseudonymic Logging */ +typedef __kernel_pid_t rsbac_upid_t; /* Same as pid in Linux < 2.6.24 */ + +typedef struct pid * rsbac_pid_t; /* use new pid struct */ + +typedef __u32 rsbac_ta_number_t; + +typedef __u8 rsbac_security_level_t; +#define SL_max 252 +#define SL_min 0 +// #define SL_rsbac_internal 253 +#define SL_inherit 254 +#define SL_none 255 +enum rsbac_old_security_level_t {SL_unclassified, SL_confidential, SL_secret, + SL_top_secret, SL_old_rsbac_internal, + SL_old_inherit, SL_old_none}; + /* MAC security levels */ +typedef __u64 rsbac_mac_category_vector_t; /* MAC category sets */ +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +typedef __u64 __attribute__((aligned(4))) rsbac_mac_category_vector_ia32_t; /* MAC category sets */ +#endif +#define RSBAC_MAC_GENERAL_CATEGORY 0 +#define RSBAC_MAC_DEF_CAT_VECTOR ((rsbac_mac_category_vector_t) 1) + /* 1 << GENERAL_CAT */ +#define RSBAC_MAC_MAX_CAT_VECTOR ((rsbac_mac_category_vector_t) -1) + /* all bits set */ +#define RSBAC_MAC_MIN_CAT_VECTOR ((rsbac_mac_category_vector_t) 0) + /* no bits set */ +#define RSBAC_MAC_INHERIT_CAT_VECTOR ((rsbac_mac_category_vector_t) 0) + /* for fd: no bits set */ +#define RSBAC_MAC_NR_CATS 64 +#define RSBAC_MAC_MAX_CAT 63 + +#define RSBAC_MAC_CAT_VECTOR(x) ((rsbac_mac_category_vector_t) 1 << (x)) + +typedef u_int rsbac_cwi_relation_id_t; + +/* For MAC, FF, AUTH */ +enum rsbac_system_role_t {SR_user, SR_security_officer, SR_administrator, + SR_auditor, SR_none}; +typedef rsbac_enum_t rsbac_system_role_int_t; + +/* For all models */ +enum rsbac_fake_root_uid_t {FR_off, FR_uid_only, FR_euid_only, FR_both, + FR_none}; +typedef rsbac_enum_t rsbac_fake_root_uid_int_t; + +enum rsbac_scd_type_t {ST_time_strucs, ST_clock, ST_host_id, + ST_net_id, ST_ioports, ST_rlimit, + ST_swap, ST_syslog, ST_rsbac, ST_rsbac_log, + ST_other, ST_kmem, ST_network, ST_firewall, + ST_priority, ST_sysfs, ST_rsbac_remote_log, + ST_quota, ST_sysctl, ST_nfsd, ST_ksyms, + ST_mlock, ST_capability, ST_kexec, ST_videomem, + ST_none}; + +typedef __u32 rsbac_scd_vector_t; +#define RSBAC_SCD_VECTOR(x) ((rsbac_scd_vector_t) 1 << (x)) + +enum rsbac_dev_type_t {D_block, D_char, D_block_major, D_char_major, D_none}; + + +enum rsbac_ipc_type_t {I_sem, I_msg, I_shm, I_anonpipe, I_mqueue, + I_anonunix, I_none}; +union rsbac_ipc_id_t + { + u_long id_nr; + }; + +typedef __u64 rsbac_inode_nr_t; +typedef __u32 rsbac_old_inode_nr_t; + +enum rsbac_allow_write_exec_t {AWX_false, AWX_true, AWX_inherit, AWX_relocate, AWX_none}; +typedef rsbac_enum_t rsbac_allow_write_exec_int_t; + +#ifdef __KERNEL__ +/* We need unique identifiers for each file/dir. inode means inode in */ +/* the file system. */ +struct rsbac_fs_file_t + { + kdev_t device; + rsbac_inode_nr_t inode; + struct dentry * dentry_p; /* used for inheritance recursion */ + }; + +struct rsbac_dev_t + { + enum rsbac_dev_type_t type; + kdev_t id; + }; +#endif /* __KERNEL */ + +/* We need unique ids for dev objects */ +struct rsbac_dev_desc_t + { + __u32 type; + __u32 major; + __u32 minor; + }; + +static inline struct rsbac_dev_desc_t + rsbac_mkdev_desc(__u32 type, __u32 major, __u32 minor) + { + struct rsbac_dev_desc_t dev_desc; + + dev_desc.type = type; + dev_desc.major = major; + dev_desc.minor = minor; + return dev_desc; + } + +#define RSBAC_ZERO_DEV_DESC rsbac_mkdev_desc(D_none, 0, 0) +#define RSBAC_AUTO_DEV_DESC rsbac_mkdev_desc(D_none, 99, 99) +#define RSBAC_IS_ZERO_DEV_DESC(dev) ((dev.type == D_none) && !dev.major && !dev.minor) +#define RSBAC_IS_AUTO_DEV_DESC(dev) ((dev.type == D_none) && (dev.major == 99) && (dev.minor == 99)) + +/* And we need unique ids for ipc objects */ +struct rsbac_ipc_t + { + enum rsbac_ipc_type_t type; + union rsbac_ipc_id_t id; + }; + +/* log levels: nothing, denied requests only, all, refer to request log level */ +enum rsbac_log_level_t {LL_none, LL_denied, LL_full, LL_request, LL_invalid}; +typedef __u64 rsbac_log_array_t; +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +typedef __u64 __attribute__((aligned(4))) rsbac_log_array_ia32_t; +#endif + +/* request bitvectors */ +typedef __u64 rsbac_request_vector_t; +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +typedef __u64 __attribute__((aligned(4))) rsbac_request_vector_ia32_t; +#endif +#define RSBAC_REQUEST_VECTOR(x) ((rsbac_request_vector_t) 1 << (x)) + +/* The max length of each filename is kept in a macro */ +#define RSBAC_MAXNAMELEN 256 + +#define RSBAC_LIST_TA_MAX_NAMELEN 32 +#define RSBAC_LIST_TA_MAX_PASSLEN 36 + +/* MAC */ + +typedef __u8 rsbac_mac_user_flags_t; +typedef __u16 rsbac_mac_process_flags_t; +typedef __u8 rsbac_mac_file_flags_t; +typedef struct rsbac_fs_file_t rsbac_mac_file_t; +#define RSBAC_MAC_MAX_MAXNUM 1000000 + +#define MAC_override 1 +#define MAC_auto 2 +#define MAC_trusted 4 +#define MAC_write_up 8 +#define MAC_read_up 16 +#define MAC_write_down 32 +#define MAC_allow_auto 64 +#define MAC_prop_trusted 128 +#define MAC_program_auto 256 + +#define RSBAC_MAC_U_FLAGS (MAC_override | MAC_trusted | MAC_write_up | MAC_read_up | MAC_write_down | MAC_allow_auto) +#define RSBAC_MAC_P_FLAGS (MAC_override | MAC_auto | MAC_trusted | MAC_write_up | MAC_read_up | MAC_write_down | MAC_prop_trusted | MAC_program_auto) +#define RSBAC_MAC_F_FLAGS (MAC_auto | MAC_trusted | MAC_write_up | MAC_read_up | MAC_write_down) + +#define RSBAC_MAC_DEF_U_FLAGS 0 +#define RSBAC_MAC_DEF_SYSADM_U_FLAGS MAC_allow_auto +#define RSBAC_MAC_DEF_SECOFF_U_FLAGS MAC_override + +#define RSBAC_MAC_DEF_P_FLAGS 0 +#define RSBAC_MAC_DEF_INIT_P_FLAGS MAC_auto + +typedef rsbac_enum_t rsbac_mac_auto_int_t; +enum rsbac_mac_auto_t {MA_no, MA_yes, MA_inherit}; + +/* DAZ */ +typedef __u8 rsbac_daz_scanned_t; +#define DAZ_unscanned 0 +#define DAZ_infected 1 +#define DAZ_clean 2 +#define DAZ_max 2 +#define DEFAULT_DAZ_FD_SCANNED DAZ_unscanned +typedef __u8 rsbac_daz_scanner_t; +typedef __u8 rsbac_daz_do_scan_t; +#define DAZ_never 0 +#define DAZ_registered 1 +#define DAZ_always 2 +#define DAZ_inherit 3 +#define DAZ_max_do_scan 3 +#define DEFAULT_DAZ_FD_DO_SCAN DAZ_inherit +#define DEFAULT_DAZ_FD_ROOT_DO_SCAN DAZ_registered + +/* FF */ + +typedef __u16 rsbac_ff_flags_t; +#define FF_read_only 1 +#define FF_execute_only 2 +#define FF_search_only 4 +#define FF_write_only 8 +#define FF_secure_delete 16 +#define FF_no_execute 32 +#define FF_no_delete_or_rename 64 +#define FF_append_only 256 +#define FF_no_mount 512 +#define FF_no_search 1024 + +#define FF_add_inherited 128 + +#define RSBAC_FF_DEF FF_add_inherited +#define RSBAC_FF_ROOT_DEF 0 + +/***** RC *****/ + +#include + +/**** AUTH ****/ +/* special cap value, replaced by process owner at execute time */ +#define RSBAC_AUTH_MAX_MAXNUM 1000000 +#define RSBAC_AUTH_OWNER_F_CAP ((rsbac_uid_num_t) -3) +#define RSBAC_AUTH_DAC_OWNER_F_CAP ((rsbac_uid_num_t) -4) +#define RSBAC_AUTH_MAX_RANGE_UID ((rsbac_uid_num_t) -10) +#define RSBAC_AUTH_GROUP_F_CAP ((rsbac_uid_num_t) -3) +#define RSBAC_AUTH_DAC_GROUP_F_CAP ((rsbac_uid_num_t) -4) +#define RSBAC_AUTH_MAX_RANGE_GID ((rsbac_uid_num_t) -10) +typedef struct rsbac_fs_file_t rsbac_auth_file_t; +struct rsbac_auth_cap_range_t + { + rsbac_uid_t first; + rsbac_uid_t last; + }; +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +struct rsbac_auth_cap_range_ia32_t + { + rsbac_uid_ia32_t first; + rsbac_uid_ia32_t last; + } __attribute__ ((aligned (4))); +#endif +struct rsbac_auth_old_cap_range_t + { + rsbac_old_uid_t first; + rsbac_old_uid_t last; + }; +enum rsbac_auth_cap_type_t {ACT_real, ACT_eff, ACT_fs, + ACT_group_real, ACT_group_eff, ACT_group_fs, + ACT_none}; +typedef rsbac_enum_t rsbac_auth_cap_type_int_t; + +enum rsbac_auth_may_setuid_t {AMS_off, AMS_full, AMS_last_auth_only, + AMS_last_auth_and_gid, AMS_none}; + +typedef rsbac_enum_t rsbac_auth_may_setuid_int_t; + +/**** ACL ****/ +/* include at end of types.h */ + +/**** CAP ****/ +enum rsbac_cap_process_hiding_t {PH_off, PH_from_other_users, PH_full, + PH_none}; +typedef rsbac_enum_t rsbac_cap_process_hiding_int_t; + +enum rsbac_cap_ld_env_t { LD_deny, LD_allow, LD_keep, LD_inherit }; +typedef rsbac_enum_t rsbac_cap_ld_env_int_t; + +#define RSBAC_CAP_DEFAULT_MIN (__u32) 0 +#define RSBAC_CAP_DEFAULT_MAX (__u32) -1 + +#include +#define CAP_NONE 34 +#define RSBAC_CAP_MAX CAP_NONE + +/**** JAIL ****/ + +#define RSBAC_JAIL_VERSION 1 + +typedef __u32 rsbac_jail_id_t; +#define RSBAC_JAIL_DEF_ID 0 +typedef __u32 rsbac_jail_ip_t; +typedef __u32 rsbac_jail_scd_vector_t; + +typedef __u32 rsbac_jail_flags_t; +#define JAIL_allow_external_ipc 1 +#define JAIL_allow_all_net_family 2 +#define JAIL_allow_inet_raw 8 +#define JAIL_auto_adjust_inet_any 16 +#define JAIL_allow_inet_localhost 32 +#define JAIL_allow_dev_get_status 128 +#define JAIL_allow_dev_mod_system 256 +#define JAIL_allow_dev_read 512 +#define JAIL_allow_dev_write 1024 +#define JAIL_allow_tty_open 2048 +#define JAIL_allow_parent_ipc 4096 +#define JAIL_allow_suid_files 8192 +#define JAIL_allow_mount 16384 +#define JAIL_this_is_syslog 32768 +#define JAIL_allow_ipc_to_syslog 65536 +#define JAIL_allow_netlink 131072 +#define JAIL_allow_netdev_mod_system 262144 +#define JAIL_allow_process_by_parent 524288 + +#define RSBAC_JAIL_LOCALHOST ((1 << 24) | 127) + +/**** PAX ****/ + +typedef unsigned long rsbac_pax_flags_t; + +/* for PaX defines */ +#ifdef __KERNEL__ +#include +#include +#endif +#ifndef PF_PAX_PAGEEXEC +#define PF_PAX_PAGEEXEC 0x01000000 /* Paging based non-executable pages */ +#define PF_PAX_EMUTRAMP 0x02000000 /* Emulate trampolines */ +#define PF_PAX_MPROTECT 0x04000000 /* Restrict mprotect() */ +#define PF_PAX_RANDMMAP 0x08000000 /* Randomize mmap() base */ +#define PF_PAX_RANDEXEC 0x10000000 /* Randomize ET_EXEC base */ +#define PF_PAX_SEGMEXEC 0x20000000 /* Segmentation based non-executable pages */ +#endif + +#define RSBAC_PAX_DEF_FLAGS (PF_PAX_SEGMEXEC | PF_PAX_PAGEEXEC | PF_PAX_MPROTECT | PF_PAX_RANDMMAP) +#define RSBAC_PAX_ALL_FLAGS ((rsbac_pax_flags_t) 255 << 24) + +/**** UM User management ****/ +/* Included from um_types.h */ + +/**** RES ****/ + +typedef __u32 rsbac_res_limit_t; +#define RSBAC_RES_UNSET 0 + +#define RSBAC_RES_MAX 10 /* RLIMIT_LOCKS in 2.4.x kernels */ +#define RSBAC_RES_NONE 11 + +typedef rsbac_res_limit_t rsbac_res_array_t[RSBAC_RES_MAX + 1]; + +/**** REG ****/ +typedef __s32 rsbac_reg_handle_t; + +/* UDF */ +typedef __u8 rsbac_udf_checked_t; +#define UDF_unchecked 0 +#define UDF_denied 1 +#define UDF_allowed 2 +#define UDF_max 2 +#define DEFAULT_UDF_FD_CHECKED UDF_unchecked +typedef __u8 rsbac_udf_checker_t; +typedef __u8 rsbac_udf_do_check_t; +#define UDF_never 0 +#define UDF_always 1 +#define UDF_inherit 2 +#define UDF_max_do_check 2 +#define DEFAULT_UDF_FD_DO_CHECK UDF_inherit +#define DEFAULT_UDF_FD_ROOT_DO_CHECK UDF_never +#define RSBAC_UDF_PATH_MAX 4096 +#define UDF_res_allow 0 +#define UDF_res_deny 1 +#define UDF_res_temp_fail_allow 254 +#define UDF_res_temp_fail_deny 255 + + +/****************************************************************************/ +/* ADF types */ +/****************************************************************************/ + +#include + +#ifdef __KERNEL__ + typedef struct socket * rsbac_net_obj_id_t; +#else + typedef void * rsbac_net_obj_id_t; +#endif + +struct rsbac_net_obj_desc_t + { + rsbac_net_obj_id_t sock_p; + void * local_addr; + u_int local_len; + void * remote_addr; + u_int remote_len; + rsbac_net_temp_id_t local_temp; + rsbac_net_temp_id_t remote_temp; + }; + +#define RSBAC_ADF_REQUEST_ARRAY_VERSION 2 + +enum rsbac_adf_request_t { + R_ADD_TO_KERNEL, + R_ALTER, + R_APPEND_OPEN, + R_CHANGE_GROUP, + R_CHANGE_OWNER, + R_CHDIR, + R_CLONE, + R_CLOSE, + R_CREATE, + R_DELETE, + R_EXECUTE, + R_GET_PERMISSIONS_DATA, + R_GET_STATUS_DATA, + R_LINK_HARD, + R_MODIFY_ACCESS_DATA, + R_MODIFY_ATTRIBUTE, + R_MODIFY_PERMISSIONS_DATA, + R_MODIFY_SYSTEM_DATA, + R_MOUNT, + R_READ, + R_READ_ATTRIBUTE, + R_READ_WRITE_OPEN, + R_READ_OPEN, + R_REMOVE_FROM_KERNEL, + R_RENAME, + R_SEARCH, + R_SEND_SIGNAL, + R_SHUTDOWN, + R_SWITCH_LOG, + R_SWITCH_MODULE, + R_TERMINATE, + R_TRACE, + R_TRUNCATE, + R_UMOUNT, + R_WRITE, + R_WRITE_OPEN, + R_MAP_EXEC, + R_BIND, + R_LISTEN, + R_ACCEPT, + R_CONNECT, + R_SEND, + R_RECEIVE, + R_NET_SHUTDOWN, + R_CHANGE_DAC_EFF_OWNER, + R_CHANGE_DAC_FS_OWNER, + R_CHANGE_DAC_EFF_GROUP, + R_CHANGE_DAC_FS_GROUP, + R_IOCTL, + R_LOCK, + R_AUTHENTICATE, + R_MOVETO, + R_NONE + }; + +typedef rsbac_enum_t rsbac_adf_request_int_t; + +#include + +/* This type is returned from the rsbac_adf_request() function. Since a */ +/* decision of undefined means an error, it is never returned. */ + +enum rsbac_adf_req_ret_t {NOT_GRANTED,GRANTED,DO_NOT_CARE,UNDEFINED}; + +/****************************************************************************/ +/* ACI types */ +/****************************************************************************/ + +/* For switching adf-modules */ +enum rsbac_switch_target_t {SW_GEN,SW_MAC,SW_UDF,SW_DAZ,SW_FF,SW_RC,SW_AUTH, + SW_REG,SW_ACL,SW_CAP,SW_JAIL,SW_RES,SW_PAX,SW_SOFTMODE, + SW_MPROTECT,SW_UM,SW_FREEZE,SW_NONE}; +#define RSBAC_MAX_MOD (SW_SOFTMODE - 1) +typedef rsbac_enum_t rsbac_switch_target_int_t; + +/****************************************************************************/ +/* For objects, users and processes all manipulation is encapsulated by the */ +/* function calls rsbac_set_attr, rsbac_get_attr and rsbac_remove_target. */ + +/* For those, we declare some extra types to specify target and attribute. */ + +enum rsbac_target_t {T_FILE, T_DIR, T_FIFO, T_SYMLINK, T_DEV, T_IPC, T_SCD, T_USER, T_PROCESS, + T_NETDEV, T_NETTEMP, T_NETOBJ, T_NETTEMP_NT, T_GROUP, + T_FD, T_UNIXSOCK, + T_NONE}; + +union rsbac_target_id_t + { +#ifdef __KERNEL__ + struct rsbac_fs_file_t file; + struct rsbac_fs_file_t dir; + struct rsbac_fs_file_t fifo; + struct rsbac_fs_file_t symlink; + struct rsbac_fs_file_t unixsock; +#endif + struct rsbac_dev_desc_t dev; + struct rsbac_ipc_t ipc; + rsbac_enum_t scd; + rsbac_uid_t user; + rsbac_gid_t group; + rsbac_pid_t process; /* new struct pid * */ + rsbac_upid_t uprocess; /* old fashioned pid from user space */ + rsbac_netdev_id_t netdev; + rsbac_net_temp_id_t nettemp; + struct rsbac_net_obj_desc_t netobj; + int dummy; + }; + +#ifdef __KERNEL__ +typedef rsbac_enum_t rsbac_log_entry_t[T_NONE+1]; +typedef rsbac_enum_t rsbac_old_log_entry_t[T_NONE]; + +struct rsbac_create_data_t + { + enum rsbac_target_t target; + struct dentry * dentry_p; + int mode; + kdev_t device; /* for mknod etc. */ + }; + +struct rsbac_rlimit_t + { + u_int resource; + struct rlimit limit; + }; +#endif + +enum rsbac_attribute_t + { + A_pseudo, + A_security_level, + A_initial_security_level, + A_local_sec_level, + A_remote_sec_level, + A_min_security_level, + A_mac_categories, + A_mac_initial_categories, + A_local_mac_categories, + A_remote_mac_categories, + A_mac_min_categories, + A_mac_user_flags, + A_mac_process_flags, + A_mac_file_flags, + A_system_role, + A_mac_role, + A_daz_role, + A_ff_role, + A_auth_role, + A_cap_role, + A_jail_role, + A_pax_role, + A_current_sec_level, + A_mac_curr_categories, + A_min_write_open, + A_min_write_categories, + A_max_read_open, + A_max_read_categories, + A_mac_auto, + A_mac_check, + A_mac_prop_trusted, + A_pm_role, + A_pm_process_type, + A_pm_current_task, + A_pm_object_class, + A_local_pm_object_class, + A_remote_pm_object_class, + A_pm_ipc_purpose, + A_local_pm_ipc_purpose, + A_remote_pm_ipc_purpose, + A_pm_object_type, + A_local_pm_object_type, + A_remote_pm_object_type, + A_pm_program_type, + A_pm_tp, + A_pm_task_set, + A_daz_scanned, + A_daz_scanner, + A_ff_flags, + A_rc_type, + A_rc_select_type, + A_local_rc_type, + A_remote_rc_type, + A_rc_type_fd, + A_rc_type_nt, + A_rc_force_role, + A_rc_initial_role, + A_rc_role, + A_rc_def_role, + A_auth_may_setuid, + A_auth_may_set_cap, + A_auth_learn, + A_min_caps, + A_max_caps, + A_max_caps_user, + A_max_caps_program, + A_jail_id, + A_jail_parent, + A_jail_ip, + A_jail_flags, + A_jail_max_caps, + A_jail_scd_get, + A_jail_scd_modify, + A_pax_flags, + A_res_role, + A_res_min, + A_res_max, + A_log_array_low, + A_local_log_array_low, + A_remote_log_array_low, + A_log_array_high, + A_local_log_array_high, + A_remote_log_array_high, + A_log_program_based, + A_log_user_based, + A_symlink_add_remote_ip, + A_symlink_add_uid, + A_symlink_add_mac_level, + A_symlink_add_rc_role, + A_allow_write_exec, + A_cap_process_hiding, + A_fake_root_uid, + A_audit_uid, + A_auid_exempt, + A_auth_last_auth, + A_remote_ip, + A_cap_ld_env, + A_daz_do_scan, + A_vset, + A_udf_role, + A_udf_checked, + A_udf_checker, + A_udf_do_check, +#ifdef __KERNEL__ + /* adf-request helpers */ + A_owner, + A_group, + A_signal, + A_mode, + A_nlink, + A_switch_target, + A_mod_name, + A_request, + A_trace_request, + A_auth_add_f_cap, + A_auth_remove_f_cap, + A_auth_get_caplist, + A_prot_bits, + A_internal, + /* used with CREATE on DIR */ + A_create_data, + A_new_object, + A_rlimit, + A_new_dir_dentry_p, + A_auth_start_uid, + A_auth_start_euid, + A_auth_start_gid, + A_auth_start_egid, + A_acl_learn, + A_priority, + A_pgid, + A_kernel_thread, + A_open_flag, + A_reboot_cmd, + A_setsockopt_level, + A_ioctl_cmd, + A_f_mode, + A_process, + A_sock_type, + A_pagenr, + A_cap_learn, + A_rc_learn, + A_old_dir_inode_p, +#endif + A_none}; + +union rsbac_attribute_value_t + { + rsbac_uid_t owner; /* process owner */ + rsbac_pseudo_t pseudo; + rsbac_system_role_int_t system_role; +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_MAC) + rsbac_security_level_t security_level; + rsbac_mac_category_vector_t mac_categories; + rsbac_security_level_t current_sec_level; + rsbac_security_level_t min_write_open; + rsbac_security_level_t max_read_open; + rsbac_mac_user_flags_t mac_user_flags; + rsbac_mac_process_flags_t mac_process_flags; + rsbac_mac_file_flags_t mac_file_flags; + rsbac_mac_auto_int_t mac_auto; + rsbac_boolean_t mac_check; + rsbac_boolean_t mac_prop_trusted; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_DAZ) + rsbac_daz_scanned_t daz_scanned; + rsbac_daz_scanner_t daz_scanner; + rsbac_daz_do_scan_t daz_do_scan; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_FF) + rsbac_ff_flags_t ff_flags; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_RC) + rsbac_rc_type_id_t rc_type; + rsbac_rc_type_id_t rc_type_fd; + rsbac_rc_role_id_t rc_force_role; + rsbac_rc_role_id_t rc_initial_role; + rsbac_rc_role_id_t rc_role; + rsbac_rc_role_id_t rc_def_role; + rsbac_rc_type_id_t rc_select_type; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_AUTH) + rsbac_auth_may_setuid_int_t auth_may_setuid; + rsbac_boolean_t auth_may_set_cap; + rsbac_pid_t auth_p_capset; + rsbac_inode_nr_t auth_f_capset; + rsbac_boolean_t auth_learn; + rsbac_uid_t auth_last_auth; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_CAP) + rsbac_cap_vector_t min_caps; + rsbac_cap_vector_t max_caps; + rsbac_cap_vector_t max_caps_user; + rsbac_cap_vector_t max_caps_program; + rsbac_cap_process_hiding_int_t cap_process_hiding; + rsbac_cap_ld_env_int_t cap_ld_env; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_JAIL) + rsbac_jail_id_t jail_id; + rsbac_jail_id_t jail_parent; + rsbac_jail_ip_t jail_ip; + rsbac_jail_flags_t jail_flags; + rsbac_jail_scd_vector_t jail_scd_get; + rsbac_jail_scd_vector_t jail_scd_modify; + rsbac_cap_vector_t jail_max_caps; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_PAX) + rsbac_pax_flags_t pax_flags; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_RES) + rsbac_res_array_t res_array; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_UDF) + rsbac_udf_checked_t udf_checked; + rsbac_udf_checker_t udf_checker; + rsbac_udf_do_check_t udf_do_check; +#endif + rsbac_log_array_t log_array_low; + rsbac_log_array_t log_array_high; + rsbac_request_vector_t log_program_based; + rsbac_request_vector_t log_user_based; + rsbac_enum_t symlink_add_remote_ip; + rsbac_boolean_t symlink_add_uid; + rsbac_boolean_t symlink_add_mac_level; + rsbac_boolean_t symlink_add_rc_role; + rsbac_allow_write_exec_int_t allow_write_exec; +// rsbac_net_temp_id_t net_temp; + rsbac_fake_root_uid_int_t fake_root_uid; + rsbac_uid_t audit_uid; + rsbac_uid_t auid_exempt; + __u32 remote_ip; + rsbac_um_set_t vset; +#ifdef __KERNEL__ + rsbac_gid_t group; /* process/fd group */ + struct sockaddr * sockaddr_p; /* socket address */ + int signal; /* signal for kill */ + int mode; /* mode for create/mount */ + int nlink; /* for DELETE/unlink */ + enum rsbac_switch_target_t switch_target; /* for SWITCH_MODULE */ + char * mod_name; /* for ADD_TO_KERNEL */ + enum rsbac_adf_request_t request; /* for SWITCH_LOG */ + long trace_request; /* request for sys_trace */ + struct rsbac_auth_cap_range_t auth_cap_range; + int prot_bits;/* prot bits for mmap()/mprotect() */ + rsbac_boolean_t internal; + /* used with CREATE on DIR */ + struct rsbac_create_data_t create_data; + /* newly created object in OPEN requests? */ + rsbac_boolean_t new_object; + struct rsbac_rlimit_t rlimit; + struct dentry * new_dir_dentry_p; + rsbac_uid_t auth_start_uid; + rsbac_uid_t auth_start_euid; + rsbac_gid_t auth_start_gid; + rsbac_gid_t auth_start_egid; + rsbac_boolean_t acl_learn; + int priority; + rsbac_pid_t pgid; + rsbac_boolean_t kernel_thread; + u_int open_flag; + u_int reboot_cmd; + int setsockopt_level; + u_int ioctl_cmd; + mode_t f_mode; + rsbac_pid_t process; + short sock_type; + u_int pagenr; + rsbac_boolean_t cap_learn; + rsbac_boolean_t rc_learn; + struct inode * old_dir_inode_p; +#endif + u_char u_char_dummy; + u_short u_short_dummy; + int dummy; + u_int u_dummy; + long long_dummy; + u_long u_long_dummy; + }; + +/* List all values possibly used in FD Cache to find data size */ + +#ifdef CONFIG_RSBAC_FD_CACHE +union rsbac_attribute_value_cache_t + { + rsbac_uid_t owner; /* process owner */ + rsbac_pseudo_t pseudo; + rsbac_system_role_int_t system_role; +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_MAC) + rsbac_security_level_t security_level; + rsbac_mac_category_vector_t mac_categories; + rsbac_security_level_t current_sec_level; + rsbac_security_level_t min_write_open; + rsbac_security_level_t max_read_open; + rsbac_mac_user_flags_t mac_user_flags; + rsbac_mac_process_flags_t mac_process_flags; + rsbac_mac_file_flags_t mac_file_flags; + rsbac_mac_auto_int_t mac_auto; + rsbac_boolean_t mac_check; + rsbac_boolean_t mac_prop_trusted; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_DAZ) + rsbac_daz_scanned_t daz_scanned; + rsbac_daz_scanner_t daz_scanner; + rsbac_daz_do_scan_t daz_do_scan; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_FF) + rsbac_ff_flags_t ff_flags; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_RC) + rsbac_rc_type_id_t rc_type; + rsbac_rc_type_id_t rc_type_fd; + rsbac_rc_role_id_t rc_force_role; + rsbac_rc_role_id_t rc_initial_role; + rsbac_rc_role_id_t rc_role; + rsbac_rc_role_id_t rc_def_role; + rsbac_rc_type_id_t rc_select_type; +#endif +#if !defined(__KERNEL__) || defined(CONFIG_RSBAC_UDF) + rsbac_udf_checked_t udf_checked; + rsbac_udf_checker_t udf_checker; + rsbac_udf_do_check_t udf_do_check; +#endif + rsbac_log_array_t log_array_low; + rsbac_log_array_t log_array_high; + rsbac_request_vector_t log_program_based; + rsbac_request_vector_t log_user_based; + rsbac_enum_t symlink_add_remote_ip; + rsbac_boolean_t symlink_add_uid; + rsbac_boolean_t symlink_add_mac_level; + rsbac_boolean_t symlink_add_rc_role; + rsbac_allow_write_exec_int_t allow_write_exec; +// rsbac_net_temp_id_t net_temp; + rsbac_fake_root_uid_int_t fake_root_uid; + rsbac_uid_t audit_uid; + rsbac_uid_t auid_exempt; + __u32 remote_ip; + rsbac_um_set_t vset; + u_char u_char_dummy; + u_short u_short_dummy; + int dummy; + u_int u_dummy; + long long_dummy; + u_long u_long_dummy; + }; +#endif + +/**** ACL + UM ****/ + +#include +#include + +/* not aligned, yet */ +struct rsbac_rw_req { + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + enum rsbac_attribute_t rsbac_attribute; + union rsbac_attribute_value_t rsbac_attribute_value; + enum rsbac_adf_request_t rsbac_request; +}; + +int rsbac_handle_rw_req(const struct file *file, struct rsbac_rw_req *rsbac_rw_req_obj); +int rsbac_handle_rw_up(struct rsbac_rw_req *rsbac_rw_req_obj); + +#endif + diff --git a/include/rsbac/udf.h b/include/rsbac/udf.h new file mode 100644 index 000000000000..67be094f2af3 --- /dev/null +++ b/include/rsbac/udf.h @@ -0,0 +1,27 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2013: Amon Ott */ +/* API: */ +/* Functions for Access */ +/* Control Information / UDF */ +/* Last modified: 18/Nov/2013 */ +/************************************ */ + +#ifndef __RSBAC_UDF_H +#define __RSBAC_UDF_H + +#include + +/* Get ttl for new cache items in seconds */ +/* This function returns 0, if no cache is available, and the ttl value + otherwise */ +rsbac_time_t rsbac_udf_get_ttl(void); + +/* Set ttl for new cache items in seconds */ +/* ttl must be positive, values bigger than 10 years in seconds + (RSBAC_LIST_MAX_AGE_LIMIT in lists.h) are reduced to this limit */ +void rsbac_udf_set_ttl(rsbac_time_t ttl); + +/* Flush DAZuko cache lists */ +int rsbac_udf_flush_cache(void); +#endif diff --git a/include/rsbac/um.h b/include/rsbac/um.h new file mode 100644 index 000000000000..b7b6e6e91765 --- /dev/null +++ b/include/rsbac/um.h @@ -0,0 +1,178 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2011: */ +/* Amon Ott */ +/* API: Data structures */ +/* and functions for User Management */ +/* Last modified: 19/Apt/2011 */ +/************************************ */ + +#ifndef __RSBAC_UM_H +#define __RSBAC_UM_H + +#include +#include +#include + +/***************************************************/ +/* General Prototypes */ +/***************************************************/ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac_error.h. */ + +/****************************************************************************/ +/* Initialization, including ACI restoration for all mounted devices from */ +/* disk. After this call, all ACI is kept in memory for performance reasons,*/ +/* but user and file/dir object ACI are written to disk on every change. */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +extern int rsbac_init_um(void); +#else +extern int rsbac_init_um(void) __init; +#endif + +/* Some information about the current status is also available */ +extern int rsbac_stats_um(void); + +/************************************************* */ +/* Access functions */ +/************************************************* */ + +/* Trying to access a never created or removed user entry returns an error! */ + +/* rsbac_um_add_user (fills *user_p with new uid) */ + +int rsbac_um_add_user( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t * user_p, + struct rsbac_um_user_entry_t * entry_p, + char * pass, + rsbac_time_t ttl); + +int rsbac_um_add_group( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t * group_p, + struct rsbac_um_group_entry_t * entry_p, + char * pass, + rsbac_time_t ttl); + +int rsbac_um_add_gm( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + rsbac_gid_num_t group, + rsbac_time_t ttl); + +int rsbac_um_mod_user( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + enum rsbac_um_mod_t mod, + union rsbac_um_mod_data_t * data_p); + +int rsbac_um_mod_group( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t group, + enum rsbac_um_mod_t mod, + union rsbac_um_mod_data_t * data_p); + +int rsbac_um_get_user_item( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + enum rsbac_um_mod_t mod, + union rsbac_um_mod_data_t * data_p); + +int rsbac_um_get_group_item( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t group, + enum rsbac_um_mod_t mod, + union rsbac_um_mod_data_t * data_p); + +int rsbac_um_user_exists( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t user); + +int rsbac_um_group_exists( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t group); + +int rsbac_um_remove_user( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t user); + +int rsbac_um_remove_group( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t group); + +int rsbac_um_remove_gm( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + rsbac_gid_num_t group); + +int rsbac_um_get_next_user( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t old_user, + rsbac_uid_t * next_user_p); + +int rsbac_um_get_user_list( + rsbac_list_ta_number_t ta_number, + rsbac_um_set_t vset, + rsbac_uid_t ** list_pp); + +int rsbac_um_get_gm_list( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + rsbac_gid_num_t ** list_pp); + +int rsbac_um_get_gm_user_list( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t group, + rsbac_uid_num_t ** list_pp); + +int rsbac_um_get_group_list( + rsbac_list_ta_number_t ta_number, + rsbac_um_set_t vset, + rsbac_gid_t ** list_pp); + +int rsbac_um_get_user_entry( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + struct rsbac_um_user_entry_t * entry_p, + rsbac_time_t * ttl_p); + +int rsbac_um_get_uid( + rsbac_list_ta_number_t ta_number, + char * name, + rsbac_uid_t * uid_p); + +int rsbac_um_get_gid( + rsbac_list_ta_number_t ta_number, + char * name, + rsbac_gid_t * gid_p); + +int rsbac_um_check_pass(rsbac_uid_t uid, + char * pass); + +/* Check for good password (min length etc.) */ +int rsbac_um_good_pass(rsbac_uid_t uid, char * pass); + +#ifdef CONFIG_RSBAC_UM_ONETIME +int rsbac_um_add_onetime(rsbac_uid_t uid, char * pass, rsbac_time_t ttl); + +int rsbac_um_remove_all_onetime(rsbac_uid_t uid); + +int rsbac_um_count_onetime(rsbac_uid_t uid); +#endif + +int rsbac_um_set_pass(rsbac_uid_t uid, + char * pass); + +int rsbac_um_set_group_pass(rsbac_gid_t gid, + char * pass); + +int rsbac_um_check_account(rsbac_uid_t user); + +int rsbac_um_get_max_history(rsbac_list_ta_number_t ta_number, rsbac_uid_t uid); + +int rsbac_um_set_max_history(rsbac_list_ta_number_t ta_number, rsbac_uid_t uid, __u8 max_history); + +#endif diff --git a/include/rsbac/um_types.h b/include/rsbac/um_types.h new file mode 100644 index 000000000000..b5e575bcd6b5 --- /dev/null +++ b/include/rsbac/um_types.h @@ -0,0 +1,154 @@ +/**************************************/ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2016: Amon Ott */ +/* User Management Data structures */ +/* Last modified: 17/Feb/2016 */ +/**************************************/ + +#ifndef __RSBAC_UM_TYPES_H +#define __RSBAC_UM_TYPES_H + +//#include + +#define RSBAC_UM_MAX_MAXNUM 1000000 + +#define RSBAC_UM_USER_LIST_NAME "um_user" +#define RSBAC_UM_GROUP_LIST_NAME "um_grp" +#define RSBAC_UM_USER_PWHISTORY_LIST_NAME "um_pwh" +#define RSBAC_UM_ONETIME_LIST_NAME "um_pwot" +#define RSBAC_UM_UID_CACHE_LIST_NAME "um_uch" +#define RSBAC_UM_GID_CACHE_LIST_NAME "um_gch" +#define RSBAC_UM_OLD_USER_LIST_NAME "um_u." +#define RSBAC_UM_OLD_GROUP_LIST_NAME "um_g." +#define RSBAC_UM_OLD_USER_PWHISTORY_LIST_NAME "um_pwh." + +#define RSBAC_UM_NR_USER_LIST_HASH_BITS 3 +#define RSBAC_UM_NR_GROUP_LIST_HASH_BITS 3 +#define RSBAC_UM_NR_USER_PWHISTORY_LIST_HASH_BITS 3 +#define RSBAC_UM_NR_NAME_CACHE_LIST_HASH_BITS 2 + +#define RSBAC_UM_USER_LIST_VERSION 3 +#define RSBAC_UM_GROUP_LIST_VERSION 3 +#define RSBAC_UM_USER_PWHISTORY_LIST_VERSION 2 +#define RSBAC_UM_ONETIME_LIST_VERSION 1 +#define RSBAC_UM_NAME_CACHE_LIST_VERSION 1 + +#define RSBAC_UM_USER_OLD_LIST_VERSION 2 +#define RSBAC_UM_USER_OLD_OLD_LIST_VERSION 1 +#define RSBAC_UM_GROUP_OLD_LIST_VERSION 2 +#define RSBAC_UM_GROUP_OLD_OLD_LIST_VERSION 1 +#define RSBAC_UM_USER_PWHISTORY_OLD_LIST_VERSION 1 + +#define RSBAC_UM_USER_LIST_KEY 6363636 +#define RSBAC_UM_GROUP_LIST_KEY 9847298 +#define RSBAC_UM_USER_PWHISTORY_LIST_KEY 8854687 +#define RSBAC_UM_ONETIME_LIST_KEY 63273279 +#define RSBAC_UM_UID_CACHE_LIST_KEY 129871376 +#define RSBAC_UM_GID_CACHE_LIST_KEY 129876363 + +#define RSBAC_UM_NAME_LEN 65 +#define RSBAC_UM_OLD_NAME_LEN 16 +#define RSBAC_UM_PASS_LEN 24 +#define RSBAC_UM_FULLNAME_LEN 65 +#define RSBAC_UM_OLD_FULLNAME_LEN 30 +#define RSBAC_UM_HOMEDIR_LEN 101 +#define RSBAC_UM_OLD_HOMEDIR_LEN 50 +#define RSBAC_UM_SHELL_LEN 45 +#define RSBAC_UM_OLD_SHELL_LEN 24 + +typedef __s32 rsbac_um_days_t; + +typedef char rsbac_um_password_t[RSBAC_UM_PASS_LEN]; + +enum rsbac_um_mod_t { UM_name, UM_pass, UM_fullname, UM_homedir, UM_shell, + UM_group, UM_lastchange, UM_minchange, UM_maxchange, + UM_warnchange, UM_inactive, UM_expire, UM_ttl, + UM_cryptpass, UM_none +}; + +union rsbac_um_mod_data_t { + char string[RSBAC_MAXNAMELEN]; + rsbac_gid_num_t group; + rsbac_um_days_t days; + rsbac_time_t ttl; +}; + +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) +union rsbac_um_mod_data_ia32_t { + char string[RSBAC_MAXNAMELEN]; + rsbac_gid_num_t group; + rsbac_um_days_t days; + rsbac_time_t ttl; +}__attribute__ ((aligned (4))); +#endif + +struct rsbac_um_user_entry_t { + rsbac_gid_num_t group; + rsbac_um_days_t lastchange; + rsbac_um_days_t minchange; + rsbac_um_days_t maxchange; + rsbac_um_days_t warnchange; + rsbac_um_days_t inactive; + rsbac_um_days_t expire; + char name[RSBAC_UM_NAME_LEN]; + char pass[RSBAC_UM_PASS_LEN]; + char fullname[RSBAC_UM_FULLNAME_LEN]; + char homedir[RSBAC_UM_HOMEDIR_LEN]; + char shell[RSBAC_UM_SHELL_LEN]; +}; + +struct rsbac_um_old_user_entry_t { + char name[RSBAC_UM_OLD_NAME_LEN]; + char pass[RSBAC_UM_PASS_LEN]; + char fullname[RSBAC_UM_OLD_FULLNAME_LEN]; + char homedir[RSBAC_UM_OLD_HOMEDIR_LEN]; + char shell[RSBAC_UM_OLD_SHELL_LEN]; + rsbac_gid_num_t group; + rsbac_um_days_t lastchange; + rsbac_um_days_t minchange; + rsbac_um_days_t maxchange; + rsbac_um_days_t warnchange; + rsbac_um_days_t inactive; + rsbac_um_days_t expire; +}; + +#define DEFAULT_UM_U_ENTRY \ + { \ + 65534, /* group */ \ + 100000, /* lastchange */ \ + 0, /* minchange */ \ + 365, /* maxchange */ \ + 10, /* warnchange */ \ + 3, /* inactive */ \ + 100000, /* expire */ \ + "", /* name */ \ + "", /* pass */ \ + "", /* fullname */ \ + "/home", /* homedir */ \ + "/bin/sh" /* shell */ \ + } + +struct rsbac_um_group_entry_t { + char name[RSBAC_UM_NAME_LEN]; + char pass[RSBAC_UM_PASS_LEN]; +}; + +struct rsbac_um_old_group_entry_t { + char name[RSBAC_UM_OLD_NAME_LEN]; + char pass[RSBAC_UM_PASS_LEN]; +}; + +#if defined(CONFIG_RSBAC_UM_NAME_CACHE) && defined(CONFIG_RSBAC_UM_VIRTUAL) +struct rsbac_um_name_cache_desc_t { + char name[RSBAC_UM_NAME_LEN]; + rsbac_um_set_t vset; +}; +#endif + +#define DEFAULT_UM_G_ENTRY \ + { \ + "", /* name */ \ + "" /* pass */ \ + } + +#endif diff --git a/include/rsbac/unistd-alpha.h b/include/rsbac/unistd-alpha.h new file mode 100644 index 000000000000..d6014f21b134 --- /dev/null +++ b/include/rsbac/unistd-alpha.h @@ -0,0 +1,16 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2002: Amon Ott */ +/* System Call definitions - alpha */ +/* Last modified: 20/Mar/2002 */ +/************************************ */ + +#ifndef __RSBAC_UNISTD_ALPHA_H +#define __RSBAC_UNISTD_ALPHA_H + +#ifndef __NR_security +#define __NR_security 380 +#endif +#define __NR_rsbac __NR_security + +#endif diff --git a/include/rsbac/unistd-i386.h b/include/rsbac/unistd-i386.h new file mode 100644 index 000000000000..5d600fb23c79 --- /dev/null +++ b/include/rsbac/unistd-i386.h @@ -0,0 +1,16 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2002: Amon Ott */ +/* System Call definitions - i386 */ +/* Last modified: 20/Mar/2002 */ +/************************************ */ + +#ifndef __RSBAC_UNISTD_I386_H +#define __RSBAC_UNISTD_I386_H + +#ifndef __NR_security +#define __NR_security 223 +#endif +#define __NR_rsbac __NR_security + +#endif diff --git a/include/rsbac/unistd-ppc.h b/include/rsbac/unistd-ppc.h new file mode 100644 index 000000000000..cab4714b0fac --- /dev/null +++ b/include/rsbac/unistd-ppc.h @@ -0,0 +1,16 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2002: Amon Ott */ +/* System Call definitions - i386 */ +/* Last modified: 07/Apr/2002 */ +/************************************ */ + +#ifndef __RSBAC_UNISTD_PPC_H +#define __RSBAC_UNISTD_PPC_H + +#ifndef __NR_security +#define __NR_security 220 +#endif +#define __NR_rsbac __NR_security + +#endif diff --git a/include/uapi/linux/sched.h b/include/uapi/linux/sched.h index e2a6c7b3510b..b5cfd05d6d51 100644 --- a/include/uapi/linux/sched.h +++ b/include/uapi/linux/sched.h @@ -28,6 +28,9 @@ #define CLONE_NEWPID 0x20000000 /* New pid namespace */ #define CLONE_NEWNET 0x40000000 /* New network namespace */ #define CLONE_IO 0x80000000 /* Clone io context */ +#ifdef CONFIG_RSBAC +#define CLONE_KTHREAD 0x100000000ULL /* clone a kernel thread */ +#endif /* * Scheduling policies diff --git a/init/do_mounts.c b/init/do_mounts.c index c2de5104aad2..5368392fe9a7 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -35,6 +35,14 @@ #include "do_mounts.h" +#ifdef CONFIG_RSBAC +#include +#include +#ifdef CONFIG_BLK_DEV_INITRD +#include +#endif +#endif + int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */ int root_mountflags = MS_RDONLY | MS_SILENT; @@ -602,6 +610,14 @@ void __init prepare_namespace(void) devtmpfs_mount("dev"); sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); + +#ifdef CONFIG_RSBAC +#ifdef CONFIG_RSBAC_INIT_DELAY + if(rsbac_no_delay_init) +#endif + rsbac_init(ROOT_DEV); +#endif + } static bool is_tmpfs; diff --git a/init/main.c b/init/main.c index 052481fbe363..9123435d4baf 100644 --- a/init/main.c +++ b/init/main.c @@ -95,6 +95,8 @@ #include #include +#include + static int kernel_init(void *); extern void init_IRQ(void); @@ -677,6 +679,9 @@ asmlinkage __visible void __init start_kernel(void) key_init(); security_init(); dbg_late_init(); +#ifdef CONFIG_RSBAC + rsbac_kthreads_init(); +#endif vfs_caches_init(); pagecache_init(); signals_init(); diff --git a/ipc/msg.c b/ipc/msg.c index 2c38f10d1483..34715de0d892 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -41,6 +41,7 @@ #include #include #include "util.h" +#include /* one msg_receiver structure for each sleeping receiver */ struct msg_receiver { @@ -118,7 +119,26 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params) key_t key = params->key; int msgflg = params->flg; - msq = kvmalloc(sizeof(*msq), GFP_KERNEL); +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + rsbac_pr_debug(aef, "[sys_msgget()]: calling ADF\n"); + rsbac_target_id.ipc.type = I_msg; + rsbac_target_id.ipc.id.id_nr = 0; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + + msq = kvmalloc(sizeof(*msq), GFP_KERNEL); if (unlikely(!msq)) return -ENOMEM; @@ -148,6 +168,24 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params) return retval; } +#ifdef CONFIG_RSBAC + rsbac_target_id.ipc.type = I_msg; + rsbac_target_id.ipc.id.id_nr = msq->q_perm.id; + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_CREATE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "newque() [sys_msgget()]: rsbac_adf_set_attr() returned error"); + } +#endif + + ipc_unlock_object(&msq->q_perm); rcu_read_unlock(); @@ -367,6 +405,11 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd, struct msqid64_ds uninitialized_var(msqid64); struct msg_queue *msq; int err; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif if (cmd == IPC_SET) { if (copy_msqid_from_user(&msqid64, buf, version)) @@ -391,9 +434,40 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd, switch (cmd) { case IPC_RMID: +#ifdef CONFIG_RSBAC + rsbac_target_id.ipc.type = I_msg; + rsbac_target_id.ipc.id.id_nr = msqid; + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_DELETE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto out_unlock1; + } +#endif + ipc_lock_object(&msq->q_perm); /* freeque unlocks the ipc object and rcu */ freeque(ns, ipcp); + +#ifdef CONFIG_RSBAC + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_DELETE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_msgctl(): rsbac_adf_set_attr() returned error"); + } +#endif goto out_up; case IPC_SET: { @@ -405,6 +479,50 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd, goto out_unlock1; } +#ifdef CONFIG_RSBAC + rsbac_target_id.ipc.type = I_msg; + rsbac_target_id.ipc.id.id_nr = msqid; + if (__kuid_val(ipcp->uid) != msqid64.msg_perm.uid) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.owner = msqid64.msg_perm.uid; + if (!rsbac_adf_request(R_CHANGE_OWNER, + task_pid(current), + T_IPC, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + err = -EPERM; + goto out_unlock1; + } + } + if (__kgid_val(ipcp->gid) != msqid64.msg_perm.gid) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.group = msqid64.msg_perm.gid; + if (!rsbac_adf_request(R_CHANGE_GROUP, + task_pid(current), + T_IPC, + rsbac_target_id, + A_group, + rsbac_attribute_value)) { + err = -EPERM; + goto out_unlock1; + } + } + if (ipcp->mode != ((ipcp->mode & ~S_IRWXUGO) | (S_IRWXUGO & msqid64.msg_perm.mode))) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.mode = (S_IRWXUGO & msqid64.msg_perm.mode); + if (!rsbac_adf_request(R_ALTER, + task_pid(current), + T_IPC, + rsbac_target_id, + A_mode, + rsbac_attribute_value)) { + err = -EPERM; + goto out_unlock1; + } + } +#endif + ipc_lock_object(&msq->q_perm); err = ipc_update_perm(&msqid64.msg_perm, ipcp); if (err) @@ -636,6 +754,12 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, struct ipc_namespace *ns; DEFINE_WAKE_Q(wake_q); +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + ns = current->nsproxy->ipc_ns; if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0) @@ -643,6 +767,21 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, if (mtype < 1) return -EINVAL; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.ipc.type = I_msg; + rsbac_target_id.ipc.id.id_nr = msqid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEND, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + msg = load_msg(mtext, msgsz); if (IS_ERR(msg)) return PTR_ERR(msg); @@ -727,6 +866,21 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, atomic_inc(&ns->msg_hdrs); } +#ifdef CONFIG_RSBAC + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_SEND, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_msgsnd(): rsbac_adf_set_attr() returned error"); + } +#endif + err = 0; msg = NULL; @@ -855,11 +1009,32 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl struct msg_msg *msg, *copy = NULL; DEFINE_WAKE_Q(wake_q); +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + ns = current->nsproxy->ipc_ns; if (msqid < 0 || (long) bufsz < 0) return -EINVAL; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.ipc.type = I_msg; + rsbac_target_id.ipc.id.id_nr = msqid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_RECEIVE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + if (msgflg & MSG_COPY) { if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT)) return -EINVAL; @@ -902,6 +1077,23 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl msg = ERR_PTR(-E2BIG); goto out_unlock0; } + + /* RSBAC: notify ADF of opened ipc */ +#ifdef CONFIG_RSBAC + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_RECEIVE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_msgrcv(): rsbac_adf_set_attr() returned error"); + } +#endif + /* * If we are copying, then do not unlink message and do * not update queue parameters. diff --git a/ipc/sem.c b/ipc/sem.c index 38371e93bfa5..12302726a65f 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -86,6 +86,7 @@ #include #include "util.h" +#include /* One queue for each sleeping process in the system. */ @@ -480,11 +481,32 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) int semflg = params->flg; int i; +#ifdef CONFIG_RSBAC_IPC_SEM + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!nsems) return -EINVAL; if (ns->used_sems + nsems > ns->sc_semmns) return -ENOSPC; +#ifdef CONFIG_RSBAC_IPC_SEM + rsbac_pr_debug(aef, "[sys_semget()]: calling ADF\n"); + rsbac_target_id.ipc.type = I_sem; + rsbac_target_id.ipc.id.id_nr = 0; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + sma = sem_alloc(nsems); if (!sma) return -ENOMEM; @@ -520,6 +542,22 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) } ns->used_sems += nsems; +/* RSBAC: notify ADF of new shm */ +#ifdef CONFIG_RSBAC_IPC_SEM + rsbac_target_id.ipc.id.id_nr = sma->sem_perm.id; + rsbac_new_target_id.dummy = 0; + if (rsbac_adf_set_attr(R_CREATE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value)) + rsbac_printk(KERN_WARNING + "newary() [sys_semget()]: rsbac_adf_set_attr() returned error\n"); +#endif + sem_unlock(sma, -1); rcu_read_unlock(); @@ -1275,6 +1313,11 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, int err, val; DEFINE_WAKE_Q(wake_q); +#ifdef CONFIG_RSBAC_IPC_SEM + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + #if defined(CONFIG_64BIT) && defined(__BIG_ENDIAN) /* big-endian 64bit */ val = arg >> 32; @@ -1310,6 +1353,22 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, return -EACCES; } +#ifdef CONFIG_RSBAC_IPC_SEM + rsbac_target_id.ipc.type = I_sem; + rsbac_target_id.ipc.id.id_nr = semid; + rsbac_pr_debug(aef, "[sys_semctl()]: calling ADF\n"); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_WRITE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + rcu_read_unlock(); + return -EPERM; + } +#endif + sem_lock(sma, NULL, -1); if (!ipc_valid_object(&sma->sem_perm)) { @@ -1345,6 +1404,12 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, ushort *sem_io = fast_sem_io; DEFINE_WAKE_Q(wake_q); +#ifdef CONFIG_RSBAC_IPC_SEM + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + rcu_read_lock(); sma = sem_obtain_object_check(ns, semid); if (IS_ERR(sma)) { @@ -1395,6 +1460,22 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, goto out_unlock; } } +#ifdef CONFIG_RSBAC_IPC_SEM + rsbac_target_id.ipc.type = I_sem; + rsbac_target_id.ipc.id.id_nr = semid; + rsbac_pr_debug(aef, "[sys_semctl()]: calling ADF\n"); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_READ, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto out_unlock; + } +#endif + for (i = 0; i < sma->sem_nsems; i++) sem_io[i] = sma->sems[i].semval; sem_unlock(sma, -1); @@ -1402,6 +1483,25 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, err = 0; if (copy_to_user(array, sem_io, nsems*sizeof(ushort))) err = -EFAULT; + + /* RSBAC: notify ADF of read sem */ +#ifdef CONFIG_RSBAC_IPC_SEM + if(!err) { + rsbac_new_target_id.dummy = 0; + if (rsbac_adf_set_attr(R_READ, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value)) { + rsbac_printk(KERN_WARNING + "semctl_main() [sys_semctl()]: rsbac_adf_set_attr() returned error"); + } + } +#endif + goto out_free; } case SETALL: @@ -1430,6 +1530,23 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, goto out_free; } +#ifdef CONFIG_RSBAC_IPC_SEM + rsbac_target_id.ipc.type = I_sem; + rsbac_target_id.ipc.id.id_nr = semid; + rsbac_pr_debug(aef, "[sys_semctl()]: calling ADF\n"); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_WRITE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + ipc_rcu_putref(&sma->sem_perm, sem_rcu_free); + goto out_free; + } +#endif + for (i = 0; i < nsems; i++) { if (sem_io[i] > SEMVMX) { ipc_rcu_putref(&sma->sem_perm, sem_rcu_free); @@ -1455,6 +1572,23 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, un->semadj[i] = 0; } sma->sem_ctime = get_seconds(); + + /* RSBAC: notify ADF of written sem */ +#ifdef CONFIG_RSBAC_IPC_SEM + rsbac_new_target_id.dummy = 0; + if (rsbac_adf_set_attr(R_WRITE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value)) { + rsbac_printk(KERN_WARNING + "semctl_main() [sys_semctl()]: rsbac_adf_set_attr() returned error"); + } +#endif + /* maybe some queued-up processes were waiting for this */ do_smart_update(sma, NULL, 0, 0, &wake_q); err = 0; @@ -1538,6 +1672,12 @@ static int semctl_down(struct ipc_namespace *ns, int semid, struct semid64_ds semid64; struct kern_ipc_perm *ipcp; +#ifdef CONFIG_RSBAC_IPC_SEM + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (cmd == IPC_SET) { if (copy_semid_from_user(&semid64, p, version)) return -EFAULT; @@ -1561,11 +1701,88 @@ static int semctl_down(struct ipc_namespace *ns, int semid, switch (cmd) { case IPC_RMID: +#ifdef CONFIG_RSBAC_IPC_SEM + rsbac_target_id.ipc.type = I_sem; + rsbac_target_id.ipc.id.id_nr = semid; + rsbac_pr_debug(aef, "[sys_semctl()]: calling ADF\n"); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_DELETE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto out_unlock1; + } +#endif + sem_lock(sma, NULL, -1); /* freeary unlocks the ipc object and rcu */ freeary(ns, ipcp); + + /* RSBAC: notify ADF of deleted sem */ +#ifdef CONFIG_RSBAC_IPC_SEM + rsbac_new_target_id.dummy = 0; + if (rsbac_adf_set_attr(R_DELETE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value)) { + rsbac_printk(KERN_WARNING + "semctl_down() [sys_semctl()]: rsbac_adf_set_attr() returned error"); + } +#endif + goto out_up; case IPC_SET: +#ifdef CONFIG_RSBAC_IPC_SEM + rsbac_target_id.ipc.type = I_sem; + rsbac_target_id.ipc.id.id_nr = semid; + if (__kuid_val(ipcp->uid) != semid64.sem_perm.uid) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.owner = semid64.sem_perm.uid; + if (!rsbac_adf_request(R_CHANGE_OWNER, + task_pid(current), + T_IPC, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + err = -EPERM; + goto out_unlock1; + } + } + if (__kgid_val(ipcp->gid) != semid64.sem_perm.gid) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.group = semid64.sem_perm.gid; + if (!rsbac_adf_request(R_CHANGE_GROUP, + task_pid(current), + T_IPC, + rsbac_target_id, + A_group, + rsbac_attribute_value)) { + err = -EPERM; + goto out_unlock1; + } + } + if (ipcp->mode != ((ipcp->mode & ~S_IRWXUGO) | (S_IRWXUGO & semid64.sem_perm.mode))) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.mode = (S_IRWXUGO & semid64.sem_perm.mode); + if (!rsbac_adf_request(R_ALTER, + task_pid(current), + T_IPC, + rsbac_target_id, + A_mode, + rsbac_attribute_value)) { + err = -EPERM; + goto out_unlock1; + } + } +#endif + sem_lock(sma, NULL, -1); err = ipc_update_perm(&semid64.sem_perm, ipcp); if (err) diff --git a/ipc/shm.c b/ipc/shm.c index 8828b4c3a190..3a387c986f66 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -47,6 +47,11 @@ #include "util.h" +#include +#if defined(CONFIG_RSBAC_MPROTECT) +#include +#endif + struct shm_file_data { int id; struct ipc_namespace *ns; @@ -231,6 +236,10 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) { struct file *shm_file; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; +#endif + shm_file = shp->shm_file; shp->shm_file = NULL; ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; @@ -242,6 +251,14 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) user_shm_unlock(i_size_read(file_inode(shm_file)), shp->mlock_user); fput(shm_file); + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ACI remove_target()\n"); + rsbac_target_id.ipc.type = I_shm; + rsbac_target_id.ipc.id.id_nr = shp->shm_perm.id; + rsbac_remove_target(T_IPC, rsbac_target_id); +#endif + ipc_rcu_putref(&shp->shm_perm, shm_rcu_free); } @@ -275,6 +292,27 @@ static void shm_close(struct vm_area_struct *vma) struct shmid_kernel *shp; struct ipc_namespace *ns = sfd->ns; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_shmdt() et al.]: calling ADF\n"); + rsbac_target_id.ipc.type = I_shm; + rsbac_target_id.ipc.id.id_nr = sfd->id; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_CLOSE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + rsbac_printk(KERN_WARNING + "shm_close() [sys_shmdt() et al.]: rsbac_adf_request() for CLOSE returned NOT_GRANTED\n"); + } +#endif + down_write(&shm_ids(ns).rwsem); /* remove from the list of attaches of the shm segment */ shp = shm_lock(ns, sfd->id); @@ -532,6 +570,12 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) char name[13]; vm_flags_t acctflag = 0; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (size < SHMMIN || size > ns->shm_ctlmax) return -EINVAL; @@ -542,6 +586,21 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) ns->shm_tot + numpages > ns->shm_ctlall) return -ENOSPC; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_shmget()]: calling ADF\n"); + rsbac_target_id.ipc.type = I_shm; + rsbac_target_id.ipc.id.id_nr = 0; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + shp = kvmalloc(sizeof(*shp), GFP_KERNEL); if (unlikely(!shp)) return -ENOMEM; @@ -615,6 +674,24 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) ipc_unlock_object(&shp->shm_perm); rcu_read_unlock(); + +#ifdef CONFIG_RSBAC + rsbac_target_id.ipc.id.id_nr = file->f_path.dentry->d_inode->i_ino; + rsbac_new_target_id.ipc.type = I_shm; + rsbac_new_target_id.ipc.id.id_nr = file->f_path.dentry->d_inode->i_ino; + if (rsbac_adf_set_attr(R_CREATE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_IPC, + rsbac_new_target_id, + A_none, + rsbac_attribute_value)) { + rsbac_printk(KERN_WARNING + "newseg() [sys_shmget()]: rsbac_adf_set_attr() returned error"); + } +#endif + return error; no_id: @@ -988,6 +1065,12 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) int err, version; struct ipc_namespace *ns; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + union rsbac_target_id_t rsbac_new_target_id; +#endif + if (cmd < 0 || shmid < 0) return -EINVAL; @@ -1001,6 +1084,41 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) case IPC_STAT: return shmctl_nolock(ns, shmid, cmd, version, buf); case IPC_RMID: + +#ifdef CONFIG_RSBAC + rsbac_target_id.ipc.type = I_shm; + rsbac_target_id.ipc.id.id_nr = shmid; + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_DELETE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } + err = shmctl_down(ns, shmid, cmd, buf, version); + if (!err) { + rsbac_target_id.ipc.type = I_shm; + rsbac_target_id.ipc.id.id_nr = shmid; + rsbac_attribute_value.dummy = 0; + rsbac_new_target_id.dummy = 0; + if (rsbac_adf_set_attr(R_DELETE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value)) { + rsbac_printk(KERN_WARNING + "sys_shmctl(): rsbac_adf_set_attr() returned error"); + } + } + return err; +#endif + case IPC_SET: return shmctl_down(ns, shmid, cmd, buf, version); case SHM_LOCK: @@ -1106,6 +1224,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, fmode_t f_mode; unsigned long populate = 0; +#ifdef CONFIG_RSBAC + enum rsbac_adf_request_t rsbac_request = R_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + err = -EINVAL; if (shmid < 0) goto out; @@ -1144,6 +1269,22 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, acc_mode |= S_IXUGO; } +#ifdef CONFIG_RSBAC_MPROTECT + if ( (prot & PROT_EXEC) + && (prot & PROT_WRITE) + && !rsbac_write_exec_allowed(NULL, prot) + ) { + char * program_name = rsbac_get_program_name(); + + rsbac_printk(KERN_INFO "do_shmat(): RSBAC mprotect: denied WRITE and EXEC, pid %u(%s)\n", + current->pid, program_name); + if (program_name) + rsbac_kfree(program_name); + err = -EPERM; + goto out; + } +#endif + /* * We cannot rely on the fs check since SYSV IPC does have an * additional creator id... @@ -1173,6 +1314,27 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, goto out_unlock; } +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + if ((shmflg & SHM_RDONLY)) + rsbac_request = R_READ_OPEN; + else + rsbac_request = R_READ_WRITE_OPEN; + rsbac_target_id.ipc.type = I_shm; + rsbac_target_id.ipc.id.id_nr = shp->shm_perm.id; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_IPC, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + ipc_unlock_object(&shp->shm_perm); + goto out_unlock; + } +#endif + path = shp->shm_file->f_path; path_get(&path); shp->shm_nattch++; @@ -1245,6 +1407,25 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, else shm_unlock(shp); up_write(&shm_ids(ns).rwsem); + +/* RSBAC: notify ADF of attached shm */ +#ifdef CONFIG_RSBAC + if(!err) { + rsbac_new_target_id.dummy = 0; + if (rsbac_adf_set_attr(rsbac_request, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value)) { + rsbac_printk(KERN_WARNING + "sys_shmat(): rsbac_adf_set_attr() returned error"); + } + } +#endif + return err; out_unlock: diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 6c772adabad2..abaff2252362 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -24,6 +24,10 @@ #include #include +#ifdef CONFIG_RSBAC +#include +#endif + #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY || \ (map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \ (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \ @@ -1390,6 +1394,12 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz union bpf_attr attr = {}; int err; +#ifdef CONFIG_RSBAC_NET + enum rsbac_adf_request_t rsbac_adf_req; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled) return -EPERM; @@ -1413,6 +1423,29 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz if (copy_from_user(&attr, uattr, size) != 0) return -EFAULT; +#ifdef CONFIG_RSBAC_NET + switch (cmd) { + case BPF_MAP_LOOKUP_ELEM: + case BPF_MAP_GET_NEXT_KEY: + rsbac_adf_req = R_GET_STATUS_DATA; + break; + default: + rsbac_adf_req = R_MODIFY_SYSTEM_DATA; + break; + } + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_firewall; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(rsbac_adf_req, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + switch (cmd) { case BPF_MAP_CREATE: err = map_create(&attr); diff --git a/kernel/capability.c b/kernel/capability.c index f97fe77ceb88..0c5bfb611a0e 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -19,6 +19,8 @@ #include #include +#include + /* * Leveraged for setting/resetting capabilities */ @@ -119,6 +121,15 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, { int ret; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_target_id.process = NULL; +#endif + if (pid && (pid != task_pid_vnr(current))) { struct task_struct *target; @@ -127,12 +138,36 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, target = find_task_by_vpid(pid); if (!target) ret = -ESRCH; - else + else { ret = security_capget(target, pEp, pIp, pPp); +#ifdef CONFIG_RSBAC + rsbac_target_id.process = get_task_pid(target, PIDTYPE_PID); +#endif + } rcu_read_unlock(); - } else + } else { ret = security_capget(current, pEp, pIp, pPp); +#ifdef CONFIG_RSBAC + rsbac_target_id.process = get_task_pid(current, PIDTYPE_PID); +#endif + } +#ifdef CONFIG_RSBAC + if(!ret) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.dummy = 0; + if(!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + ret = -EPERM; + } + } + if (rsbac_target_id.process) + put_pid(rsbac_target_id.process); +#endif return ret; } @@ -229,6 +264,12 @@ SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data) int ret; pid_t pid; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + ret = cap_validate_magic(header, &tocopy); if (ret != 0) return ret; @@ -272,9 +313,47 @@ SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data) if (ret < 0) goto error; +#ifdef CONFIG_RSBAC + if (!cap_issubset(effective, new->cap_effective) + || !cap_issubset(permitted, new->cap_permitted) + || !cap_issubset(inheritable, new->cap_inheritable)) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_capability; + rsbac_attribute_value.dummy = 0; + if(!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + ret = -EPERM; + goto error; + } + } +#endif + audit_log_capset(new, current_cred()); - return commit_creds(new); + ret = commit_creds(new); + +#ifdef CONFIG_RSBAC + if (!ret) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_setcap(): rsbac_adf_set_attr() returned error"); + } + } +#endif + + return ret; error: abort_creds(new); @@ -377,6 +456,9 @@ static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit) current->flags |= PF_SUPERPRIV; return true; } +#if defined(CONFIG_RSBAC_CAP_LOG_MISSING) || defined(CONFIG_RSBAC_JAIL_LOG_MISSING) + rsbac_log_missing_cap(cap); +#endif return false; } diff --git a/kernel/cred.c b/kernel/cred.c index ecf03657e71c..70d69fc7cdaf 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -243,7 +243,9 @@ struct cred *cred_alloc_blank(void) */ struct cred *prepare_creds(void) { +#ifndef CONFIG_RSBAC struct task_struct *task = current; +#endif const struct cred *old; struct cred *new; @@ -255,7 +257,11 @@ struct cred *prepare_creds(void) kdebug("prepare_creds() alloc %p", new); +#ifdef CONFIG_RSBAC + old = current_cred(); +#else old = task->cred; +#endif memcpy(new, old, sizeof(struct cred)); atomic_set(&new->usage, 1); diff --git a/kernel/exit.c b/kernel/exit.c index c5548faa9f37..7dc94e916a3d 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -68,6 +68,8 @@ #include #include +#include + static void __unhash_process(struct task_struct *p, bool group_dead) { nr_threads--; @@ -764,6 +766,12 @@ void __noreturn do_exit(long code) { struct task_struct *tsk = current; int group_dead; + +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + TASKS_RCU(int tasks_rcu_i); profile_task_exit(tsk); @@ -828,6 +836,22 @@ void __noreturn do_exit(long code) preempt_count_set(PREEMPT_ENABLED); } +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "do_exit() [sys_exit()]: calling ADF\n"); + rsbac_target_id.process = get_task_pid(tsk, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_TERMINATE, + rsbac_target_id.process, + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + rsbac_printk(KERN_WARNING + "do_exit() [sys_exit()]: ADF request for TERMINATE returned NOT_GRANTED!\n"); + } + put_pid(rsbac_target_id.process); +#endif + /* sync mm's RSS info before statistics gathering */ if (tsk->mm) sync_mm_rss(tsk->mm); diff --git a/kernel/fork.c b/kernel/fork.c index 17921b0390b4..fca4866432b0 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -96,6 +96,8 @@ #include #include +#include + #include #define CREATE_TRACE_POINTS @@ -1994,7 +1996,11 @@ struct task_struct *fork_idle(int cpu) * It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. */ +#ifdef CONFIG_RSBAC +long _do_fork(unsigned long long clone_flags, +#else long _do_fork(unsigned long clone_flags, +#endif unsigned long stack_start, unsigned long stack_size, int __user *parent_tidptr, @@ -2005,6 +2011,30 @@ long _do_fork(unsigned long clone_flags, int trace = 0; long nr; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + enum rsbac_attribute_t rsbac_attribute; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_attribute = A_none; + rsbac_attribute_value.dummy = 0; + if(current->pid) { + rsbac_pr_debug(aef, "[sys_fork(),sys_clone(),sys_vfork]: calling ADF\n"); + rsbac_target_id.process = task_pid(current); + if (!rsbac_adf_request(R_CLONE, + rsbac_target_id.process, + T_PROCESS, + rsbac_target_id, + rsbac_attribute, + rsbac_attribute_value)) { + return -EPERM; + } + } +#endif + /* * Determine whether and which event to report to ptracer. When * called from kernel_thread or CLONE_UNTRACED is explicitly @@ -2048,6 +2078,33 @@ long _do_fork(unsigned long clone_flags, get_task_struct(p); } +#ifdef CONFIG_RSBAC + if (clone_flags & CLONE_KTHREAD) { + rsbac_attribute = A_kernel_thread; + rsbac_attribute_value.kernel_thread = 1; + rsbac_mark_kthread(task_pid(p)); + rsbac_kthread_notify(task_pid(p)); + } + + if (current->pid) + { + rsbac_pr_debug(aef, "[sys_fork(),sys_clone(),sys_vfork()]: calling ADF_set_attr\n"); + rsbac_target_id.process = task_pid(current); + rsbac_new_target_id.process = task_pid(p); + if (unlikely(rsbac_adf_set_attr(R_CLONE, + rsbac_target_id.process, + T_PROCESS, + rsbac_target_id, + T_PROCESS, + rsbac_new_target_id, + rsbac_attribute, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "do_fork() [sys_fork(), sys_clone()]: rsbac_adf_set_attr() returned error!\n"); + } + } +#endif + wake_up_new_task(p); /* forking complete and child started to run, tell ptracer */ @@ -2069,7 +2126,11 @@ long _do_fork(unsigned long clone_flags, #ifndef CONFIG_HAVE_COPY_THREAD_TLS /* For compatibility with architectures that call do_fork directly rather than * using the syscall entry points below. */ +#ifdef CONFIG_RSBAC +long do_fork(unsigned long long clone_flags, +#else long do_fork(unsigned long clone_flags, +#endif unsigned long stack_start, unsigned long stack_size, int __user *parent_tidptr, @@ -2085,8 +2146,13 @@ long do_fork(unsigned long clone_flags, */ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { +#ifdef CONFIG_RSBAC + return _do_fork(flags|CLONE_VM|CLONE_UNTRACED|CLONE_KTHREAD, (unsigned long)fn, + (unsigned long)arg, NULL, NULL, 0); +#else return _do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn, (unsigned long)arg, NULL, NULL, 0); +#endif } #ifdef __ARCH_WANT_SYS_FORK diff --git a/kernel/groups.c b/kernel/groups.c index 434f6665f187..833fb72444ef 100644 --- a/kernel/groups.c +++ b/kernel/groups.c @@ -11,6 +11,8 @@ #include #include +#include + struct group_info *groups_alloc(int gidsetsize) { struct group_info *gi; @@ -191,6 +193,12 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) struct group_info *group_info; int retval; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + int i; +#endif + if (!may_setgroups()) return -EPERM; if ((unsigned)gidsetsize > NGROUPS_MAX) @@ -205,6 +213,25 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) return retval; } +#ifdef CONFIG_RSBAC + if (gidsetsize > 0) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = task_pid(current); + for (i=0; i < gidsetsize; i++) { + rsbac_attribute_value.group = RSBAC_GEN_GID(RSBAC_UM_VIRTUAL_KEEP, __kgid_val(group_info->gid[i])); + if(!rsbac_adf_request(R_CHANGE_GROUP, + rsbac_target_id.process, + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value)) { + put_group_info(group_info); + return -EPERM; + } + } + } +#endif + retval = set_current_groups(group_info); put_group_info(group_info); diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 127e7cfafa55..53a5a01ab7d5 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -28,6 +28,10 @@ #include +#ifdef CONFIG_RSBAC +#include +#endif + /* * These will be re-linked against their real values * during the second link stage. @@ -620,6 +624,27 @@ static int kallsyms_open(struct inode *inode, struct file *file) * using get_symbol_offset for every symbol. */ struct kallsym_iter *iter; + +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_target_id.scd = ST_ksyms; + rsbac_attribute_value.dummy = 0; + rsbac_pr_debug(aef, "calling ADF\n"); + if(!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + iter = __seq_open_private(file, &kallsyms_op, sizeof(*iter)); if (!iter) return -ENOMEM; diff --git a/kernel/kexec.c b/kernel/kexec.c index e62ec4dc6620..cd48df52b6ce 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -18,6 +18,8 @@ #include #include +#include + #include "kexec_internal.h" static int copy_user_segment_list(struct kimage *image, @@ -197,10 +199,29 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, { int result; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + /* We only trust the superuser with rebooting the system. */ if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) return -EPERM; +#ifdef CONFIG_RSBAC + rsbac_target_id.scd = ST_kexec; + rsbac_attribute_value.dummy = 0; + rsbac_pr_debug(aef, "calling ADF\n"); + if(!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + /* * Verify we have a legal set of flags * This leaves us room for future extensions. diff --git a/kernel/module.c b/kernel/module.c index 40f983cbea81..d96a9f7c216c 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -67,6 +67,8 @@ #include #include "module-internal.h" +#include + #define CREATE_TRACE_POINTS #include @@ -958,6 +960,11 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, char name[MODULE_NAME_LEN]; int ret, forced = 0; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!capable(CAP_SYS_MODULE) || modules_disabled) return -EPERM; @@ -967,6 +974,19 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, audit_log_kern_module(name); +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.dummy = 0; + rsbac_attribute_value.mod_name = name; + if (!rsbac_adf_request(R_REMOVE_FROM_KERNEL, + task_pid(current), + T_NONE, + rsbac_target_id, + A_mod_name, + rsbac_attribute_value)) + return -EPERM; +#endif + if (mutex_lock_interruptible(&module_mutex) != 0) return -EINTR; @@ -3819,10 +3839,29 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, int err; struct load_info info = { }; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + err = may_init_module(); if (err) return err; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.dummy = 0; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_ADD_TO_KERNEL, + task_pid(current), + T_NONE, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n", umod, len, uargs); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index fc47863f629c..57151aab8388 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -52,6 +52,8 @@ #include #include +#include + #define CREATE_TRACE_POINTS #include @@ -1433,10 +1435,53 @@ int do_syslog(int type, char __user *buf, int len, int source) static int saved_console_loglevel = LOGLEVEL_DEFAULT; int error; +#ifdef CONFIG_RSBAC_SYSLOG + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + error = check_syslog_permissions(type, source); if (error) goto out; +#ifdef CONFIG_RSBAC_SYSLOG + rsbac_pr_debug(aef, "[sys_syslog()]: calling ADF\n"); + rsbac_target_id.scd = ST_syslog; + rsbac_attribute_value.dummy = 0; + switch(type) { + case SYSLOG_ACTION_READ: + case SYSLOG_ACTION_READ_ALL: + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + goto out; + } + break; + case SYSLOG_ACTION_READ_CLEAR: + case SYSLOG_ACTION_CLEAR: + case SYSLOG_ACTION_CONSOLE_OFF: + case SYSLOG_ACTION_CONSOLE_ON: + case SYSLOG_ACTION_CONSOLE_LEVEL: + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + error = -EPERM; + goto out; + } + break; + + default: + break; + } +#endif + switch (type) { case SYSLOG_ACTION_CLOSE: /* Close log */ break; diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 60f356d91060..1e86eaddb72d 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -30,6 +30,8 @@ #include #include +#include + /* * Access another process' address space via ptrace. * Source/target buffer must be kernel space, @@ -1126,7 +1128,27 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, struct task_struct *child; long ret; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (request == PTRACE_TRACEME) { +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "sys_ptrace(): calling ADF\n"); + rsbac_target_id.process = task_pid(current); + rsbac_attribute_value.trace_request = PTRACE_TRACEME; + if (!rsbac_adf_request(R_TRACE, + rsbac_target_id.process, + T_PROCESS, + rsbac_target_id, + A_trace_request, + rsbac_attribute_value)) { + ret = -EPERM; + goto out; + } +#endif + ret = ptrace_traceme(); if (!ret) arch_ptrace_attach(current); @@ -1139,6 +1161,23 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, goto out; } +#ifdef CONFIG_RSBAC + if (request != PTRACE_DETACH) { + rsbac_pr_debug(aef, "sys_ptrace(): calling ADF\n"); + rsbac_target_id.process = task_pid(child); + rsbac_attribute_value.trace_request = request; + if (!rsbac_adf_request(R_TRACE, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_trace_request, + rsbac_attribute_value)) { + ret = -EPERM; + goto out_put_task_struct; + } + } +#endif + if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) { ret = ptrace_attach(child, request, addr, data); /* @@ -1275,7 +1314,27 @@ COMPAT_SYSCALL_DEFINE4(ptrace, compat_long_t, request, compat_long_t, pid, struct task_struct *child; long ret; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (request == PTRACE_TRACEME) { +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "compat_sys_ptrace(): calling ADF\n"); + rsbac_target_id.process = task_pid(current); + rsbac_attribute_value.trace_request = PTRACE_TRACEME; + if (!rsbac_adf_request(R_TRACE, + rsbac_target_id.process, + T_PROCESS, + rsbac_target_id, + A_trace_request, + rsbac_attribute_value)) { + ret = -EPERM; + goto out; + } +#endif + ret = ptrace_traceme(); goto out; } @@ -1286,6 +1345,23 @@ COMPAT_SYSCALL_DEFINE4(ptrace, compat_long_t, request, compat_long_t, pid, goto out; } +#ifdef CONFIG_RSBAC + if (request != PTRACE_DETACH) { + rsbac_pr_debug(aef, "compat_sys_ptrace(): calling ADF\n"); + rsbac_target_id.process = task_pid(child); + rsbac_attribute_value.trace_request = request; + if (!rsbac_adf_request(R_TRACE, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_trace_request, + rsbac_attribute_value)) { + ret = -EPERM; + goto out_put_task_struct; + } + } +#endif + if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) { ret = ptrace_attach(child, request, addr, data); /* diff --git a/kernel/reboot.c b/kernel/reboot.c index bd30a973fe94..24fbb7b12534 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -17,6 +17,11 @@ #include #include +#ifdef CONFIG_RSBAC +#include +#include +#endif + /* * this indicates whether you can reboot with ctrl-alt-del: the default is yes */ @@ -284,6 +289,11 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, char buffer[256]; int ret = 0; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + /* We only trust the superuser with rebooting the system. */ if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT)) return -EPERM; @@ -311,6 +321,20 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) cmd = LINUX_REBOOT_CMD_HALT; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.dummy = 0; + rsbac_attribute_value.reboot_cmd = cmd; + if (!rsbac_adf_request(R_SHUTDOWN, + task_pid(current), + T_NONE, + rsbac_target_id, + A_reboot_cmd, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + mutex_lock(&reboot_mutex); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 0869b20fba81..b4f289714186 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -33,6 +33,8 @@ #include #endif +#include + #include "sched.h" #include "../workqueue_internal.h" #include "../smpboot.h" @@ -3818,6 +3820,10 @@ int can_nice(const struct task_struct *p, const int nice) SYSCALL_DEFINE1(nice, int, increment) { long nice, retval; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif /* * Setpriority might change our priority at the same moment. @@ -3831,6 +3837,22 @@ SYSCALL_DEFINE1(nice, int, increment) if (increment < 0 && !can_nice(current, nice)) return -EPERM; +#ifdef CONFIG_RSBAC + if (increment < 0) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_priority; + rsbac_attribute_value.priority = nice; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_priority, + rsbac_attribute_value)) { + return -EPERM; + } + } +#endif + retval = security_task_setnice(current, nice); if (retval) return retval; @@ -4277,6 +4299,12 @@ do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param) struct task_struct *p; int retval; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!param || pid < 0) return -EINVAL; if (copy_from_user(&lparam, param, sizeof(struct sched_param))) @@ -4285,8 +4313,31 @@ do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param) rcu_read_lock(); retval = -ESRCH; p = find_process_by_pid(pid); - if (p != NULL) + if (p != NULL) { + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_sched_setscheduler, sys_sched_setparam]: calling ADF\n"); + if (!pid || (pid == current->pid)) { + rsbac_target = T_SCD; + rsbac_target_id.scd = ST_priority; + } else { + rsbac_target = T_PROCESS; + rsbac_target_id.process = task_pid(p); + } + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + rcu_read_unlock(); + return -EPERM; + } +#endif + retval = sched_setscheduler(p, policy, &lparam); + } rcu_read_unlock(); return retval; @@ -4435,6 +4486,12 @@ SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid) struct task_struct *p; int retval; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (pid < 0) return -EINVAL; @@ -4443,6 +4500,29 @@ SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid) p = find_process_by_pid(pid); if (p) { retval = security_task_getscheduler(p); + +#ifdef CONFIG_RSBAC + if (!retval) { + rsbac_pr_debug(aef, "[sys_sched_getscheduler]: calling ADF\n"); + if (!pid || (pid == current->pid)) { + rsbac_target = T_SCD; + rsbac_target_id.scd = ST_priority; + } else { + rsbac_target = T_PROCESS; + rsbac_target_id.process = task_pid(p); + } + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + retval = -EPERM; + } + } +#endif + if (!retval) retval = p->policy | (p->sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0); @@ -4465,6 +4545,12 @@ SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param) struct task_struct *p; int retval; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!param || pid < 0) return -EINVAL; @@ -4478,6 +4564,27 @@ SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param) if (retval) goto out_unlock; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_sched_getparam]: calling ADF\n"); + if (!pid || (pid == current->pid)) { + rsbac_target = T_SCD; + rsbac_target_id.scd = ST_priority; + } else { + rsbac_target = T_PROCESS; + rsbac_target_id.process = task_pid(p); + } + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + retval = -EPERM; + goto out_unlock; + } +#endif + if (task_has_rt_policy(p)) lp.sched_priority = p->rt_priority; rcu_read_unlock(); @@ -4582,6 +4689,12 @@ SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, long sched_setaffinity(pid_t pid, const struct cpumask *in_mask) { +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + cpumask_var_t cpus_allowed, new_mask; struct task_struct *p; int retval; @@ -4624,6 +4737,26 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask) if (retval) goto out_free_new_mask; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_sched_setaffinity]: calling ADF\n"); + if (p == current) { + rsbac_target = T_SCD; + rsbac_target_id.scd = ST_priority; + } else { + rsbac_target = T_PROCESS; + rsbac_target_id.process = task_pid(p); + } + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + retval = -EPERM; + goto out_free_new_mask; + } +#endif cpuset_cpus_allowed(p, cpus_allowed); cpumask_and(new_mask, in_mask, cpus_allowed); @@ -4693,6 +4826,31 @@ SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len, { cpumask_var_t new_mask; int retval; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sched_getaffinity]: calling ADF\n"); + if (!pid || (pid == current->pid)) { + rsbac_target = T_SCD; + rsbac_target_id.scd = ST_priority; + } else { + rsbac_target = T_PROCESS; + rsbac_target_id.process = find_pid_ns(pid, &init_pid_ns); + } + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) return -ENOMEM; @@ -5074,6 +5232,12 @@ SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, struct rq *rq; int retval; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (pid < 0) return -EINVAL; @@ -5087,6 +5251,27 @@ SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, if (retval) goto out_unlock; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_sched_rr_get_interval]: calling ADF\n"); + if (!pid || (pid == current->pid)) { + rsbac_target = T_SCD; + rsbac_target_id.scd = ST_priority; + } else { + rsbac_target = T_PROCESS; + rsbac_target_id.process = task_pid(p); + } + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + retval = -EPERM; + goto out_unlock; + } +#endif + rq = task_rq_lock(p, &rf); time_slice = 0; if (p->sched_class->get_rr_interval) diff --git a/kernel/signal.c b/kernel/signal.c index 7e33f8c583e6..28537242ba46 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -51,6 +51,8 @@ #include #include "audit.h" /* audit_signal_info() */ +#include + /* * SLAB caches for signal bits. */ @@ -736,6 +738,12 @@ static int check_kill_permission(int sig, struct siginfo *info, struct pid *sid; int error; +#ifdef CONFIG_RSBAC + enum rsbac_adf_request_t rsbac_adf_req; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!valid_signal(sig)) return -EINVAL; @@ -762,6 +770,31 @@ static int check_kill_permission(int sig, struct siginfo *info, } } +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "check_kill_permission() [group_send_sig_info(), sys_tgkill(),sys_tkill()]: calling ADF\n"); + rsbac_target_id.process = get_task_pid(t, PIDTYPE_PID); + rsbac_attribute_value.signal = sig; + if (sig) + rsbac_adf_req = R_SEND_SIGNAL; + else + rsbac_adf_req = R_GET_STATUS_DATA; + if ((!info || ((unsigned long)info != 1 + && (unsigned long)info != 2 && SI_FROMUSER(info))) + && ((sig != SIGCONT) || (task_session(current) != task_session(t))) + && !(t->flags & PF_EXITING) + && !rsbac_adf_request(rsbac_adf_req, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_signal, + rsbac_attribute_value) + ) { + put_pid(rsbac_target_id.process); + return -EPERM; + } + put_pid(rsbac_target_id.process); +#endif + return security_task_kill(t, info, sig, 0); } diff --git a/kernel/sys.c b/kernel/sys.c index 2855ee73acd0..f08e394b7f9d 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -68,6 +68,11 @@ #include #include +#ifdef CONFIG_RSBAC +#include +#include +#endif + #ifndef SET_UNALIGN_CTL # define SET_UNALIGN_CTL(a, b) (-EINVAL) #endif @@ -188,6 +193,12 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) struct pid *pgrp; kuid_t uid; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (which > PRIO_USER || which < PRIO_PROCESS) goto out; @@ -198,6 +209,43 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) if (niceval > MAX_NICE) niceval = MAX_NICE; +#ifdef CONFIG_RSBAC + if ((niceval < (current->static_prio - MAX_RT_PRIO - 20)) || ((which == PRIO_PROCESS) + && (who != 0) + && (who != current->pid)) + || ((which == PRIO_PGRP) + && (who != 0) + && (who != current->pid))) { + rsbac_pr_debug(aef, "calling ADF\n"); + if (niceval < (current->static_prio - MAX_RT_PRIO - 20)) { + rsbac_target = T_SCD; + rsbac_target_id.scd = ST_priority; + } else { + rcu_read_lock(); + rsbac_target_id.process = find_pid_ns(who, &init_pid_ns); + if (likely(rsbac_target_id.process)) { + rsbac_target = T_PROCESS; + get_pid(rsbac_target_id.process); + } + rcu_read_unlock(); + } + rsbac_attribute_value.priority = niceval; + if ((rsbac_target != T_NONE) && !rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_priority, + rsbac_attribute_value)) { + error = -EPERM; + if ((rsbac_target == T_PROCESS) && rsbac_target_id.process) + put_pid(rsbac_target_id.process); + goto out; + } + if ((rsbac_target == T_PROCESS) && rsbac_target_id.process) + put_pid(rsbac_target_id.process); + } +#endif + rcu_read_lock(); read_lock(&tasklist_lock); switch (which) { @@ -356,18 +404,65 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) retval = -EPERM; if (rgid != (gid_t) -1) { - if (gid_eq(old->gid, krgid) || + +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = task_pid(current); + rsbac_attribute_value.long_dummy = 0; + rsbac_attribute_value.group = RSBAC_GEN_GID(RSBAC_UM_VIRTUAL_KEEP, rgid); +#endif + + if ((gid_eq(old->gid, krgid) || gid_eq(old->egid, krgid) || ns_capable(old->user_ns, CAP_SETGID)) +#ifdef CONFIG_RSBAC + && rsbac_adf_request(R_CHANGE_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value) +#endif + ) new->gid = krgid; else goto error; } if (egid != (gid_t) -1) { - if (gid_eq(old->gid, kegid) || + +#ifdef CONFIG_RSBAC_DAC_GROUP + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = task_pid(current); + rsbac_attribute_value.long_dummy = 0; + rsbac_attribute_value.group = RSBAC_GEN_GID(RSBAC_UM_VIRTUAL_KEEP, egid); +#endif + + if ((gid_eq(old->gid, kegid) || gid_eq(old->egid, kegid) || gid_eq(old->sgid, kegid) || ns_capable(old->user_ns, CAP_SETGID)) + +#ifdef CONFIG_RSBAC_DAC_GROUP + && rsbac_adf_request(R_CHANGE_DAC_EFF_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value) + && rsbac_adf_request(R_CHANGE_DAC_FS_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value) +#endif + ) new->egid = kegid; else goto error; @@ -398,6 +493,11 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) int retval; kgid_t kgid; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + kgid = make_kgid(ns, gid); if (!gid_valid(kgid)) return -EINVAL; @@ -407,10 +507,57 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) return -ENOMEM; old = current_cred(); +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = task_pid(current); + rsbac_attribute_value.long_dummy = 0; + rsbac_attribute_value.group = RSBAC_GEN_GID(RSBAC_UM_VIRTUAL_KEEP, gid); +#endif + retval = -EPERM; - if (ns_capable(old->user_ns, CAP_SETGID)) + if (ns_capable(old->user_ns, CAP_SETGID) + +#ifdef CONFIG_RSBAC + && rsbac_adf_request(R_CHANGE_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value) +#ifdef CONFIG_RSBAC_DAC_GROUP + && rsbac_adf_request(R_CHANGE_DAC_EFF_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value) + && rsbac_adf_request(R_CHANGE_DAC_FS_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value) +#endif +#endif + ) new->gid = new->egid = new->sgid = new->fsgid = kgid; - else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid)) + else if ((gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid)) + +#ifdef CONFIG_RSBAC_DAC_GROUP + && rsbac_adf_request(R_CHANGE_DAC_EFF_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value) + && rsbac_adf_request(R_CHANGE_DAC_FS_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value) +#endif + ) new->egid = new->fsgid = kgid; else goto error; @@ -474,6 +621,13 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) int retval; kuid_t kruid, keuid; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + rsbac_uid_t rsbac_old_uid; +#endif + kruid = make_kuid(ns, ruid); keuid = make_kuid(ns, euid); @@ -519,7 +673,103 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) if (retval < 0) goto error; - return commit_creds(new); +#ifdef CONFIG_RSBAC + rsbac_old_uid = __kuid_val(old->uid); + rsbac_target_id.process = task_pid(current); + if (ruid != (uid_t) -1) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.long_dummy = 0; + rsbac_attribute_value.owner = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, ruid); + if (!rsbac_adf_request(R_CHANGE_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + retval = -EPERM; + goto error; + } + } +#ifdef CONFIG_RSBAC_DAC_OWNER + if (euid != (uid_t) -1) { + rsbac_pr_debug(aef, "calling ADF for euid\n"); + rsbac_attribute_value.long_dummy = 0; + rsbac_attribute_value.owner = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, euid); + if (!rsbac_adf_request(R_CHANGE_DAC_EFF_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + retval = -EPERM; + goto error; + } + if (!rsbac_adf_request(R_CHANGE_DAC_FS_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + retval = -EPERM; + goto error; + } + } +#endif +#endif + + retval = commit_creds(new); + +#ifdef CONFIG_RSBAC + if(!retval) { + rsbac_target_id.process = task_pid(current); + if(ruid != (uid_t) -1) { + rsbac_set_audit_uid(rsbac_old_uid); + rsbac_attribute_value.owner = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, __kuid_val(current_uid())); + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_CHANGE_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_owner, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_setreuid(): rsbac_adf_set_attr() returned error"); + } + } +#ifdef CONFIG_RSBAC_DAC_OWNER + if(euid != (uid_t) -1) { + rsbac_attribute_value.owner = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, __kuid_val(current_euid())); + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_CHANGE_DAC_EFF_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_owner, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_setreuid(): rsbac_adf_set_attr() for euid returned error"); + } + if (unlikely(rsbac_adf_set_attr(R_CHANGE_DAC_FS_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_owner, + rsbac_attribute_value))) { + printk(KERN_WARNING + "sys_setreuid(): rsbac_adf_set_attr() for fsuid returned error"); + } + } +#endif + } +#endif + + return retval; error: abort_creds(new); @@ -545,10 +795,22 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) int retval; kuid_t kuid; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + uid_t rsbac_old_uid; +#endif + kuid = make_kuid(ns, uid); if (!uid_valid(kuid)) return -EINVAL; +#ifdef CONFIG_RSBAC_FAKE_ROOT_UID + if(!uid && rsbac_uid_faked()) + return 0; +#endif + new = prepare_creds(); if (!new) return -ENOMEM; @@ -572,7 +834,91 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) if (retval < 0) goto error; - return commit_creds(new); +#ifdef CONFIG_RSBAC + rsbac_old_uid = __kuid_val(old->uid); + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = task_pid(current); + rsbac_attribute_value.long_dummy = 0; + rsbac_attribute_value.owner = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, uid); + if(!rsbac_adf_request(R_CHANGE_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + retval = -EPERM; + goto error; + } +#ifdef CONFIG_RSBAC_DAC_OWNER + rsbac_pr_debug(aef, "calling ADF for euid\n"); + if (!rsbac_adf_request(R_CHANGE_DAC_EFF_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + retval = -EPERM; + goto error; + } + rsbac_pr_debug(aef, "calling ADF for fsuid\n"); + if (!rsbac_adf_request(R_CHANGE_DAC_FS_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + retval = -EPERM; + goto error; + } +#endif +#endif + + retval = commit_creds(new); + +#ifdef CONFIG_RSBAC + if (!retval) { + rsbac_target_id.process = task_pid(current); + rsbac_set_audit_uid(rsbac_old_uid); + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_CHANGE_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_owner, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_setuid(): rsbac_adf_set_attr() returned error"); + } +#ifdef CONFIG_RSBAC_DAC_OWNER + if (unlikely(rsbac_adf_set_attr(R_CHANGE_DAC_EFF_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_owner, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_setuid(): rsbac_adf_set_attr() for euid returned error"); + } + if (unlikely(rsbac_adf_set_attr(R_CHANGE_DAC_FS_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_owner, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_setuid(): rsbac_adf_set_attr() for fsuid returned error"); + } +#endif + } +#endif + + return retval; error: abort_creds(new); @@ -592,6 +938,13 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) int retval; kuid_t kruid, keuid, ksuid; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + uid_t rsbac_old_uid; +#endif + kruid = make_kuid(ns, ruid); keuid = make_kuid(ns, euid); ksuid = make_kuid(ns, suid); @@ -642,7 +995,103 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) if (retval < 0) goto error; - return commit_creds(new); +#ifdef CONFIG_RSBAC + rsbac_old_uid = __kuid_val(old->uid); + rsbac_target_id.process = task_pid(current); + if(ruid != (uid_t) -1) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.long_dummy = 0; + rsbac_attribute_value.owner = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, ruid); + if(!rsbac_adf_request(R_CHANGE_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + retval = -EPERM; + goto error; + } + } +#ifdef CONFIG_RSBAC_DAC_OWNER + if(euid != (uid_t) -1) { + rsbac_pr_debug(aef, "calling ADF for euid\n"); + rsbac_attribute_value.long_dummy = 0; + rsbac_attribute_value.owner = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, euid); + if(!rsbac_adf_request(R_CHANGE_DAC_EFF_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + retval = -EPERM; + goto error; + } + rsbac_pr_debug(aef, "calling ADF for fsuid\n"); + if(!rsbac_adf_request(R_CHANGE_DAC_FS_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) { + retval = -EPERM; + goto error; + } + } +#endif +#endif + + retval = commit_creds(new); + +#ifdef CONFIG_RSBAC + if (!retval) { + rsbac_target_id.process = task_pid(current); + rsbac_new_target_id.dummy = 0; + if(ruid != (uid_t) -1) { + rsbac_set_audit_uid(rsbac_old_uid); + rsbac_attribute_value.owner = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, __kuid_val(current_uid())); + if (unlikely(rsbac_adf_set_attr(R_CHANGE_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_owner, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_setresuid(): rsbac_adf_set_attr() returned error"); + } + } +#ifdef CONFIG_RSBAC_DAC_OWNER + if(euid != (uid_t) -1) { + rsbac_attribute_value.owner = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, __kuid_val(current_euid())); + if (unlikely(rsbac_adf_set_attr(R_CHANGE_DAC_EFF_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_owner, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_setreuid(): rsbac_adf_set_attr() for euid returned error\n"); + } + if (unlikely(rsbac_adf_set_attr(R_CHANGE_DAC_FS_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_owner, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_setreuid(): rsbac_adf_set_attr() for fsuid returned error\n"); + } + } +#endif + } +#endif + + return retval; error: abort_creds(new); @@ -679,6 +1128,11 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) int retval; kgid_t krgid, kegid, ksgid; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + krgid = make_kgid(ns, rgid); kegid = make_kgid(ns, egid); ksgid = make_kgid(ns, sgid); @@ -695,6 +1149,11 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) return -ENOMEM; old = current_cred(); +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = task_pid(current); +#endif + retval = -EPERM; if (!ns_capable(old->user_ns, CAP_SETGID)) { if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) && @@ -708,6 +1167,38 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) goto error; } +#ifdef CONFIG_RSBAC + if (rgid != (gid_t) -1) { + rsbac_attribute_value.group = RSBAC_GEN_GID(RSBAC_UM_VIRTUAL_KEEP, rgid); + if (!rsbac_adf_request(R_CHANGE_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value)) + goto error; + } +#ifdef CONFIG_RSBAC_DAC_GROUP + if (egid != (gid_t) -1) { + rsbac_attribute_value.group = RSBAC_GEN_GID(RSBAC_UM_VIRTUAL_KEEP, egid); + if (!rsbac_adf_request(R_CHANGE_DAC_EFF_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value)) + goto error; + if (!rsbac_adf_request(R_CHANGE_DAC_FS_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value)) + goto error; + } +#endif +#endif + if (rgid != (gid_t) -1) new->gid = krgid; if (egid != (gid_t) -1) @@ -757,6 +1248,12 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) uid_t old_fsuid; kuid_t kuid; +#ifdef CONFIG_RSBAC_DAC_OWNER + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + old = current_cred(); old_fsuid = from_kuid_munged(old->user_ns, old->fsuid); @@ -768,9 +1265,25 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) if (!new) return old_fsuid; - if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || +#ifdef CONFIG_RSBAC_DAC_OWNER + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = task_pid(current); + rsbac_attribute_value.owner = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, uid); +#endif + + if ((uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || - ns_capable(old->user_ns, CAP_SETUID)) { + ns_capable(old->user_ns, CAP_SETUID)) + +#ifdef CONFIG_RSBAC_DAC_OWNER + && rsbac_adf_request(R_CHANGE_DAC_FS_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_owner, + rsbac_attribute_value) +#endif + ) { if (!uid_eq(kuid, old->fsuid)) { new->fsuid = kuid; if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) @@ -783,6 +1296,24 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) change_okay: commit_creds(new); + +#ifdef CONFIG_RSBAC_DAC_OWNER + rsbac_target_id.process = task_pid(current); + rsbac_new_target_id.dummy = 0; + rsbac_attribute_value.owner = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, uid); + if (unlikely(rsbac_adf_set_attr(R_CHANGE_DAC_FS_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_owner, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_setfsuid(): rsbac_adf_set_attr() returned error\n"); + } +#endif + return old_fsuid; } @@ -796,6 +1327,11 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) gid_t old_fsgid; kgid_t kgid; +#ifdef CONFIG_RSBAC_DAC_GROUP + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + old = current_cred(); old_fsgid = from_kgid_munged(old->user_ns, old->fsgid); @@ -807,9 +1343,25 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) if (!new) return old_fsgid; - if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) || +#ifdef CONFIG_RSBAC_DAC_GROUP + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = task_pid(current); + rsbac_attribute_value.group = RSBAC_GEN_GID(RSBAC_UM_VIRTUAL_KEEP, gid); +#endif + + if ((gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) || gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) || - ns_capable(old->user_ns, CAP_SETGID)) { + ns_capable(old->user_ns, CAP_SETGID)) + +#ifdef CONFIG_RSBAC_DAC_GROUP + && rsbac_adf_request(R_CHANGE_DAC_FS_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value) +#endif + ) { if (!gid_eq(kgid, old->fsgid)) { new->fsgid = kgid; goto change_okay; @@ -864,14 +1416,22 @@ SYSCALL_DEFINE0(getppid) SYSCALL_DEFINE0(getuid) { +#ifdef CONFIG_RSBAC_FAKE_ROOT_UID + return rsbac_fake_uid(); +#else /* Only we change this so SMP safe */ return from_kuid_munged(current_user_ns(), current_uid()); +#endif } SYSCALL_DEFINE0(geteuid) { +#ifdef CONFIG_RSBAC_FAKE_ROOT_UID + return rsbac_fake_euid(); +#else /* Only we change this so SMP safe */ return from_kuid_munged(current_user_ns(), current_euid()); +#endif } SYSCALL_DEFINE0(getgid) @@ -956,6 +1516,11 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) struct pid *pgrp; int err; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!pid) pid = task_pid_vnr(group_leader); if (!pgid) @@ -964,6 +1529,23 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) return -EINVAL; rcu_read_lock(); +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = find_pid_ns(pid, &init_pid_ns); + if (likely(rsbac_target_id.process)) { + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + rcu_read_unlock(); + return -EPERM; + } + } +#endif + /* From this point forward we keep holding onto the tasklist lock * so that our parent does not change from under us. -DaveM */ @@ -1030,6 +1612,11 @@ SYSCALL_DEFINE1(getpgid, pid_t, pid) if (!pid) grp = task_pgrp(current); else { +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + retval = -ESRCH; p = find_task_by_vpid(pid); if (!p) @@ -1038,6 +1625,23 @@ SYSCALL_DEFINE1(getpgid, pid_t, pid) if (!grp) goto out; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(p, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + retval = -EPERM; + put_pid(rsbac_target_id.process); + goto out; + } + put_pid(rsbac_target_id.process); +#endif + retval = security_task_getpgid(p); if (retval) goto out; @@ -1067,6 +1671,11 @@ SYSCALL_DEFINE1(getsid, pid_t, pid) if (!pid) sid = task_session(current); else { +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + retval = -ESRCH; p = find_task_by_vpid(pid); if (!p) @@ -1075,6 +1684,23 @@ SYSCALL_DEFINE1(getsid, pid_t, pid) if (!sid) goto out; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = get_task_pid(p, PIDTYPE_PID); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + retval = -EPERM; + put_pid(rsbac_target_id.process); + goto out; + } + put_pid(rsbac_target_id.process); +#endif + retval = security_task_getsid(p); if (retval) goto out; @@ -1250,11 +1876,31 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) int errno; char tmp[__NEW_UTS_LEN]; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_host_id; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + down_write(&uts_sem); errno = -EFAULT; if (!copy_from_user(tmp, name, len)) { @@ -1301,11 +1947,30 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) int errno; char tmp[__NEW_UTS_LEN]; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_net_id; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + down_write(&uts_sem); errno = -EFAULT; if (!copy_from_user(tmp, name, len)) { @@ -1468,6 +2133,12 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource, struct rlimit *rlim; int retval = 0; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (resource >= RLIM_NLIMITS) return -EINVAL; if (new_rlim) { @@ -1493,6 +2164,23 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource, if (new_rlim->rlim_max > rlim->rlim_max && !capable(CAP_SYS_RESOURCE)) retval = -EPERM; + +#ifdef CONFIG_RSBAC + if (!retval) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rlimit; + rsbac_attribute_value.rlimit.resource = resource; + rsbac_attribute_value.rlimit.limit = *new_rlim; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_rlimit, + rsbac_attribute_value)) + retval = -EPERM; + } +#endif + if (!retval) retval = security_task_setrlimit(tsk, resource, new_rlim); if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) { @@ -1513,6 +2201,21 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource, } task_unlock(tsk->group_leader); +#ifdef CONFIG_RSBAC + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_rlimit, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_setrlimit(): rsbac_adf_set_attr() returned error"); + } +#endif + /* * RLIMIT_CPU handling. Note that the kernel fails to return an error * code if it rejected the user's attempt to set RLIMIT_CPU. This is a diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index edf19cc53140..3f1776e1eaac 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -22,6 +22,8 @@ #include "timekeeping_internal.h" +#include + /* * NTP timekeeping variables: * @@ -659,6 +661,11 @@ static inline void process_adjtimex_modes(struct timex *txc, */ int ntp_validate_timex(struct timex *txc) { +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (txc->modes & ADJ_ADJTIME) { /* singleshot must not be used with any other mode bits */ if (!(txc->modes & ADJ_OFFSET_SINGLESHOT)) @@ -670,6 +677,20 @@ int ntp_validate_timex(struct timex *txc) /* In order to modify anything, you gotta be super-user! */ if (txc->modes && !capable(CAP_SYS_TIME)) return -EPERM; + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_time_strucs; + rsbac_attribute_value.dummy = 0; + if (txc->modes && !rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + return -EPERM; +#endif + /* * if the quartz is off by more than 10% then * something is VERY wrong! diff --git a/kernel/uid16.c b/kernel/uid16.c index 5c2dc5b2bf4f..18368064afac 100644 --- a/kernel/uid16.c +++ b/kernel/uid16.c @@ -17,6 +17,8 @@ #include +#include + SYSCALL_DEFINE3(chown16, const char __user *, filename, old_uid_t, user, old_gid_t, group) { return sys_chown(filename, low2highuid(user), low2highgid(group)); @@ -177,6 +179,12 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist) struct group_info *group_info; int retval; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + int i; +#endif + if (!may_setgroups()) return -EPERM; if ((unsigned)gidsetsize > NGROUPS_MAX) @@ -191,6 +199,26 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist) return retval; } +#ifdef CONFIG_RSBAC + if (gidsetsize > 0) { + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.process = task_pid(current); + for (i=0; i < gidsetsize; i++) { + rsbac_attribute_value.group = RSBAC_GEN_GID(RSBAC_UM_VIRTUAL_KEEP, __kgid_val(group_info->gid[i])); + if(!rsbac_adf_request(R_CHANGE_GROUP, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_group, + rsbac_attribute_value)) + { + put_group_info(group_info); + return -EPERM; + } + } + } +#endif + retval = set_current_groups(group_info); put_group_info(group_info); @@ -199,12 +227,20 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist) SYSCALL_DEFINE0(getuid16) { +#ifdef CONFIG_RSBAC_FAKE_ROOT_UID + return high2lowuid(rsbac_fake_uid()); +#else return high2lowuid(from_kuid_munged(current_user_ns(), current_uid())); +#endif } SYSCALL_DEFINE0(geteuid16) { +#ifdef CONFIG_RSBAC_FAKE_ROOT_UID + return high2lowuid(rsbac_fake_euid()); +#else return high2lowuid(from_kuid_munged(current_user_ns(), current_euid())); +#endif } SYSCALL_DEFINE0(getgid16) diff --git a/mm/mlock.c b/mm/mlock.c index b562b5523a65..12a1e97d9cfb 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -23,6 +23,8 @@ #include #include +#include + #include "internal.h" bool can_do_mlock(void) @@ -668,9 +670,29 @@ static __must_check int do_mlock(unsigned long start, size_t len, vm_flags_t fla unsigned long lock_limit; int error = -ENOMEM; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!can_do_mlock()) return -EPERM; +#ifdef CONFIG_RSBAC + rsbac_target_id.scd = ST_mlock; + rsbac_attribute_value.dummy = 0; + rsbac_pr_debug(aef, "calling ADF\n"); + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + lru_add_drain_all(); /* flush pagevec */ len = PAGE_ALIGN(len + (offset_in_page(start))); @@ -793,12 +815,31 @@ SYSCALL_DEFINE1(mlockall, int, flags) unsigned long lock_limit; int ret; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT))) return -EINVAL; if (!can_do_mlock()) return -EPERM; +#ifdef CONFIG_RSBAC + rsbac_target_id.scd = ST_mlock; + rsbac_attribute_value.dummy = 0; + rsbac_pr_debug(aef, "calling ADF\n"); + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + if (flags & MCL_CURRENT) lru_add_drain_all(); /* flush pagevec */ diff --git a/mm/mmap.c b/mm/mmap.c index f19efcf75418..a1a78c70933c 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -50,6 +50,11 @@ #include #include +#include +#if defined(CONFIG_RSBAC_MPROTECT) +#include +#endif + #include "internal.h" #ifndef arch_mmap_check @@ -1326,11 +1331,48 @@ unsigned long do_mmap(struct file *file, unsigned long addr, struct mm_struct *mm = current->mm; int pkey = 0; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + *populate = 0; if (!len) return -EINVAL; +#ifdef CONFIG_RSBAC_MPROTECT + if ( (prot & PROT_EXEC) && (prot & PROT_WRITE) && !rsbac_write_exec_allowed(NULL, prot) ) { + char * program_name = rsbac_get_program_name(); + + if (file && file->f_path.dentry) { + char * help_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + help_name = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN); + if (help_name) { + if (!(rsbac_get_full_path(file->f_path.dentry, help_name, CONFIG_RSBAC_MAX_PATH_LEN - 1) > 0)) + strcpy(help_name, "(unknown)"); + } +#else + help_name = file->f_path.dentry->d_name.name; +#endif + rsbac_printk(KERN_INFO "do_mmap() [sys_mmap()]: RSBAC mprotect: denied WRITE and EXEC to %s, pid %u(%s)\n", + help_name, current->pid, program_name); +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (help_name) + rsbac_kfree(help_name); +#endif + } else + rsbac_printk(KERN_INFO "do_mmap() [sys_mmap()]: RSBAC mprotect: denied WRITE and EXEC, pid %u(%s)\n", + current->pid, program_name); + if (program_name) + rsbac_kfree(program_name); + return -EPERM; + } +#endif + /* * Does the application expect PROT_READ to imply PROT_EXEC? * @@ -1464,6 +1506,32 @@ unsigned long do_mmap(struct file *file, unsigned long addr, vm_flags |= VM_NORESERVE; } +#ifdef CONFIG_RSBAC + if (prot & PROT_EXEC) { + rsbac_pr_debug(aef, "[do_mmap() [sys_mmap()]]: calling ADF\n"); + if (file) { + rsbac_target = T_FILE; + rsbac_target_id.file.device = file->f_path.dentry->d_inode->i_sb->s_dev; + rsbac_target_id.file.inode = file->f_path.dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = file->f_path.dentry; + } else { + rsbac_target = T_NONE; + rsbac_target_id.dummy = 0; + } + rsbac_attribute_value.prot_bits = prot; + if (!rsbac_adf_request(R_MAP_EXEC, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_prot_bits, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "[do_mmap() [sys_mmap()]]: request not granted, my PID: %i\n", + current->pid); + return -EPERM; + } + } +#endif + addr = mmap_region(file, addr, len, vm_flags, pgoff, uf); if (!IS_ERR_VALUE(addr) && ((vm_flags & VM_LOCKED) || diff --git a/mm/mprotect.c b/mm/mprotect.c index 4180ad8cc9c5..b0a9c23e63f4 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -31,6 +31,11 @@ #include #include +#include +#if defined(CONFIG_RSBAC_MPROTECT) +#include +#endif + #include "internal.h" static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, @@ -383,6 +388,13 @@ static int do_mprotect_pkey(unsigned long start, size_t len, const bool rier = (current->personality & READ_IMPLIES_EXEC) && (prot & PROT_READ); +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + int need_notify = FALSE; +#endif + prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP); if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */ return -EINVAL; @@ -469,6 +481,101 @@ static int do_mprotect_pkey(unsigned long start, size_t len, if (error) goto out; +#ifdef CONFIG_RSBAC + if ((prot & PROT_EXEC) && !(vma->vm_flags & PROT_EXEC)) { + rsbac_pr_debug(aef, "calling ADF\n"); + if (vma->vm_file) { + rsbac_target = T_FILE; + rsbac_target_id.file.device = vma->vm_file->f_path.dentry->d_inode->i_sb->s_dev; + rsbac_target_id.file.inode = vma->vm_file->f_path.dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = vma->vm_file->f_path.dentry; + } else { + rsbac_target = T_NONE; + rsbac_target_id.dummy = 0; + } + rsbac_attribute_value.prot_bits = prot; + if (!rsbac_adf_request(R_MAP_EXEC, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_prot_bits, + rsbac_attribute_value)) + { + rsbac_pr_debug(aef, "request NOT_GRANTED\n"); + error = -EPERM; + goto out; + } else + need_notify = TRUE; + } +#ifdef CONFIG_RSBAC_MPROTECT + if ( ( ((prot & PROT_EXEC) && !(vma->vm_flags & PROT_EXEC)) + || ((prot & PROT_WRITE) && !(vma->vm_flags & PROT_WRITE)) + ) + && !rsbac_write_exec_allowed(vma, prot) + ) { + if ( ((prot & PROT_EXEC) && (prot & PROT_WRITE)) + || ((prot & PROT_EXEC) && (vma->vm_flags & PROT_WRITE)) + || ((prot & PROT_WRITE) && (vma->vm_flags & PROT_EXEC)) + ) { + char * program_name = rsbac_get_program_name(); + + if (vma->vm_file && vma->vm_file->f_path.dentry) { + char * help_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + help_name = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN); + if (help_name) { + if (!(rsbac_get_full_path(vma->vm_file->f_path.dentry, help_name, CONFIG_RSBAC_MAX_PATH_LEN - 1) > 0)) + strcpy(help_name, "(unknown)"); + } +#else + help_name = vma->vm_file->f_path.dentry->d_name.name; +#endif + rsbac_printk(KERN_INFO "SYSC_mprotect(): RSBAC mprotect: denied WRITE and EXEC to %s, pid %u(%s)\n", + help_name, current->pid, program_name); +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (help_name) + rsbac_kfree(help_name); +#endif + } else + rsbac_printk(KERN_INFO "SYSC_mprotect(): RSBAC mprotect: denied WRITE and EXEC, pid %u(%s)\n", + current->pid, program_name); + if (program_name) + rsbac_kfree(program_name); + error = -EPERM; + goto out; + } + if ((prot & PROT_EXEC) && (newflags & VM_MAYWRITE)) { +#ifdef CONFIG_RSBAC_DEBUG + char * program_name = rsbac_get_program_name(); + if (vma->vm_file && vma->vm_file->f_path.dentry) + rsbac_pr_debug(mprotect, "RSBAC mprotect: EXEC -> unset MAYWRITE for %s, pid %u(%s)\n", + vma->vm_file->f_path.dentry->d_name.name, current->pid, program_name); + else + rsbac_pr_debug(mprotect, "RSBAC mprotect: EXEC -> unset MAYWRITE, pid %u(%s)\n", + current->pid, program_name); + if (program_name) + rsbac_kfree(program_name); +#endif + newflags &= ~VM_MAYWRITE; + } else if ((prot & PROT_WRITE) && (newflags & VM_MAYEXEC)) { +#ifdef CONFIG_RSBAC_DEBUG + char * program_name = rsbac_get_program_name(); + if (vma->vm_file && vma->vm_file->f_path.dentry) + rsbac_pr_debug(mprotect, "RSBAC mprotect: WRITE -> unset MAYEXEC for %s, pid %u(%s)\n", + vma->vm_file->f_path.dentry->d_name.name, current->pid, program_name); + else + rsbac_pr_debug(mprotect, "RSBAC mprotect: WRITE -> unset MAYEXEC, pid %u(%s)\n", + current->pid, program_name); + if (program_name) + rsbac_kfree(program_name); +#endif + newflags &= ~VM_MAYEXEC; + } + } +#endif +#endif + tmp = vma->vm_end; if (tmp > end) tmp = end; @@ -491,6 +598,28 @@ static int do_mprotect_pkey(unsigned long start, size_t len, } out: up_write(¤t->mm->mmap_sem); + + /* RSBAC: notify ADF of mapped segment */ +#ifdef CONFIG_RSBAC + if (need_notify && !error) { + union rsbac_target_id_t rsbac_new_target_id; + + rsbac_pr_debug(aef, "calling ADF_set_attr\n"); + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_MAP_EXEC, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_mprotect: rsbac_adf_set_attr() returned error\n"); + } + } +#endif + return error; } diff --git a/mm/swapfile.c b/mm/swapfile.c index 6ba4aab2db0b..d53775e7eeb9 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -44,6 +44,8 @@ #include #include +#include + static bool swap_count_continued(struct swap_info_struct *, pgoff_t, unsigned char); static void free_swap_count_continuations(struct swap_info_struct *); @@ -2309,9 +2311,29 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) int err, found = 0; unsigned int old_block_size; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!capable(CAP_SYS_ADMIN)) return -EPERM; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_swap; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; +} +#endif + BUG_ON(!current->mm); pathname = getname(specialfile); @@ -2323,6 +2345,35 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) if (IS_ERR(victim)) goto out; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF for DEV / FILE\n"); + if (S_ISBLK(victim->f_path.dentry->d_inode->i_mode)) { + rsbac_target = T_DEV; + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(victim->f_path.dentry->d_inode->i_rdev); + rsbac_target_id.dev.minor = RSBAC_MINOR(victim->f_path.dentry->d_inode->i_rdev); + } else + if (S_ISREG(victim->f_path.dentry->d_inode->i_mode)) { + rsbac_target = T_FILE; + rsbac_target_id.file.device = victim->f_path.dentry->d_sb->s_dev; + rsbac_target_id.file.inode = victim->f_path.dentry->d_inode->i_ino; + rsbac_target_id.file.dentry_p = victim->f_path.dentry; + } else { + rsbac_target = T_NONE; + rsbac_target_id.dummy = 0; + } + rsbac_attribute_value.dummy = 0; + if ((rsbac_target != T_NONE) && !rsbac_adf_request(R_REMOVE_FROM_KERNEL, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto out_dput; + } +#endif + mapping = victim->f_mapping; spin_lock(&swap_lock); plist_for_each_entry(p, &swap_active_head, list) { @@ -2867,12 +2918,31 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) struct page *page = NULL; struct inode *inode = NULL; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (swap_flags & ~SWAP_FLAGS_VALID) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_swap; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + return -EPERM; +#endif + p = alloc_swap_info(); if (IS_ERR(p)) return PTR_ERR(p); @@ -2896,6 +2966,37 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) mapping = swap_file->f_mapping; inode = mapping->host; +/* RSBAC */ +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "calling ADF for DEV / FILE\n"); + if(S_ISBLK(inode->i_mode)) { + rsbac_target = T_DEV; + rsbac_target_id.dev.type = D_block; + rsbac_target_id.dev.major = RSBAC_MAJOR(inode->i_rdev); + rsbac_target_id.dev.minor = RSBAC_MINOR(inode->i_rdev); + } else if(S_ISREG(inode->i_mode)) { + rsbac_target = T_FILE; + rsbac_target_id.file.device = swap_file->f_path.dentry->d_sb->s_dev; + rsbac_target_id.file.inode = inode->i_ino; + rsbac_target_id.file.dentry_p = swap_file->f_path.dentry; + } else { + rsbac_target = T_NONE; + rsbac_target_id.dummy = 0; + } + rsbac_attribute_value.dummy = 0; + if( (rsbac_target != T_NONE) + && !rsbac_adf_request(R_ADD_TO_KERNEL, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value) + ) { + error = -EPERM; + goto bad_swap; + } +#endif + /* If S_ISREG(inode->i_mode) will do inode_lock(inode); */ error = claim_swapfile(p, inode); if (unlikely(error)) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index f3aef22931ab..2e910ba7837e 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -27,6 +27,8 @@ #include #include +#include + #include "br_private.h" /* @@ -487,6 +489,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) unsigned br_hr, dev_hr; bool changed_addr; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + /* Don't allow bridging non-ethernet like devices, or DSA-enabled * master network devices since the bridge layer rx_handler prevents * the DSA fake ethertype handler to be invoked, so we do not strip off @@ -507,6 +514,34 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) if (br_port_exists(dev)) return -EBUSY; +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "calling ADF\n"); + strncpy(rsbac_target_id.netdev, dev->name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#ifndef CONFIG_RSBAC_NET_DEV_VIRT + { + char * p = rsbac_target_id.netdev; + while (*p) { + if (*p == ':') { + *p=' '; + break; + } + p++; + } + } +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + /* No bridging devices that dislike that (e.g. wireless) */ if (dev->priv_flags & IFF_DONT_BRIDGE) return -EOPNOTSUPP; @@ -622,10 +657,45 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) struct net_bridge_port *p; bool changed_addr; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + p = br_port_get_rtnl(dev); if (!p || p->br != br) return -EINVAL; +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "calling ADF\n"); + strncpy(rsbac_target_id.netdev, dev->name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#ifndef CONFIG_RSBAC_NET_DEV_VIRT + { + char * p = rsbac_target_id.netdev; + while (*p) + { + if (*p == ':') + { + *p=' '; + break; + } + p++; + } + } +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + /* Since more than one interface can be attached to a bridge, * there still maybe an alternate path for netconsole to use; * therefore there is no reason for a NETDEV_RELEASE event. diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index 709a4e6fb447..719b92b4848e 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -6,6 +6,8 @@ #include #include +#include + /* * Map an interface index to its name (SIOCGIFNAME) */ @@ -400,6 +402,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) int ret; char *colon; +#ifdef CONFIG_RSBAC_NET_DEV + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + /* One special case: SIOCGIFCONF takes ifconf argument and requires shared lock, because it sleeps writing to user space. @@ -437,10 +444,20 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) ifr.ifr_name[IFNAMSIZ-1] = 0; +#ifdef CONFIG_RSBAC_NET_DEV_VIRT + strncpy(rsbac_target_id.netdev, ifr.ifr_name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#endif + colon = strchr(ifr.ifr_name, ':'); if (colon) *colon = 0; +#if defined(CONFIG_RSBAC_NET_DEV) && !defined(CONFIG_RSBAC_NET_DEV_VIRT) + strncpy(rsbac_target_id.netdev, ifr.ifr_name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#endif + /* * See which interface the caller is talking about. */ @@ -460,6 +477,20 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) case SIOCGIFMAP: case SIOCGIFINDEX: case SIOCGIFTXQLEN: + +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + dev_load(net, ifr.ifr_name); rcu_read_lock(); ret = dev_ifsioc_locked(net, &ifr, cmd); @@ -546,6 +577,20 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) case SIOCSHWTSTAMP: if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) return -EPERM; + +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + /* fall through */ case SIOCBONDSLAVEINFOQUERY: case SIOCBONDINFOQUERY: @@ -572,6 +617,20 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) cmd == SIOCGHWTSTAMP || (cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15)) { + +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + dev_load(net, ifr.ifr_name); rtnl_lock(); ret = dev_ifsioc(net, &ifr, cmd); diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index fdcb1bcd2afa..f07eda48e67e 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -37,6 +37,8 @@ bool fib_rule_matchall(const struct fib_rule *rule) } EXPORT_SYMBOL_GPL(fib_rule_matchall); +#include + int fib_default_rule_add(struct fib_rules_ops *ops, u32 pref, u32 table, u32 flags) { @@ -377,6 +379,10 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, struct fib_rule *rule, *r, *last = NULL; struct nlattr *tb[FRA_MAX+1]; int err = -EINVAL, unresolved = 0; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) goto errout; @@ -395,6 +401,22 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, if (err < 0) goto errout; +#ifdef CONFIG_RSBAC_NET + rsbac_pr_debug(aef, "fib_nl_newrule(): calling ADF\n"); + rsbac_target_id.scd = ST_network; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto errout; + } +#endif + rule = kzalloc(ops->rule_size, GFP_KERNEL); if (rule == NULL) { err = -ENOMEM; @@ -571,6 +593,10 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr *tb[FRA_MAX+1]; struct fib_kuid_range range; int err = -EINVAL; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) goto errout; @@ -599,6 +625,22 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, range = fib_kuid_range_unset; } +#ifdef CONFIG_RSBAC_NET + rsbac_pr_debug(aef, "fib_nl_delrule(): calling ADF\n"); + rsbac_target_id.scd = ST_network; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto errout; + } +#endif + list_for_each_entry(rule, &ops->rules_list, list) { if (frh->action && (frh->action != rule->action)) continue; @@ -729,6 +771,25 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, { struct nlmsghdr *nlh; struct fib_rule_hdr *frh; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC_NET + rsbac_pr_debug(aef, "fib_nl_fill_rule(): calling ADF\n"); + rsbac_target_id.scd = ST_network; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif nlh = nlmsg_put(skb, pid, seq, type, sizeof(*frh), flags); if (nlh == NULL) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 8b52179ddc6e..f099b6c85c59 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -120,6 +120,8 @@ #include +#include + /* * Interface to generic neighbour cache. */ @@ -1175,15 +1177,32 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg) struct arpreq r; struct net_device *dev = NULL; +#ifdef CONFIG_RSBAC_NET_DEV + enum rsbac_adf_request_t rsbac_request = R_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + switch (cmd) { case SIOCDARP: case SIOCSARP: if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) return -EPERM; + +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_request = R_MODIFY_SYSTEM_DATA; +#endif + case SIOCGARP: err = copy_from_user(&r, arg, sizeof(struct arpreq)); if (err) return -EFAULT; + +#ifdef CONFIG_RSBAC_NET_DEV + if (rsbac_request == R_NONE) + rsbac_request = R_GET_STATUS_DATA; +#endif + break; default: return -EINVAL; @@ -1211,6 +1230,24 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg) err = -EINVAL; if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type) goto out; + +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "calling ADF\n"); + strncpy(rsbac_target_id.netdev, r.arp_dev, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } +#endif + } else if (cmd == SIOCGARP) { err = -ENODEV; goto out; diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 38d9af9b917c..4e570643a037 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -66,6 +66,8 @@ #include #include +#include + static struct ipv4_devconf ipv4_devconf = { .data = { [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1, @@ -601,6 +603,11 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, struct in_ifaddr *ifa, **ifap; int err = -EINVAL; +#ifdef CONFIG_RSBAC_NET_DEV + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + ASSERT_RTNL(); err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy, @@ -615,6 +622,37 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, goto errout; } +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "calling ADF\n"); + strncpy(rsbac_target_id.netdev, in_dev->dev->name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#ifndef CONFIG_RSBAC_NET_DEV_VIRT + { + char * p = rsbac_target_id.netdev; + + while (*p) + { + if (*p == ':') + { + *p=' '; + break; + } + p++; + } + } +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_BIND, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto errout; + } +#endif + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) { if (tb[IFA_LOCAL] && @@ -774,6 +812,11 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, struct in_device *in_dev; int err; +#ifdef CONFIG_RSBAC_NET_DEV + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy, NULL); if (err < 0) @@ -794,6 +837,37 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, if (!in_dev) goto errout; +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "calling ADF\n"); + strncpy(rsbac_target_id.netdev, in_dev->dev->name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#ifndef CONFIG_RSBAC_NET_DEV_VIRT + { + char * p = rsbac_target_id.netdev; + while (*p) + { + if (*p == ':') + { + *p=' '; + break; + } + p++; + } + } +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_BIND, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto errout; + } +#endif + ifa = inet_alloc_ifa(); if (!ifa) /* @@ -951,6 +1025,12 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) int ret = -EFAULT; int tryaddrmatch = 0; +#ifdef CONFIG_RSBAC_NET_DEV + enum rsbac_adf_request_t rsbac_request = R_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + /* * Fetch the caller's info block into kernel space */ @@ -959,6 +1039,11 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) goto out; ifr.ifr_name[IFNAMSIZ - 1] = 0; +#ifdef CONFIG_RSBAC_NET_DEV_VIRT + strncpy(rsbac_target_id.netdev, ifr.ifr_name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#endif + /* save original address for comparison */ memcpy(&sin_orig, sin, sizeof(*sin)); @@ -966,6 +1051,11 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) if (colon) *colon = 0; +#if defined(CONFIG_RSBAC_NET_DEV) && !defined(CONFIG_RSBAC_NET_DEV_VIRT) + strncpy(rsbac_target_id.netdev, ifr.ifr_name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#endif + dev_load(net, ifr.ifr_name); switch (cmd) { @@ -980,12 +1070,22 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) tryaddrmatch = (sin_orig.sin_family == AF_INET); memset(sin, 0, sizeof(*sin)); sin->sin_family = AF_INET; + +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_request = R_GET_STATUS_DATA; +#endif + break; case SIOCSIFFLAGS: ret = -EPERM; if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) goto out; + +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_request = R_MODIFY_SYSTEM_DATA; +#endif + break; case SIOCSIFADDR: /* Set interface address (and family) */ case SIOCSIFBRDADDR: /* Set the broadcast address */ @@ -997,12 +1097,31 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) ret = -EINVAL; if (sin->sin_family != AF_INET) goto out; + +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_request = R_BIND; +#endif break; default: ret = -EINVAL; goto out; } +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + ret = -EPERM; + goto out; + } +#endif + rtnl_lock(); ret = -ENODEV; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 044d2a159a3c..58f40c4ca2a6 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -49,6 +49,8 @@ #include #include +#include + #ifndef CONFIG_IP_MULTIPLE_TABLES static int __net_init fib4_rules_init(struct net *net) @@ -571,6 +573,11 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg) struct rtentry rt; int err; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + switch (cmd) { case SIOCADDRT: /* Add a route */ case SIOCDELRT: /* Delete a route */ @@ -580,6 +587,20 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg) if (copy_from_user(&rt, arg, sizeof(rt))) return -EFAULT; +#ifdef CONFIG_RSBAC_NET + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_network; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + rtnl_lock(); err = rtentry_to_fib_config(net, cmd, &rt, &cfg); if (err == 0) { @@ -724,10 +745,30 @@ static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, struct fib_table *tb; int err; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + err = rtm_to_fib_config(net, skb, nlh, &cfg, extack); if (err < 0) goto errout; +#ifdef CONFIG_RSBAC_NET + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_network; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto errout; + } +#endif + tb = fib_get_table(net, cfg.fc_table); if (!tb) { NL_SET_ERR_MSG(extack, "FIB table does not exist"); @@ -748,7 +789,12 @@ static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, struct fib_table *tb; int err; - err = rtm_to_fib_config(net, skb, nlh, &cfg, extack); +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + + err = rtm_to_fib_config(net, skb, nlh, &cfg, extack); if (err < 0) goto errout; diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 3828b3a805cd..aa6998f342b3 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -35,6 +35,8 @@ #include #include +#include + static const struct inet_diag_handler **inet_diag_table; struct inet_diag_entry { @@ -1082,6 +1084,11 @@ static int inet_diag_get_exact_compat(struct sk_buff *in_skb, static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) { +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + int hdrlen = sizeof(struct inet_diag_req); struct net *net = sock_net(skb->sk); @@ -1094,6 +1101,19 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) struct nlattr *attr; int err; +#ifdef CONFIG_RSBAC_NET + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_network; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + return -EPERM; +#endif + attr = nlmsg_find_attr(nlh, hdrlen, INET_DIAG_REQ_BYTECODE); err = inet_diag_bc_audit(attr, skb); diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 06863ea3fc5b..e532aa0bcd32 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -459,6 +459,8 @@ static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) return NULL; } +#include + #if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2) static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -1330,11 +1332,31 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, goto out_unlock; } if (optname != MRT_INIT) { +#ifdef CONFIG_RSBAC_NET_DEV + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (sk != rcu_access_pointer(mrt->mroute_sk) && !ns_capable(net->user_ns, CAP_NET_ADMIN)) { ret = -EACCES; goto out_unlock; } + +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_network; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + ret = -EPERM; + goto out_unlock; + } +#endif } switch (optname) { diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 2a55a40211cb..fd888f96286b 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -31,6 +31,8 @@ #include #include "../../netfilter/xt_repldata.h" +#include + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); MODULE_DESCRIPTION("IPv4 packet filter"); @@ -1006,6 +1008,11 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr, struct ipt_get_entries get; struct xt_table *t; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (*len < sizeof(get)) return -EINVAL; if (copy_from_user(&get, uptr, sizeof(get)) != 0) @@ -1014,6 +1021,21 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr, return -EINVAL; get.name[sizeof(get.name) - 1] = '\0'; +#ifdef CONFIG_RSBAC_NET + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_firewall; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + t = xt_find_table_lock(net, AF_INET, get.name); if (t) { const struct xt_table_info *private = t->private; @@ -1538,9 +1560,28 @@ compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, { int ret; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) return -EPERM; +#ifdef CONFIG_RSBAC_NET + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_firewall; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + switch (cmd) { case IPT_SO_SET_REPLACE: ret = compat_do_replace(sock_net(sk), user, len); @@ -1600,6 +1641,11 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr, struct compat_ipt_get_entries get; struct xt_table *t; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (*len < sizeof(get)) return -EINVAL; @@ -1611,6 +1657,21 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr, get.name[sizeof(get.name) - 1] = '\0'; +#ifdef CONFIG_RSBAC_NET + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_firewall; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + xt_compat_lock(AF_INET); t = xt_find_table_lock(net, AF_INET, get.name); if (t) { @@ -1662,9 +1723,28 @@ do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) { int ret; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) return -EPERM; +#ifdef CONFIG_RSBAC_NET + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_firewall; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + switch (cmd) { case IPT_SO_SET_REPLACE: ret = do_replace(sock_net(sk), user, len); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 0383e66f59bc..963b4891b9eb 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -116,6 +116,8 @@ #include "fib_lookup.h" +#include + #define RT_FL_TOS(oldflp4) \ ((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK)) @@ -2680,6 +2682,24 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, u32 table_id = RT_TABLE_MAIN; kuid_t uid; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_network; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + err = -EPERM; + goto errout; + } +#endif + err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy, extack); if (err < 0) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 39da0c5801c9..17354e44ecf4 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -31,6 +31,8 @@ #include #include +#include + /* The list of all installed classifier types */ static LIST_HEAD(tcf_proto_base); @@ -432,10 +434,34 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, int err; int tp_created; +#ifdef CONFIG_RSBAC_NET + enum rsbac_adf_request_t rsbac_request; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if ((n->nlmsg_type != RTM_GETTFILTER) && !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) return -EPERM; +#ifdef CONFIG_RSBAC_NET + rsbac_pr_debug(aef, "calling ADF\n"); + if (n->nlmsg_type == RTM_GETTFILTER) + rsbac_request = R_GET_STATUS_DATA; + else + rsbac_request = R_MODIFY_SYSTEM_DATA; + rsbac_target_id.scd = ST_network; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + replay: tp_created = 0; @@ -778,6 +804,25 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) long index; int err; +#ifdef CONFIG_RSBAC_NET + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC_NET + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_network; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + if (nlmsg_len(cb->nlh) < sizeof(*tcm)) return skb->len; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index bd24a550e0f9..51711a61b5d5 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -36,6 +36,8 @@ #include #include +#include + static int qdisc_notify(struct net *net, struct sk_buff *oskb, struct nlmsghdr *n, u32 clid, struct Qdisc *old, struct Qdisc *new); @@ -1138,6 +1140,15 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, struct Qdisc *p = NULL; int err; +#ifdef CONFIG_RSBAC_NET_DEV + enum rsbac_adf_request_t rsbac_request; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#if !defined(CONFIG_RSBAC_NET_DEV_VIRT) + char * rsbac_colon; +#endif +#endif + if ((n->nlmsg_type != RTM_GETQDISC) && !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) return -EPERM; @@ -1150,6 +1161,30 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, if (!dev) return -ENODEV; +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "calling ADF\n"); + if (n->nlmsg_type == RTM_GETQDISC) + rsbac_request = R_GET_STATUS_DATA; + else + rsbac_request = R_MODIFY_SYSTEM_DATA; + strncpy(rsbac_target_id.netdev, dev->name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#if !defined(CONFIG_RSBAC_NET_DEV_VIRT) + rsbac_colon = strchr(rsbac_target_id.netdev, ':'); + if (rsbac_colon) + *rsbac_colon = 0; +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + clid = tcm->tcm_parent; if (clid) { if (clid != TC_H_ROOT) { @@ -1207,6 +1242,14 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, struct Qdisc *q, *p; int err; +#ifdef CONFIG_RSBAC_NET_DEV + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#if !defined(CONFIG_RSBAC_NET_DEV_VIRT) + char * rsbac_colon; +#endif +#endif + if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) return -EPERM; @@ -1224,6 +1267,25 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, if (!dev) return -ENODEV; +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "tc_modify_qdisc(): calling ADF\n"); + strncpy(rsbac_target_id.netdev, dev->name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#if !defined(CONFIG_RSBAC_NET_DEV_VIRT) + rsbac_colon = strchr(rsbac_target_id.netdev, ':'); + if (rsbac_colon) + *rsbac_colon = 0; +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif if (clid) { if (clid != TC_H_ROOT) { @@ -1521,6 +1583,14 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) struct nlattr *tca[TCA_MAX + 1]; int err; +#ifdef CONFIG_RSBAC_NET_DEV + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#if !defined(CONFIG_RSBAC_NET_DEV_VIRT) + char * rsbac_colon; +#endif +#endif + s_idx = cb->args[0]; s_q_idx = q_idx = cb->args[1]; @@ -1538,6 +1608,27 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) goto cont; if (idx > s_idx) s_q_idx = 0; + +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "tc_dump_qdisc(): calling ADF\n"); + strncpy(rsbac_target_id.netdev, dev->name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#if !defined(CONFIG_RSBAC_NET_DEV_VIRT) + rsbac_colon = strchr(rsbac_target_id.netdev, ':'); + if(rsbac_colon) + *rsbac_colon = 0; +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + goto cont; + } +#endif + q_idx = 0; if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx, @@ -1586,6 +1677,15 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, u32 qid; int err; +#ifdef CONFIG_RSBAC_NET_DEV + enum rsbac_adf_request_t rsbac_request; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#if !defined(CONFIG_RSBAC_NET_DEV_VIRT) + char * rsbac_colon; +#endif +#endif + if ((n->nlmsg_type != RTM_GETTCLASS) && !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) return -EPERM; @@ -1598,6 +1698,30 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, if (!dev) return -ENODEV; +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "tc_ctl_tclass(): calling ADF\n"); + if (n->nlmsg_type == RTM_GETTCLASS) + rsbac_request = R_GET_STATUS_DATA; + else + rsbac_request = R_MODIFY_SYSTEM_DATA; + strncpy(rsbac_target_id.netdev, dev->name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#if !defined(CONFIG_RSBAC_NET_DEV_VIRT) + rsbac_colon = strchr(rsbac_target_id.netdev, ':'); + if (rsbac_colon) + *rsbac_colon = 0; +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + return -EPERM; + } +#endif + /* parent == TC_H_UNSPEC - unspecified parent. parent == TC_H_ROOT - class is root, which has no parent. @@ -1854,12 +1978,41 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) struct net_device *dev; int t, s_t; +#ifdef CONFIG_RSBAC_NET_DEV + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#if !defined(CONFIG_RSBAC_NET_DEV_VIRT) + char * rsbac_colon; +#endif +#endif + if (nlmsg_len(cb->nlh) < sizeof(*tcm)) return 0; dev = dev_get_by_index(net, tcm->tcm_ifindex); if (!dev) return 0; +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, "calling ADF\n"); + strncpy(rsbac_target_id.netdev, dev->name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#if !defined(CONFIG_RSBAC_NET_DEV_VIRT) + rsbac_colon = strchr(rsbac_target_id.netdev, ':'); + if (rsbac_colon) + *rsbac_colon = 0; +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) { + dev_put(dev); + return -EPERM; + } +#endif + s_t = cb->args[0]; t = 0; diff --git a/net/socket.c b/net/socket.c index ad22df1ffbd1..836cc2a84340 100644 --- a/net/socket.c +++ b/net/socket.c @@ -90,6 +90,14 @@ #include #include +#ifdef CONFIG_RSBAC +#include +#include +#include +#define rsbac_unix_peer(sk) (unix_sk(sk)->peer) +#define rsbac_unix_sk_peer(sk) (unix_sk(unix_sk(sk)->peer)) +#endif + #include #include @@ -630,8 +638,78 @@ EXPORT_SYMBOL(__sock_tx_timestamp); static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg) { - int ret = sock->ops->sendmsg(sock, msg, msg_data_left(msg)); + int ret; + +#if defined(CONFIG_RSBAC_NET_OBJ) + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + enum rsbac_attribute_t rsbac_attribute = A_none; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#if defined(CONFIG_RSBAC_NET_OBJ) + rsbac_pr_debug(aef, "[sys_send(), sys_sendto(), sys_sendmsg()]: calling ADF\n"); + if (sock->ops->family != AF_UNIX) { +#if !defined(CONFIG_RSBAC_NET_OBJ_RW) + if(sock->type != SOCK_STREAM) +#endif + { + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p = sock; + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = msg->msg_name; + rsbac_target_id.netobj.remote_len = msg->msg_namelen; + rsbac_attribute_value.process = get_pid(sock->sk->sk_peer_pid); + if (rsbac_attribute_value.process) { + if (pid_nr(rsbac_attribute_value.process) > 0) { + rsbac_attribute = A_process; + } else { + put_pid(rsbac_attribute_value.process); + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + } else { + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + if (!rsbac_adf_request(R_SEND, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_attribute, + rsbac_attribute_value)) { + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); + return -EPERM; + } + } + } +#endif + + ret = sock->ops->sendmsg(sock, msg, msg_data_left(msg)); BUG_ON(ret == -EIOCBQUEUED); + +#if defined(CONFIG_RSBAC_NET_OBJ) + if (!ret && (rsbac_target != T_NONE)) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_SEND, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + rsbac_attribute, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sock_sendmsg() [sys_send(), sys_sendto(), sys_sendmsg()]: rsbac_adf_set_attr() returned error\n"); + } + } + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); +#endif + return ret; } @@ -789,7 +867,80 @@ EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops); static inline int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, int flags) { - return sock->ops->recvmsg(sock, msg, msg_data_left(msg), flags); + int ret; + +#if defined(CONFIG_RSBAC_NET_OBJ) + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + enum rsbac_attribute_t rsbac_attribute = A_none; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + + ret = sock->ops->recvmsg(sock, msg, msg_data_left(msg), flags); + +#if defined(CONFIG_RSBAC_NET_OBJ) + if (ret > 0) { + rsbac_pr_debug(aef, "[sys_recv(), sys_recvfrom(), sys_recvmsg()]: calling ADF\n"); + if (sock->ops->family != AF_UNIX) { +#if !defined(CONFIG_RSBAC_NET_OBJ_RW) + if (sock->type != SOCK_STREAM) +#endif + { + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p = sock; + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = msg->msg_name; + rsbac_target_id.netobj.remote_len = msg->msg_namelen; + rsbac_attribute_value.process = get_pid(sock->sk->sk_peer_pid); + if (rsbac_attribute_value.process) { + if (pid_nr(rsbac_attribute_value.process) > 0) { + rsbac_attribute = A_process; + } else { + put_pid(rsbac_attribute_value.process); + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + } else { + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + if (!rsbac_adf_request(R_RECEIVE, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_attribute, + rsbac_attribute_value)) { + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); + return -EPERM; + } + } + } + } +#endif + +#if defined(CONFIG_RSBAC_NET_OBJ) + if ((ret > 0) && (rsbac_target != T_NONE)) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_RECEIVE, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + rsbac_attribute, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sock_recvmsg() [sys_recv(), sys_recvfrom(), sys_recvmsg()]: rsbac_adf_set_attr() for RECEIVE returned error\n"); + } + } + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); +#endif + + return ret; } int sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags) @@ -1301,6 +1452,13 @@ SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) struct socket *sock; int flags; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + /* Check the SOCK_* constants for consistency. */ BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC); BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK); @@ -1319,10 +1477,58 @@ SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) if (retval < 0) goto out; +#ifdef CONFIG_RSBAC + if (family == AF_UNIX) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = SOCK_INODE(sock)->i_ino; + } +#ifdef CONFIG_RSBAC_NET_OBJ + else { + rsbac_pr_debug(aef, "[sys_socket()]: calling ADF\n"); + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p = sock; + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; + } +#endif + rsbac_attribute_value.sock_type = type; + if ((rsbac_target != T_NONE) + && !rsbac_adf_request(R_CREATE, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_sock_type, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "[sys_socket()]: ADF returned NOT_GRANTED\n"); + retval = -EPERM; + goto out_release; + } +#endif + retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); if (retval < 0) goto out_release; +#ifdef CONFIG_RSBAC + if(rsbac_target != T_NONE) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_CREATE, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_sock_type, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_socket(): rsbac_adf_set_attr() returned error\n"); + } + } +#endif + out: /* It may be already another descriptor 8) Not kernel problem. */ return retval; @@ -1344,6 +1550,12 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, struct file *newfile1, *newfile2; int flags; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + flags = type & ~SOCK_TYPE_MASK; if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) return -EINVAL; @@ -1361,10 +1573,43 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, if (err < 0) goto out; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "sys_socketpair() [sys_socketcall()]: calling ADF\n"); + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = SOCK_INODE(sock1)->i_ino; + rsbac_attribute_value.sock_type = type; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_sock_type, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "sys_socketpair() [sys_socketcall()]: ADF returned NOT_GRANTED\n"); + err = -EPERM; + goto out_release_1; + } +#endif + err = sock_create(family, type, protocol, &sock2); if (err < 0) goto out_release_1; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "sys_socketpair() [sys_socketcall()]: calling ADF\n"); + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = SOCK_INODE(sock2)->i_ino; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_IPC, + rsbac_target_id, + A_sock_type, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "sys_socketpair() [sys_socketcall()]: ADF returned NOT_GRANTED\n"); + err = -EPERM; + goto out_release_both; + } +#endif + err = sock1->ops->socketpair(sock1, sock2); if (err < 0) goto out_release_both; @@ -1409,6 +1654,34 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, * Not kernel problem. */ +#ifdef CONFIG_RSBAC + rsbac_target_id.ipc.id.id_nr = SOCK_INODE(sock1)->i_ino; + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_CREATE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_sock_type, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_socketpair() [sys_socketcall()]: rsbac_adf_set_attr() for sock1 returned error\n"); + } + rsbac_target_id.ipc.id.id_nr = SOCK_INODE(sock2)->i_ino; + if (unlikely(rsbac_adf_set_attr(R_CREATE, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_sock_type, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_socketpair() [sys_socketcall()]: rsbac_adf_set_attr() for sock2 returned error\n"); + } +#endif + return 0; out_fput_both: @@ -1451,10 +1724,38 @@ SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) struct sockaddr_storage address; int err, fput_needed; +#ifdef CONFIG_RSBAC_NET_OBJ + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock) { err = move_addr_to_kernel(umyaddr, addrlen, &address); if (err >= 0) { +#ifdef CONFIG_RSBAC_NET_OBJ + if (sock->ops->family != AF_UNIX) { + rsbac_target_id.netobj.sock_p = sock; + rsbac_target_id.netobj.local_addr = (struct sockaddr *)&address; + rsbac_target_id.netobj.local_len = addrlen; + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; + rsbac_attribute_value.sock_type = sock->type; + rsbac_pr_debug(aef, "[sys_socketcall()]: calling ADF"); + if(!rsbac_adf_request(R_BIND, + task_pid(current), + T_NETOBJ, + rsbac_target_id, + A_sock_type, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "[sys_socketcall()]: ADF returned NOT_GRANTED\n"); + fput_light(sock->file, fput_needed); + return -EPERM; + } + } +#endif + err = security_socket_bind(sock, (struct sockaddr *)&address, addrlen); @@ -1462,6 +1763,23 @@ SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) err = sock->ops->bind(sock, (struct sockaddr *) &address, addrlen); + +#ifdef CONFIG_RSBAC_NET_OBJ + if (!err && sock->ops && (sock->ops->family != AF_UNIX)) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_BIND, + task_pid(current), + T_NETOBJ, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_sock_type, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_bind() [sys_socketcall()]: rsbac_adf_set_attr() returned error\n"); + } + } +#endif } fput_light(sock->file, fput_needed); } @@ -1478,10 +1796,60 @@ SYSCALL_DEFINE2(listen, int, fd, int, backlog) { struct socket *sock; int err, fput_needed; + +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + int somaxconn; sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock) { +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_socketcall()]: calling ADF\n"); + if (sock->ops->family == AF_UNIX) { + if (sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode) { + if (sock->file->f_path.dentry->d_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + } else { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = sock->file->f_path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = sock->file->f_path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = sock->file->f_path.dentry; + } + } + } +#ifdef CONFIG_RSBAC_NET_OBJ + else { + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p = sock; + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; + } +#endif + rsbac_attribute_value.sock_type = sock->type; + if ((rsbac_target != T_NONE) + && !rsbac_adf_request(R_LISTEN, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_sock_type, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "sys_listen() [sys_socketcall()]: ADF returned NOT_GRANTED\n"); + fput_light(sock->file, fput_needed); + return -EPERM; + } +#endif + somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; if ((unsigned int)backlog > somaxconn) backlog = somaxconn; @@ -1490,6 +1858,23 @@ SYSCALL_DEFINE2(listen, int, fd, int, backlog) if (!err) err = sock->ops->listen(sock, backlog); + +#ifdef CONFIG_RSBAC + if (!err && (rsbac_target != T_NONE)) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_LISTEN, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_sock_type, + rsbac_attribute_value))) + rsbac_printk(KERN_WARNING + "sys_listen() [sys_socketcall()]: rsbac_adf_set_attr() returned error\n"); + } +#endif + fput_light(sock->file, fput_needed); } return err; @@ -1515,6 +1900,14 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, int err, len, newfd, fput_needed; struct sockaddr_storage address; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + enum rsbac_attribute_t rsbac_attribute = A_none; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) return -EINVAL; @@ -1561,6 +1954,122 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, if (err < 0) goto out_fd; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_socketcall()]: calling ADF\n"); + if (sock->ops->family == AF_UNIX) { + if (sock->sk) { + if (unix_sk(unix_sk(sock->sk)->peer)) { + if (unix_sk(unix_sk(sock->sk)->peer)->path.dentry + && unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = unix_sk(unix_sk(sock->sk)->peer)->path.dentry; + } else { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + if (unix_sk(unix_sk(sock->sk)->peer)->path.dentry + && unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode + && SOCKET_I(unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode)->file + && SOCKET_I(unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode)->file->f_path.dentry + && SOCKET_I(unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode)->file->f_path.dentry->d_inode) + rsbac_target_id.ipc.id.id_nr = SOCKET_I(unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode)->file->f_path.dentry->d_inode->i_ino; + else + if (sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode) + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + else + rsbac_target_id.ipc.id.id_nr = 0; + } + } else { + if( unix_sk(sock->sk)->path.dentry + && unix_sk(sock->sk)->path.dentry->d_inode) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = unix_sk(sock->sk)->path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = unix_sk(sock->sk)->path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = unix_sk(sock->sk)->path.dentry; + } else { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + if (sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode) + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + else + rsbac_target_id.ipc.id.id_nr = 0; + } + } + } + if (sock->sk) { + rsbac_attribute_value.process = get_pid(sock->sk->sk_peer_pid); + if (rsbac_attribute_value.process) { + if (pid_nr(rsbac_attribute_value.process) > 0) { + rsbac_attribute = A_process; + rsbac_attribute_value.process = sock->sk->sk_peer_pid; + } else { + put_pid(rsbac_attribute_value.process); + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + } else { + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + } else { + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + } +#ifdef CONFIG_RSBAC_NET_OBJ + else { + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p = newsock; + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + if(newsock->ops->getname(newsock, (struct sockaddr *)&address, &len, 2) <0) { + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; + } else { + rsbac_target_id.netobj.remote_addr = (struct sockaddr *)&address; + rsbac_target_id.netobj.remote_len = len; + } + if (sock->sk) { + rsbac_attribute_value.process = get_pid(sock->sk->sk_peer_pid); + if (rsbac_attribute_value.process) { + if (pid_nr(rsbac_attribute_value.process) > 0) { + rsbac_attribute = A_process; + rsbac_attribute_value.process = sock->sk->sk_peer_pid; + } else { + put_pid(rsbac_attribute_value.process); + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + } else { + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + } else { + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + } +#endif + if ((rsbac_target != T_NONE) + && !rsbac_adf_request(R_ACCEPT, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_attribute, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "[sys_socketcall()]: ADF returned NOT_GRANTED\n"); + err = -EPERM; + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); + goto out_fd; + } +#endif + if (upeer_sockaddr) { if (newsock->ops->getname(newsock, (struct sockaddr *)&address, &len, 2) < 0) { @@ -1578,6 +2087,24 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, fd_install(newfd, newfile); err = newfd; +#ifdef CONFIG_RSBAC + if (rsbac_target != T_NONE) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_ACCEPT, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + rsbac_attribute, + rsbac_attribute_value))) + rsbac_printk(KERN_WARNING + "sys_accept() [sys_socketcall()]: rsbac_adf_set_attr() returned error\n"); + } + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); +#endif + out_put: fput_light(sock->file, fput_needed); out: @@ -1613,6 +2140,12 @@ SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, struct sockaddr_storage address; int err, fput_needed; +#ifdef CONFIG_RSBAC_NET_OBJ + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; @@ -1625,8 +2158,50 @@ SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, if (err) goto out_put; + /* RSBAC UNIX socket connects get intercepted in unix/af_unix.c */ +#ifdef CONFIG_RSBAC_NET_OBJ + if (sock->ops->family != AF_UNIX) { + rsbac_pr_debug(aef, "[sys_socketcall()]: calling ADF\n"); + rsbac_target_id.netobj.sock_p = sock; + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = (struct sockaddr *)&address; + rsbac_target_id.netobj.remote_len = addrlen; + rsbac_attribute_value.sock_type = sock->type; + if (!rsbac_adf_request(R_CONNECT, + task_pid(current), + T_NETOBJ, + rsbac_target_id, + A_sock_type, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "[sys_socketcall()]: ADF returned NOT_GRANTED\n"); + err = -EPERM; + goto out_put; + } + } +#endif + err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, sock->file->f_flags); + + /* RSBAC: notify ADF of opened socket connection */ +#ifdef CONFIG_RSBAC_NET_OBJ + if (!err + && (sock->ops->family != AF_UNIX)) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_CONNECT, + task_pid(current), + T_NETOBJ, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_sock_type, + rsbac_attribute_value))) + rsbac_printk(KERN_WARNING + "sys_connect() [sys_socketcall()]: rsbac_adf_set_attr() returned error\n"); + } +#endif + out_put: fput_light(sock->file, fput_needed); out: @@ -1645,6 +2220,12 @@ SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, struct sockaddr_storage address; int len, err, fput_needed; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; @@ -1653,6 +2234,47 @@ SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, if (err) goto out_put; +#if defined(CONFIG_RSBAC) + rsbac_pr_debug(aef, "calling ADF\n"); + if (sock->ops->family == AF_UNIX) { + if (sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode) { + if (sock->file->f_path.dentry->d_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + } else { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = sock->file->f_path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = sock->file->f_path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = sock->file->f_path.dentry; + } + } + } +#ifdef CONFIG_RSBAC_NET_OBJ + else { + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p = sock; + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; + } +#endif + rsbac_attribute_value.sock_type = sock->type; + if ((rsbac_target != T_NONE) + && !rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_sock_type, + rsbac_attribute_value)) { + err = -EPERM; + goto out_put; + } +#endif + err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0); if (err) goto out_put; @@ -1676,6 +2298,12 @@ SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, struct sockaddr_storage address; int len, err, fput_needed; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock != NULL) { err = security_socket_getpeername(sock); @@ -1684,6 +2312,47 @@ SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, return err; } +#if defined(CONFIG_RSBAC) + rsbac_pr_debug(aef, "calling ADF\n"); + if (sock->ops->family == AF_UNIX) { + if (sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode) { + if (sock->file->f_path.dentry->d_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + } else { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = sock->file->f_path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = sock->file->f_path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = sock->file->f_path.dentry; + } + } + } +#ifdef CONFIG_RSBAC_NET_OBJ + else { + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p = sock; + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; + } +#endif + rsbac_attribute_value.sock_type = sock->type; + if ((rsbac_target != T_NONE) + && !rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_sock_type, + rsbac_attribute_value)) { + fput_light(sock->file, fput_needed); + return -EPERM; + } +#endif + err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 1); @@ -1820,6 +2489,12 @@ SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, int err, fput_needed; struct socket *sock; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (optlen < 0) return -EINVAL; @@ -1829,6 +2504,47 @@ SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, if (err) goto out_put; +#if defined(CONFIG_RSBAC) + rsbac_pr_debug(aef, "calling ADF\n"); + if (sock->ops->family == AF_UNIX) { + if (sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode) { + if (sock->file->f_path.dentry->d_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + } else { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = sock->file->f_path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = sock->file->f_path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = sock->file->f_path.dentry; + } + } + } +#ifdef CONFIG_RSBAC_NET_OBJ + else { + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p = sock; + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; + } +#endif + rsbac_attribute_value.setsockopt_level = level; + if ((rsbac_target != T_NONE) + && !rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_setsockopt_level, + rsbac_attribute_value)) { + err = -EPERM; + goto out_put; + } +#endif + if (level == SOL_SOCKET) err = sock_setsockopt(sock, level, optname, optval, @@ -1854,12 +2570,62 @@ SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname, int err, fput_needed; struct socket *sock; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock != NULL) { err = security_socket_getsockopt(sock, level, optname); if (err) goto out_put; +#if defined(CONFIG_RSBAC) + rsbac_pr_debug(aef, "calling ADF\n"); + if (sock->ops->family == AF_UNIX) { + if (sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode + && sock->file->f_path.dentry->d_inode->i_ino + && sock->file->f_path.dentry->d_sb + && sock->file->f_path.dentry->d_sb->s_dev) { + if (sock->file->f_path.dentry->d_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + } else { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = sock->file->f_path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = sock->file->f_path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = sock->file->f_path.dentry; + } + } + } +#ifdef CONFIG_RSBAC_NET_OBJ + else { + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p = sock; + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; + } +#endif + rsbac_attribute_value.sock_type = sock->type; + if ((rsbac_target != T_NONE) + && !rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_sock_type, + rsbac_attribute_value)) { + err = -EPERM; + goto out_put; + } +#endif + if (level == SOL_SOCKET) err = sock_getsockopt(sock, level, optname, optval, @@ -1883,11 +2649,83 @@ SYSCALL_DEFINE2(shutdown, int, fd, int, how) int err, fput_needed; struct socket *sock; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; +#ifdef CONFIG_RSBAC_NET_OBJ + union rsbac_target_id_t rsbac_new_target_id; +#endif + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock != NULL) { err = security_socket_shutdown(sock, how); + +#ifdef CONFIG_RSBAC + if (!err) { + rsbac_pr_debug(aef, "[sys_socketcall()]: calling ADF\n"); + if (sock->ops->family == AF_UNIX) { + if (sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode) { + if (sock->file->f_path.dentry->d_sb->s_magic == SOCKFS_MAGIC) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + } else { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = sock->file->f_path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = sock->file->f_path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = sock->file->f_path.dentry; + } + } + } +#ifdef CONFIG_RSBAC_NET_OBJ + else { + rsbac_target = T_NETOBJ; + rsbac_target_id.netobj.sock_p = sock; + rsbac_target_id.netobj.local_addr = NULL; + rsbac_target_id.netobj.local_len = 0; + rsbac_target_id.netobj.remote_addr = NULL; + rsbac_target_id.netobj.remote_len = 0; + } +#endif + rsbac_attribute_value.sock_type = sock->type; + if ((rsbac_target != T_NONE) + && !rsbac_adf_request(R_NET_SHUTDOWN, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_sock_type, + rsbac_attribute_value)) { + err = -EPERM; + } + } +#endif + if (!err) err = sock->ops->shutdown(sock, how); + +#ifdef CONFIG_RSBAC_NET_OBJ + if (!err && (rsbac_target != T_NONE)) { + rsbac_pr_debug(aef, "calling rsbac_adf_set_attr() for NET_SHUTDOWN on netobj\n"); + rsbac_new_target_id.dummy = 0; + rsbac_attribute_value.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_NET_SHUTDOWN, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_sock_type, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "sys_shutdown(): rsbac_adf_set_attr() for NET_SHUTDOWN on socket returned error\n"); + } + } +#endif + fput_light(sock->file, fput_needed); } return err; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 7b52a380d710..583ec6ab16e9 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -119,6 +119,8 @@ #include #include +#include + struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE]; EXPORT_SYMBOL_GPL(unix_socket_table); DEFINE_SPINLOCK(unix_table_lock); @@ -831,9 +833,24 @@ static int unix_release(struct socket *sock) { struct sock *sk = sock->sk; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; +#endif + if (!sk) return 0; +#ifdef CONFIG_RSBAC + if ( sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode + ) { + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + rsbac_remove_target(T_IPC, rsbac_target_id); + } +#endif + unix_release_sock(sk, 0); sock->sk = NULL; @@ -850,6 +867,34 @@ static int unix_autobind(struct socket *sock) int err; unsigned int retries = 0; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "unix_autobind() [sys_bind()]: calling ADF\n"); + rsbac_target_id.ipc.type = I_anonunix; + if ( sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode + ) + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + else + rsbac_target_id.ipc.id.id_nr = 0; + rsbac_attribute_value.sock_type = sock->type; + if (!rsbac_adf_request(R_BIND, + task_pid(current), + T_IPC, + rsbac_target_id, + A_sock_type, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "unix_autobind() [sys_bind() etc.]: ADF returned NOT_GRANTED\n"); + return -EPERM; + } +#endif + err = mutex_lock_interruptible(&u->bindlock); if (err) return err; @@ -898,6 +943,21 @@ static int unix_autobind(struct socket *sock) err = 0; out: mutex_unlock(&u->bindlock); + +#ifdef CONFIG_RSBAC + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_BIND, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_sock_type, + rsbac_attribute_value))) + rsbac_printk(KERN_WARNING + "unix_autobind() [sys_bind() etc.]: rsbac_adf_set_attr() returned error\n"); +#endif + return err; } @@ -998,6 +1058,12 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct hlist_head *list; struct path path = { }; +#ifdef CONFIG_RSBAC + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + err = -EINVAL; if (addr_len < offsetofend(struct sockaddr_un, sun_family) || sunaddr->sun_family != AF_UNIX) @@ -1025,6 +1091,35 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) } err = mutex_lock_interruptible(&u->bindlock); +#ifdef CONFIG_RSBAC + if (!sun_path[0]) { + rsbac_pr_debug(aef, "unix_bind() [sys_bind()]: calling ADF\n"); + rsbac_target_id.ipc.type = I_anonunix; + if ( sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode + ) + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + else + rsbac_target_id.ipc.id.id_nr = 0; + rsbac_attribute_value.sock_type = sock->type; + if (!rsbac_adf_request(R_BIND, + task_pid(current), + T_IPC, + rsbac_target_id, + A_sock_type, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "unix_bind() [sys_bind()]: ADF returned NOT_GRANTED\n"); + err = -EPERM; + goto out; + } + } else { + /* RSBAC add: set credentials so that sendto() can copy them */ + if (sock->type == SOCK_DGRAM) + init_peercred(sk); + } +#endif + if (err) goto out_put; @@ -1058,6 +1153,21 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) } list = &unix_socket_table[addr->hash]; + +#ifdef CONFIG_RSBAC + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_BIND, + task_pid(current), + T_IPC, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_sock_type, + rsbac_attribute_value))) + rsbac_printk(KERN_WARNING + "unix_bind() [sys_bind()]: rsbac_adf_set_attr() returned error\n"); +#endif + } err = 0; @@ -1111,6 +1221,14 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, unsigned int hash; int err; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + enum rsbac_attribute_t rsbac_attribute = A_none; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + err = -EINVAL; if (alen < offsetofend(struct sockaddr, sa_family)) goto out; @@ -1147,6 +1265,47 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, if (err) goto out_unlock; +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "[sys_connect() [sys_socketcall()]]: calling ADF\n"); + /* Named socket? */ + if(sunaddr->sun_path[0]) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = unix_sk(other)->path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = unix_sk(other)->path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = unix_sk(other)->path.dentry; + } else { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = unix_sk(other)->path.dentry->d_inode->i_ino; + } + if ( other->sk_peer_pid + && (pid_nr(other->sk_peer_pid) > 0) + ) { + rsbac_attribute = A_process; + rsbac_attribute_value.process = get_pid(other->sk_peer_pid); + } else if ( sk->sk_peer_pid + && (pid_nr(sk->sk_peer_pid) > 0) + ) { + rsbac_attribute = A_process; + rsbac_attribute_value.process = get_pid(sk->sk_peer_pid); + } else { + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + if (!rsbac_adf_request(R_CONNECT, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_attribute, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "[sys_connect() [sys_socketcall()]]: ADF returned NOT_GRANTED\n"); + err = -EPERM; + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); + goto out_unlock; + } +#endif + } else { /* * 1003.1g breaking connected state with AF_UNSPEC @@ -1172,6 +1331,26 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, unix_peer(sk) = other; unix_state_double_unlock(sk, other); } + +#ifdef CONFIG_RSBAC + if (rsbac_target != T_NONE) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_CONNECT, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + rsbac_attribute, + rsbac_attribute_value))) + rsbac_printk(KERN_WARNING + "unix_dgram_connect() [sys_connect() [sys_socketcall()]]: rsbac_adf_set_attr() returned error\n"); + } + + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); +#endif + return 0; out_unlock: @@ -1217,6 +1396,15 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, int err; long timeo; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + enum rsbac_target_t rsbac_new_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + enum rsbac_attribute_t rsbac_attribute = A_none; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + err = unix_mkname(sunaddr, addr_len, &hash); if (err < 0) goto out; @@ -1322,6 +1510,57 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, goto out_unlock; } +#ifdef CONFIG_RSBAC + rsbac_pr_debug(aef, "unix_stream_connect() [sys_connect()]: calling ADF\n"); + /* Named socket? */ + if (unix_sk(other)->path.dentry&& unix_sk(other)->path.dentry->d_inode) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = unix_sk(other)->path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = unix_sk(other)->path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = unix_sk(other)->path.dentry; + } else { + if (other->sk_socket + && other->sk_socket->file + && other->sk_socket->file->f_path.dentry + && other->sk_socket->file->f_path.dentry->d_inode + ) { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + rsbac_target_id.ipc.id.id_nr = other->sk_socket->file->f_path.dentry->d_inode->i_ino; + } + } + if (rsbac_target != T_NONE) { + if ( other->sk_peer_pid + && (pid_nr(other->sk_peer_pid) > 0) + ) { + rsbac_attribute = A_process; + rsbac_attribute_value.process = get_pid(other->sk_peer_pid); + } else if ( sk->sk_peer_pid + && (pid_nr(sk->sk_peer_pid) > 0) + ) { + rsbac_attribute = A_process; + rsbac_attribute_value.process = get_pid(sk->sk_peer_pid); + } else { + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + if (!rsbac_adf_request(R_CONNECT, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_attribute, + rsbac_attribute_value)) { + rsbac_pr_debug(aef, "[sys_connect() [sys_socketcall()]]:" + " ADF returned NOT_GRANTED\n"); + err = -EPERM; + unix_state_unlock(sk); + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); + goto out_unlock; + } + } +#endif + /* The way is open! Fastly set all the necessary fields... */ sock_hold(sk); @@ -1361,6 +1600,56 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, spin_unlock(&other->sk_receive_queue.lock); unix_state_unlock(other); other->sk_data_ready(other); + +#ifdef CONFIG_RSBAC + if (rsbac_target != T_NONE) { + if (newu->path.dentry && newu->path.dentry->d_inode) { + rsbac_new_target = T_UNIXSOCK; + rsbac_new_target_id.unixsock.device = newu->path.dentry->d_sb->s_dev; + rsbac_new_target_id.unixsock.inode = newu->path.dentry->d_inode->i_ino; + rsbac_new_target_id.unixsock.dentry_p = newu->path.dentry; + } else { + if (newsk->sk_socket + && newsk->sk_socket->file + && newsk->sk_socket->file->f_path.dentry + && newsk->sk_socket->file->f_path.dentry->d_inode + ) { + rsbac_new_target = T_IPC; + rsbac_new_target_id.ipc.type = I_anonunix; + rsbac_new_target_id.ipc.id.id_nr = newsk->sk_socket->file->f_path.dentry->d_inode->i_ino; + } + } + if (unlikely(rsbac_adf_set_attr(R_CONNECT, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_new_target, + rsbac_new_target_id, + rsbac_attribute, + rsbac_attribute_value))) + rsbac_printk(KERN_WARNING + "unix_stream_connect() [sys_connect() [sys_socketcall()]]: rsbac_adf_set_attr() returned error\n"); +#ifdef CONFIG_RSBAC_NET +#ifdef CONFIG_RSBAC_DEBUG + if ( rsbac_debug_aef_net + && sk->sk_socket + && newsk->sk_socket + && other->sk_socket + ) { + rsbac_printk("unix_stream_connect() [sys_connect()]: connected from %u to %u (type %u), orig %u\n", + sk->sk_socket->file->f_path.dentry->d_inode->i_ino, + newsk->sk_socket->file->f_path.dentry->d_inode->i_ino, + rsbac_target, + other->sk_socket->file->f_path.dentry->d_inode->i_ino); + } +#endif +#endif + } + + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); +#endif + sock_put(other); return 0; @@ -1443,6 +1732,21 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags, unix_state_lock(tsk); newsock->state = SS_CONNECTED; unix_sock_inherit_flags(sock, newsock); + +#ifdef CONFIG_RSBAC + /* copy dentry and mnt, if there */ + if (unix_sk(sk)->path.dentry) { + if (!unix_sk(tsk)->path.dentry) { + unix_sk(tsk)->path.dentry = dget(unix_sk(sk)->path.dentry); + unix_sk(tsk)->path.mnt = mntget(unix_sk(sk)->path.mnt); + } + if (newsock->sk && !unix_sk(newsock->sk)->path.dentry) { + unix_sk(newsock->sk)->path.dentry = dget(unix_sk(sk)->path.dentry); + unix_sk(newsock->sk)->path.mnt = mntget(unix_sk(sk)->path.mnt); + } + } +#endif + sock_graft(tsk, newsock); unix_state_unlock(tsk); return 0; @@ -1653,6 +1957,14 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int data_len = 0; int sk_locked; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + enum rsbac_attribute_t rsbac_attribute = A_none; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + wait_for_unix_gc(); err = scm_send(sock, msg, &scm, false); if (err < 0) @@ -1778,6 +2090,61 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, goto out_unlock; } +#if defined(CONFIG_RSBAC) + if (other->sk_socket) { + if (rsbac_attribute == A_process) { + put_pid(rsbac_attribute_value.process); + } + rsbac_pr_debug(aef, "unix_dgram_sendmsg() [sys_send(), sys_sendto(), sys_sendmsg()]: calling ADF\n"); + if ( other->sk_socket->sk + && unix_sk(other->sk_socket->sk)->path.dentry + && unix_sk(other->sk_socket->sk)->path.dentry->d_sb + && unix_sk(other->sk_socket->sk)->path.dentry->d_inode + ) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = unix_sk(other->sk_socket->sk)->path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = unix_sk(other->sk_socket->sk)->path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = unix_sk(other->sk_socket->sk)->path.dentry; + } else { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + if ( other->sk_socket->file + && other->sk_socket->file->f_path.dentry + && other->sk_socket->file->f_path.dentry->d_inode + ) + rsbac_target_id.ipc.id.id_nr = other->sk_socket->file->f_path.dentry->d_inode->i_ino; + else + rsbac_target_id.ipc.id.id_nr = 0; + } + if ( sk->sk_peer_pid + && (pid_nr(sk->sk_peer_pid) > 0) + ) { + rsbac_attribute = A_process; + rsbac_attribute_value.process = get_pid(sk->sk_peer_pid); + } else if ( other->sk_socket->sk + && other->sk_socket->sk->sk_peer_pid + && (pid_nr(other->sk_socket->sk->sk_peer_pid) > 0) + ) { + rsbac_attribute = A_process; + rsbac_attribute_value.process = get_pid(other->sk_socket->sk->sk_peer_pid); + } else { + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + if(!rsbac_adf_request(R_SEND, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_attribute, + rsbac_attribute_value)) { + err = -EPERM; + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); + goto out_unlock; + } + } +#endif + /* other == sk && unix_peer(other) != sk if * - unix_peer(sk) == NULL, destination address bound to sk * - unix_peer(sk) == sk by time of get but disconnected before lock @@ -1825,6 +2192,26 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, other->sk_data_ready(other); sock_put(other); scm_destroy(&scm); + +#if defined(CONFIG_RSBAC) + if ((len > 0) && (rsbac_target != T_NONE)) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_SEND, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + rsbac_attribute, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "unix_dgram_sendmsg() [sys_send(), sys_sendto(), sys_sendmsg()]: rsbac_adf_set_attr() returned error\n"); + } + } + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); +#endif + return len; out_unlock: @@ -1858,6 +2245,14 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, int max_level; int data_len; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + enum rsbac_attribute_t rsbac_attribute = A_none; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + wait_for_unix_gc(); err = scm_send(sock, msg, &scm, false); if (err < 0) @@ -1880,6 +2275,56 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, if (sk->sk_shutdown & SEND_SHUTDOWN) goto pipe_err; +#if defined(CONFIG_RSBAC) + if (other->sk_socket) { + rsbac_pr_debug(aef, "unix_stream_sendmsg() [sys_send(), sys_sendto(), sys_sendmsg()]: calling ADF\n"); + if ( other->sk_socket->sk + && unix_sk(other->sk_socket->sk)->path.dentry + && unix_sk(other->sk_socket->sk)->path.dentry->d_sb + && unix_sk(other->sk_socket->sk)->path.dentry->d_inode + ) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = unix_sk(other->sk_socket->sk)->path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = unix_sk(other->sk_socket->sk)->path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = unix_sk(other->sk_socket->sk)->path.dentry; + } else { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + if ( other->sk_socket->file + && other->sk_socket->file->f_path.dentry + && other->sk_socket->file->f_path.dentry->d_inode + ) + rsbac_target_id.ipc.id.id_nr = other->sk_socket->file->f_path.dentry->d_inode->i_ino; + else + rsbac_target_id.ipc.id.id_nr = 0; + } + if ( sk->sk_peer_pid + && (pid_nr(sk->sk_peer_pid) > 0) + ) { + rsbac_attribute = A_process; + rsbac_attribute_value.process = get_pid(sk->sk_peer_pid); + } else if ( other->sk_socket->sk + && other->sk_socket->sk->sk_peer_pid + && (pid_nr(other->sk_socket->sk->sk_peer_pid) > 0) + ) { + rsbac_attribute = A_process; + rsbac_attribute_value.process = get_pid(other->sk_socket->sk->sk_peer_pid); + } else { + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + if(!rsbac_adf_request(R_SEND, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_attribute, + rsbac_attribute_value)) { + err = -EPERM; + goto out_err; + } + } +#endif + while (sent < len) { size = len - sent; @@ -1934,6 +2379,25 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, scm_destroy(&scm); +#if defined(CONFIG_RSBAC) + if (sent && (rsbac_target != T_NONE)) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_SEND, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + rsbac_attribute, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "unix_stream_sendmsg() [sys_send(), sys_sendto(), sys_sendmsg()]: rsbac_adf_set_attr() returned error\n"); + } + } + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); +#endif + return sent; pipe_err_free: @@ -1945,6 +2409,26 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, err = -EPIPE; out_err: scm_destroy(&scm); + +#if defined(CONFIG_RSBAC) + if (sent > 0) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_SEND, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + rsbac_attribute, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "unix_stream_sendmsg() [sys_send(), sys_sendto(), sys_sendmsg()]: rsbac_adf_set_attr() returned error\n"); + } + } + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); +#endif + return sent ? : err; } @@ -2115,10 +2599,79 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, int err; int peeked, skip; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + enum rsbac_attribute_t rsbac_attribute = A_none; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + err = -EOPNOTSUPP; if (flags&MSG_OOB) goto out; +#if defined(CONFIG_RSBAC) + rsbac_pr_debug(aef, "unix_dgram_recvmsg() [sys_recv(), sys_recvfrom(), sys_recvmsg()]: calling ADF\n"); + if (unix_peer(sk)) { + if ( unix_sk(unix_peer(sk))->path.dentry + && unix_sk(unix_peer(sk))->path.dentry->d_sb + && unix_sk(unix_peer(sk))->path.dentry->d_inode + ) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = unix_sk(unix_peer(sk))->path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = unix_sk(unix_peer(sk))->path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = unix_sk(unix_peer(sk))->path.dentry; + } else { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + if ( unix_peer(sk)->sk_socket + && unix_peer(sk)->sk_socket->file + && unix_peer(sk)->sk_socket->file->f_path.dentry + && unix_peer(sk)->sk_socket->file->f_path.dentry->d_inode + ) + rsbac_target_id.ipc.id.id_nr = unix_peer(sk)->sk_socket->file->f_path.dentry->d_inode->i_ino; + } + } else { + if ( unix_sk(sk)->path.dentry + && unix_sk(sk)->path.dentry->d_inode + ) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = unix_sk(sk)->path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = unix_sk(sk)->path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = unix_sk(sk)->path.dentry; + } else { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + if ( sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode + ) + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + else + rsbac_target_id.ipc.id.id_nr = 0; + } + } + if ( sk->sk_peer_pid + && (pid_nr(sk->sk_peer_pid) > 0) + ) { + rsbac_attribute = A_process; + rsbac_attribute_value.process = get_pid(sk->sk_peer_pid); + } else { + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + if(!rsbac_adf_request(R_RECEIVE, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_attribute, + rsbac_attribute_value)) { + err = -EPERM; + goto out; + } +#endif + timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); do { @@ -2204,6 +2757,26 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, skb_free_datagram(sk, skb); mutex_unlock(&u->iolock); out: + +#if defined(CONFIG_RSBAC) + if (err > 0) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_RECEIVE, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + rsbac_attribute, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "unix_dgram_recvmsg() [sys_recv(), sys_recvfrom(), sys_recvmsg()]: rsbac_adf_set_attr() returned error\n"); + } + } + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); +#endif + return err; } @@ -2284,6 +2857,14 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, size_t size = state->size; unsigned int last_len; +#ifdef CONFIG_RSBAC + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + enum rsbac_attribute_t rsbac_attribute = A_none; + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + if (unlikely(sk->sk_state != TCP_ESTABLISHED)) { err = -EINVAL; goto out; @@ -2294,6 +2875,67 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, goto out; } +#if defined(CONFIG_RSBAC) + rsbac_pr_debug(aef, "unix_stream_read_generic() [unix_stream_recvmsg() [sys_recv(), sys_recvfrom(), sys_recvmsg()]]: calling ADF\n"); + if (unix_peer(sk)) { + if ( unix_sk(unix_peer(sk))->path.dentry + && unix_sk(unix_peer(sk))->path.dentry->d_sb + && unix_sk(unix_peer(sk))->path.dentry->d_inode + ) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = unix_sk(unix_peer(sk))->path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = unix_sk(unix_peer(sk))->path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = unix_sk(unix_peer(sk))->path.dentry; + } else { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + if ( unix_peer(sk)->sk_socket + && unix_peer(sk)->sk_socket->file + && unix_peer(sk)->sk_socket->file->f_path.dentry + && unix_peer(sk)->sk_socket->file->f_path.dentry->d_inode + ) + rsbac_target_id.ipc.id.id_nr = unix_peer(sk)->sk_socket->file->f_path.dentry->d_inode->i_ino; + } + } else { + if ( unix_sk(sk)->path.dentry + && unix_sk(sk)->path.dentry->d_inode + ) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = unix_sk(sk)->path.dentry->d_sb->s_dev; + rsbac_target_id.unixsock.inode = unix_sk(sk)->path.dentry->d_inode->i_ino; + rsbac_target_id.unixsock.dentry_p = unix_sk(sk)->path.dentry; + } else { + rsbac_target = T_IPC; + rsbac_target_id.ipc.type = I_anonunix; + if ( sock->file + && sock->file->f_path.dentry + && sock->file->f_path.dentry->d_inode + ) + rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + else + rsbac_target_id.ipc.id.id_nr = 0; + } + } + if ( sk->sk_peer_pid + && (pid_nr(sk->sk_peer_pid) > 0) + ) { + rsbac_attribute = A_process; + rsbac_attribute_value.process = get_pid(sk->sk_peer_pid); + } else { + rsbac_attribute = A_sock_type; + rsbac_attribute_value.sock_type = sock->type; + } + if(!rsbac_adf_request(R_RECEIVE, + task_pid(current), + rsbac_target, + rsbac_target_id, + rsbac_attribute, + rsbac_attribute_value)) { + err = -EPERM; + goto out; + } +#endif + target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); timeo = sock_rcvtimeo(sk, noblock); @@ -2464,6 +3106,25 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, else scm_destroy(&scm); out: +#if defined(CONFIG_RSBAC) + if (copied > 0) { + rsbac_new_target_id.dummy = 0; + if (unlikely(rsbac_adf_set_attr(R_RECEIVE, + task_pid(current), + rsbac_target, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + rsbac_attribute, + rsbac_attribute_value))) { + rsbac_printk(KERN_WARNING + "unix_stream_read_generic() [unix_stream_recvmsg() [sys_recv(), sys_recvfrom(), sys_recvmsg()]]: rsbac_adf_set_attr() returned error\n"); + } + } + if (rsbac_attribute == A_process) + put_pid(rsbac_attribute_value.process); +#endif + return copied ? : err; } diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index 6cdb054484d6..ace7412c6876 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -20,6 +20,8 @@ #include #include +#include + typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, unsigned int, struct iw_request_info *, iw_handler); @@ -980,9 +982,37 @@ static int wext_ioctl_dispatch(struct net *net, struct iwreq *iwr, { int ret = wext_permission_check(cmd); +#ifdef CONFIG_RSBAC_NET_DEV + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#ifndef CONFIG_RSBAC_NET_DEV_VIRT + char * rsbac_colon; +#endif +#endif + if (ret) return ret; +#ifdef CONFIG_RSBAC_NET_DEV + rsbac_pr_debug(aef, " calling ADF\n"); + strncpy(rsbac_target_id.netdev, ifr->ifr_name, RSBAC_IFNAMSIZ); + rsbac_target_id.netdev[RSBAC_IFNAMSIZ] = 0; +#ifndef CONFIG_RSBAC_NET_DEV_VIRT + rsbac_colon = strchr(rsbac_target_id.netdev, ':'); + if (rsbac_colon) + *rsbac_colon = 0; +#endif + rsbac_attribute_value.dummy = 0; + + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_NETDEV, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + return -EPERM; +#endif + dev_load(net, iwr->ifr_name); rtnl_lock(); ret = wireless_process_ioctl(net, iwr, cmd, info, standard, private); diff --git a/rsbac/Kconfig b/rsbac/Kconfig new file mode 100644 index 000000000000..4a6ae294d413 --- /dev/null +++ b/rsbac/Kconfig @@ -0,0 +1,2332 @@ +# +# RSBAC configuration +# (c) 1999-2016 Amon Ott +# + +menuconfig RSBAC + bool "Rule Set Based Access Control (RSBAC)" + default y + ---help--- + RSBAC adds 'real' access control to the kernel. Currently there are + the following policies supported: Mandatory Access Control, + Functional Control, Privacy Model, Dazuko, File Flags, + Role Compatibility, Authentication Enforcement, User Management, + Access Control Lists, System Resources, Linux Capabilities and Jail. + + Additionally, you can add your own policies, e.g. as a kernel module + (see Module Registration (REG)). + + Since RSBAC exclusively uses the virtual file system, files on all + mounted filesystems are monitored. Still, on some filesystems, no + access control information is stored, it is instead kept in kernel + memory. These file system types are currently PROC, NFS, CODAFS, SMBFS + NCPFS, ISO9660 and (configurable below) all MSDOS types (inodes may + change between boots). You can make attribute backups and restore them + on each boot to keep them persistent. + + RSBAC will increase your kernel size by up to 520K with all options + turned on, plus allocated memory for dynamical data structures. + If you are tight on memory, it is generally a good idea to turn off + those features which you do not need. + + Please read the RSBAC docs in Documentation/rsbac or + http://www.rsbac.org/documentation before installing a RSBAC enabled + kernel, since you can easily make your system unaccessible when + changing the RSBAC configuration... + +if RSBAC + +menu "General RSBAC options" + depends on RSBAC=y + +config RSBAC_INIT_THREAD + bool 'Initialize RSBAC in separate kernel thread' + ---help--- + Some people experienced system hangs, oopses etc. during RSBAC + initialization. If you experience this, enabling this option might + help. + + At least, init can be timed out and the system more or less comes up - + if you are in softmode or maintenance mode, that is. The timeout value + is indicated by the RSBAC_MAX_INIT_TIME configure option below. + +config RSBAC_MAX_INIT_TIME + int 'Initialization timeout in seconds' + default 60 + depends on RSBAC_INIT_THREAD=y + ---help--- + Maximum time in seconds the init process waits for rsbac_initd to + complete the RSBAC initialization process via rsbac_do_init(). After + this time, RSBAC initialization is considered as failed and + rsbac_initd is killed. + +config RSBAC_PROC + bool 'RSBAC proc support' + depends on PROC_FS + default y + ---help--- + If enabled, RSBAC adds one directory to the main proc dir, called + rsbac-info. + The files in rsbac-info give read access to RSBAC statistics, and + read and write access to many RSBAC settings. + + If unsure, say Y. + + See for details. + +config RSBAC_INIT_CHECK + bool 'Check on init' + default y + ---help--- + Check RSBAC attribute consistency at boot time. + + NOTE: This cannot check attributes on other than the root filesystem. + You should run rsbac_check regularly, e.g. once per day from + cron. + +config RSBAC_NO_WRITE + bool 'Disable RSBAC writing to disk' + ---help--- + If enabled, RSBAC treats all file system types as read-only. No + attributes are saved and all settings are instead kept in memory. + If off, only PROC, NFS, CODAFS, SMBFS, NCPFS, ISO9660 and all MSDOS + filesystems are read-only. + + If you only want to turn off automatical writing, but keep the + syscall sys_rsbac_write() to write by hand, set auto write to 0 + instead. + + This switch is intended for testing purposes only and off by + default. + + If unsure, say N. + +config RSBAC_MSDOS_WRITE + bool 'Allow attribute writing on MSDOS filesystems' + depends on RSBAC_NO_WRITE=n + ---help--- + This setting allows attribute writing on MSDOS filesystems, like FAT, + VFAT, UMSDOS. Turning it on makes these attributes persistent through + reboots. + Unfortunately, MSDOS filesystems do not guarantee reproducable inode + numbers on reboots - so attributes might be applied to wrong files or + get lost. Watch for warning messages from rsbac_check. + + As a more reliable alternative, disable this feature, and make regular + attribute backups, which you can restore each time after mounting + the disk. + + If unsure, say N. + +config RSBAC_AUTO_WRITE + int 'RSBAC auto write to disk interval in seconds' + default 5 + depends on RSBAC_NO_WRITE=n + ---help--- + If not 0, a kernel daemon saves all changed RSBAC attributes to disk + every n seconds. You can also initiate each saving through the + sys_rsbac_write() syscall. This interval can alternatively be changed + via the proc interface. + +config RSBAC_RCU_RATE + int 'RSBAC attribute change burst per second' + default 1000 + ---help--- + Normally, RSBAC removes list items in the background while the + process continues without delay. Keeping the items longer needs + extra memory, so a rate limit ensures that memory does not get + exhausted. + + When the limit has been reached, deleting items is still + possible, but the process gets delayed until all possible + readers of the deleted item have finished reading and the item + is deleted immediately. This slows down attribute changes + somewhat, but should only be noticable on mass changes like at + a restore. + + The default value of 1000 should be fine for normal system use + even with FD cache. Valid values are 0 to 1000, 0 means always + wait for readers. + The value can later be changed at boot time with + rsbac_list_rcu_rate=n kernel parameter and at runtime through + /proc/rsbac-info/debug. + +config RSBAC_LIST_MAX_HASH_BITS + int 'Maximum number of list hash bits' + default 9 + ---help--- + Define the maximum number of bits for internal hashes per generic + list. The number of lists is 2^number. + Bigger values may need more memory, but allow to distribute many + list items over more and thus smaller lists behind the hashes. + It is safe to change this value at any time, but it may not + go below 3 or above 18. The system will not use more hashes per + list than necessary, see next item for more info. Default is 9. + +config RSBAC_LIST_AUTO_REHASH_TRIGGER + int 'Rehash trigger number of list items per hash' + default 20 + ---help--- + If the average number of items per hashed list is bigger than + this value and the list flag RSBAC_LIST_AUTO_HASH_RESIZE is set + for the list, rehash it with higher number of hash bits up to + CONFIG_RSBAC_LIST_MAX_HASH_BITS. + +config RSBAC_LIST_CHECK_INTERVAL + int 'Interval of automatic list check and cleanup' + default 1800 + depends on CONFIG_RSBAC_AUTO_WRITE!=0 + ---help--- + Check all lists and remove items over ttl at this interval. + Uses rsbacd and thus uses CONFIG_RSBAC_AUTO_WRITE granularity. + + Default is 1800, one half hour. + +config RSBAC_LIST_STATS + bool 'List access statistics' + default n + ---help--- + Count read and write accesses to each list for optimization. + The values are shown in /proc/rsbac-info/gen_list_counts. + +config RSBAC_LIST_TRANS + bool 'Support transactions' + default y + ---help--- + This option enables support for RSBAC configuration transactions. + RSBAC transactions are a set of temporary changes within a list that + are either commited or forgotten. + + Any user can start a transaction with the rsbac_list_ta() syscall + (e.g. via the rsbac_list_ta admin tool), and use the returned + transaction number for further administration calls which collect a + set of allowed changes. + + When finished, a simple commit through rsbac_list_ta applies all these + changes atomically to the system, while the forget command or a + transaction timeout (see next option) remove the complete set of + proposes changes. + + The number of transactions in parallel is not limited, but each list, + which has been changed by one transaction, is locked against changes + by all other transactions. Such change attempts return the error + -RSBAC_EBUSY, while using invalid transaction numbers returns the + error -RSBAC_EINVALIDTRANSACTION. This means that when using + transactions, both error codes should be checked for each call. When + a list is BUSY, it is the user's choice to retry later, forget all + changes or leave it as it is. + + Changes with transaction number 0 (no transaction) and automatic + changes by the system always affect both the real lists and all + transaction lists. + +config RSBAC_LIST_TRANS_MAX_TTL + int 'Maximum transaction time in seconds' + default 3600 + depends on RSBAC_LIST_TRANS + ---help--- + When starting a transaction, the ttl parameter sets its maximum + lifetime, after which it will be automatically removed, if + it has not been renewed in time. + This option sets the maximum allowed lifetime for any transaction in + seconds. The default value is 3600 (one hour). + +config RSBAC_LIST_TRANS_RANDOM_TA + bool 'Randomize transaction numbers' + default y + depends on RSBAC_LIST_TRANS + ---help--- + Usually, transaction numbers start with one and increase with every + new transaction. With this option, they will be randomized to make + it a bit more difficult to tamper with other admins' transactions. + + However, this is no real protection and makes transactions less human + friendly because of large numbers - use the transaction key or the + user limit to get more security for transaction handling. + +config RSBAC_FD_CACHE + bool 'Cache FD attribute values' + default n + ---help--- + This option allows to cache inherited attribute values for some + modules. It speeds up attribute lookup, but increases memory + usage significantly. + +config RSBAC_FD_CACHE_TTL + int 'Time to live for FD cache items' + default 3600 + depends on RSBAC_FD_CACHE + ---help--- + After the time given here in seconds, FD cache items will be + removed at the next list cleanup. You can change the value at + boottime with kernel parameter rsbac_fd_cache_ttl= and at + runtime through /proc/rsbac-info/debug interface. + Please also adjust CONFIG_RSBAC_LIST_CHECK_INTERVAL + accordingly to get items over ttl expunged timely. + + Default is 3600, one hour. + +config RSBAC_FD_CACHE_MAX_ITEMS + int 'Maximum number of FD cache items per hash' + default 100 + depends on RSBAC_FD_CACHE + ---help--- + Specify the maximum number of cache FD items allowed per + hashed list. Multiply by max number of hashes per list to get + total maximum number of cache entries. + + Default is 100. + +config RSBAC_DEBUG + bool 'RSBAC debugging support' + default y + ---help--- + This option enables many debugging switches to examine RSBAC internals + as well as request sanity checks. + Most of the debugging switches can be set with rsbac_debug_* kernel + parameters or via proc interface at /proc/rsbac-info/debug. + See for details. + + This option is recommended to be on, but you may as well turn it off, + if performance really matters and your RSBAC system runs without + problems. + + If unsure, say Y. + +config RSBAC_DEV_USER_BACKUP + bool 'Provide DEV and USER backup files' + depends on RSBAC_PROC=y + ---help--- + If enabled, you will find images of the USER and DEV target general + attribute list files in /proc/rsbac-info/backup. Since attribute + backup should be done with tools, this is usually not needed and + thus off by default. + + If unsure, say N. + +config RSBAC_SECOFF_UID + int 'RSBAC default security officer user ID' + default 400 + ---help--- + The number n given here specifies which user IDs should be used for + the Security Officer/Role Admin/Supervisor in the default + configuration at first boot. + + WARNING: This value should only be changed if you have a severe + conflict with the default value of 400. After the + first boot, the defaults are set and saved, and changes to + this option will not have any effect. + +config RSBAC_INIT_DELAY + bool 'Delayed init for initial ramdisk' + ---help--- + This option allows to delay RSBAC initialization until the first mount + of a real disk partition (major number > 1). It is intended to be used + with initial ramdisks, which mount the final root partition during + boot. + + You can trigger initialization at a specific partition mount with the + kernel parameter rsbac_delayed_root=major:minor. If the given + partition is not mounted and thus RSBAC not initialized, you can also + call the rsbac_init() system call at any time, e.g. with the + rsbac_init utility. + + To disable delayed init, you have to use the kernel parameter + rsbac_no_delay_init. This will force the standard initialization after + the first root mount. If this is your initrd, the RSBAC setup in there + will be used instead of the configuration on your real root device. + + WARNING: The delayed init option requires the RSBAC init code to be + kept in memory all the time, which increases your kernel + memory usage by a few 10s of KB. It should only be used in + combination with an initial ramdisk. +endmenu + +menuconfig RSBAC_UM + depends on RSBAC=y + bool 'User Management' + ---help--- + Enable RSBAC User Management, a fully passwd/shadow compatible, but + kernel based Linux user and group database. All changes are access + controlled with USER and GROUP targets. + + You will need the PAM and NSS modules from the RSBAC admin tools + contrib section to make transparent use of this feature. + + If the SHA1 algorithm is available through the crypto API, passwords + can also optionally be encrypted (next option). + +if RSBAC_UM +config RSBAC_UM_DIGEST + bool 'Use Crypto API Digest SHA1' + depends on RSBAC_UM=y + select CRYPTO + select CRYPTO_SHA1 + default y + ---help--- + If enabled, all passwords are hashed with SHA1 digests. To make the + resulting hash values unique, the password functions add a 32 Bit + salt value to the password string before hashing. + +config RSBAC_UM_USER_MIN + int 'Minimum auto user ID' + depends on RSBAC_UM=y + default 2000 + ---help--- + When users get added without giving a desired ID, the system picks the + lowest available number starting from the set value. + +config RSBAC_UM_GROUP_MIN + int 'Minimum auto group ID' + depends on RSBAC_UM=y + default 2000 + ---help--- + When groups get added without giving a desired ID, the system picks + the lowest available number starting from the set value. + +config RSBAC_UM_EXCL + bool 'Exclusive user management' + depends on RSBAC_UM=y + ---help--- + With this option, RSBAC makes sure that only user and group IDs it + knows about can be used within the system. The User Management + component will only make consistency checks, but the AUTH module will + enforce the exclusive use. + +config RSBAC_UM_MIN_PASS_LEN + int 'Minimum password length' + default 6 + depends on RSBAC_UM=y + ---help--- + Set this to the minimum length a password set by the user must have. + The default minimum length is 6, but using at least 8 is recommended + for production systems. + + Passwords set by admins with MODIFY_PERMISSIONS_DATA right to the user + will not be restricted! + +config RSBAC_UM_NON_ALPHA + bool 'Require non-alphabetic character in password' + default y + depends on RSBAC_UM=y + ---help--- + This option requires that a password set by the user must have at + least one non-alphabetic character. + + Passwords set by admins with MODIFY_PERMISSIONS_DATA right on the + user will not be restricted! + +config RSBAC_UM_PWHISTORY + bool 'Remember password history' + default y + depends on RSBAC_UM=y + ---help--- + This option requires that the password set by the user must not be + the same as the RSBAC_UM_HISTORY_SIZE previous ones. + + Passwords set by admins with MODIFY_PERMISSIONS_DATA right on the + user will not be restricted! + +config RSBAC_UM_PWHISTORY_MAX + int 'Number of successive passwords to remember' + default 8 + depends on RSBAC_UM_PWHISTORY=y + ---help--- + This is the number of passwords RSBAC User Management will + remember and check against when changing a password. + +config RSBAC_UM_ONETIME + bool 'Support one-time passwords' + default n + depends on RSBAC_UM=y + ---help--- + With this option you can add additional passwords to every user + account, which can only be used once. + +config RSBAC_UM_ONETIME_MAX + int 'Max number of one-time passwords per account' + default 100 + depends on RSBAC_UM_ONETIME=y + ---help--- + Set the number of one-time passwords, which can be set at + each account. + +config RSBAC_UM_VIRTUAL + bool 'Support virtual users' + default n + depends on RSBAC_UM=y + ---help--- + If enabled, RSBAC User Management supports virtual users, + which are organized in sets with 32 Bit ID numbers. ID 0 is + the main set. + +config RSBAC_UM_VIRTUAL_ISOLATE + bool 'Isolate virtual user sets' + default y + depends on RSBAC_UM_VIRTUAL=y + ---help--- + Select this option to ensure that users in virtual sets > 0 + never see users and groups in other virtual sets. + +config RSBAC_UM_NAME_CACHE + bool 'Cache name lookups to IDs' + default n + depends on RSBAC_UM=y + ---help--- + If enabled, RSBAC User Management will cache lookups of names + to user or group IDs, which are slow. + +config RSBAC_UM_NAME_CACHE_TTL + int 'TTL of name lookup cache items' + default 3600 + depends on RSBAC_UM_NAME_CACHE=y + ---help--- + Time to live of UM name lookup cache items in seconds. + Default is 3600. +endif + +if NET +menu 'RSBAC networking options' + depends on RSBAC + +config RSBAC_NET + bool 'RSBAC network support' + depends on NET + default y + ---help--- + The net support switch adds generic network device, network template + and network object attribute support. + + Also, general settings of IPv4 (INET) networks are controlled through + the SCD targets 'network' and 'firewall'. + + To get network device or object access control, you have to enable + the conditional switches below, as well as the individual model + switches for network access control. + +config RSBAC_NET_DEV + bool 'Net device control' + default y + depends on RSBAC_NET + ---help--- + With this option turned on, reading and modifying network device + settings, like binding addresses to devices etc., are controlled as + NETDEV targets. NETDEV objects are identified by their device name. + +config RSBAC_NET_DEV_VIRT + bool 'Treat virtual devices as individuals' + depends on RSBAC_NET_DEV + ---help--- + Turn this on, if you want to provide access control over virtual + devices independently from their base device. Due to the possible + number of virtual devices, be careful with this option. + +config RSBAC_IND_NETDEV_LOG + bool 'Individual network device logging' + default y + depends on RSBAC_NET_DEV + ---help--- + Enable individual log levels for every request type for network + devices. Log levels are none, denied requests, full, request based. + Default value is request based for all request types. + + If this option is off, only general log levels for requests are used + (same as individual logging for all objects set to request based). + +config RSBAC_NET_OBJ + bool 'Net object control (sockets)' + default y + depends on RSBAC_NET + depends on INET + ---help--- + This option enables access control for all socket based + communication, except the UNIX address family (controlled by extra + option). + + Access control is based on network object (NETOBJ) targets. Default + values for NETOBJ attributes are derived from the network template + (NETTEMP object), whose description matches this particular network + object. + + Matching is performed from lowest to highest template number. If no + template matches, general NETOBJ default values will be used. + NOTE: The behaviour in this case is model dependent! + + Socket system calls are matched to special request types with + matching names. + + NETTEMP objects themselves are protected as NETTEMP targets with + repective requests. + +config RSBAC_NET_OBJ_RW + bool 'Also intercept network object read and write' + depends on RSBAC_NET_OBJ + ---help--- + If on, READ and WRITE requests on sockets are also checked. + +config RSBAC_IND_NETOBJ_LOG + bool 'Individual network object logging' + default y + depends on RSBAC_NET_OBJ + ---help--- + Enable individual log levels for every request type for network + objects. + Log levels are none, denied requests, full, request based. + Default value is request based for all request types. + + For easier setup, the log levels are set on the network templates, + not the individual network objects. + + If this option is off, only general log levels for requests are used + (same as individual logging for all objects set to request based). +endmenu +endif + +menu 'Decision modules (policy) options' + depends on RSBAC + +config RSBAC_REG + bool 'Support for Registration of decision modules (REG)' + default y + ---help--- + If enabled, RSBAC supports runtime registering and unregistering of + additional decision module functions, e.g. from kernel modules. + + Possible functions are for decision, notification and file contents + overwrite decisions and for write-to-disk notifications. + + Additionally, syscall functions can be registered to the REG syscall + dispatcher. + + See , + and the module examples in + for details. + +config RSBAC_REG_SAMPLES + bool 'Build REG sample modules' + depends on RSBAC_REG && USB + ---help--- + Build the REG sample kernel modules. These modules show how to use + the RSBAC infrastructure, but do not perform any access control. + + The modules will be named reg_sample1, reg_sample2 and reg_sample3. + +menuconfig RSBAC_AUTH + bool 'AUTH policy support' + default y + ---help--- + This module can be seen as a support module for all others. It + restricts CHANGE_OWNER on process targets (setuid) for a process: the + request is only granted, if the process has either the + auth_may_setuid flag set or the target user ID is in its capability + set. + The auth_may_setuid flag and the capability set are inherited on + execute from the program file. + + Those file capabilities can be set, if all modules grant a + MODIFY_ATTRIBUTE request for A_auth_add_f_cap or A_auth_remove_f_cap. + Process capabilities can only be added by other processes that have + the auth_may_set_cap flag set, which is also inherited from the + executed file. + + This way an enforcement of daemon based authentification is possible, + as well as a restriction of system daemons to a set of user IDs. + + WARNING: If enabled without a login program having auth_may_setuid or + a capability set and without a capability setting daemon, + you will not be able to login to your system! + Use kernel parameter rsbac_auth_enable_login in emergencies + or at the first boot to set auth_may_setuid for /bin/login. + + Also see AUTH model description in + for details. + + If unsure, say Y. + +if RSBAC_AUTH +config RSBAC_AUTH_AUTH_PROT + bool 'AUTH module and attribute protection' + default y + ---help--- + Only, if this option is on, the AUTH module cares for its own + protection, otherwise it fully depends on other modules + (CONFIG_RSBAC_XX_AUTH_PROT). + This is meant for more sophisticated access control than a simple + system_role setting to security_officer. + + As a special effect, capability sets are cleared on every write + access to reduce system access after tampering. + + See AUTH model description for details. + +config RSBAC_AUTH_OTHER_PROT + bool 'Protect switching of other modules' + depends on RSBAC_SWITCH + ---help--- + This option makes AUTH care for the switching of other modules. + Useful if you want to prevent switching a module back on, + because it cannot protect itself in this case. + +config RSBAC_AUTH_UM_PROT + bool 'AUTH protection for User Management' + depends on RSBAC_UM + default y + ---help--- + This option makes AUTH care for User Management settings, e.g. + creation, change or deletion of users or groups. + + See User Management description for details. + +config RSBAC_AUTH_DAC_OWNER + bool 'AUTH support for effective and fs owner control' + ---help--- + If enabled, AUTH also controls the requests CHANGE_DAC_EFF_OWNER + (change process effective owner) and CHANGE_DAC_FS_OWNER (change + process filesystem owner) on process targets. Changes to these Linux + DAC (Discrete Access Control) model owner settings do not affect + RSBAC, so this option is off by default. + + This option also requires the 'Control DAC process owner (seteuid, + setfsuid)' option from the 'Other options', which enables the + requests mentioned above. + +config RSBAC_AUTH_ALLOW_SAME + bool 'Always allow setting to same id' + ---help--- + Normally, AUTH restricts all setuid and setgid calls, including those + to the same uid. Enabling this option allows these calls to be + unrestricted by the AUTH module if the same id is given. + +config RSBAC_AUTH_GROUP + bool 'AUTH support for Linux group control' + ---help--- + If enabled, AUTH also controls the request CHANGE_GROUP + (change process group) on process targets. Changes to these Linux + DAC (Discrete Access Control) model group settings do not affect + RSBAC, so this option is off by default. + +config RSBAC_AUTH_DAC_GROUP + bool 'AUTH support for effective and fs group control' + depends on RSBAC_AUTH_GROUP + ---help--- + If enabled, AUTH also controls the requests CHANGE_DAC_EFF_GROUP + (change process effective group) and CHANGE_DAC_FS_GROUP (change + process filesystem group) on process targets. Changes to these Linux + DAC (Discrete Access Control) model owner settings do not affect + RSBAC, so this option is off by default. + + This option also requires the 'Control DAC process group (setegid, + setfsgid)' option from the 'Other options', which enables the + requests mentioned above. + +config RSBAC_AUTH_LEARN + bool 'AUTH learning mode support' + ---help--- + If set, you can enable AUTH learning mode with the rsbac_auth_learn + kernel parameter. In learning mode, the AUTH module will automatically + add all missing auth capabilities. + + WARNING: This option is useful, but dangerous, so it should be off on + production systems. +config RSBAC_AUTH_LEARN_TA + int 'Learning mode transaction number' + default 0 + depends on RSBAC_AUTH_LEARN && RSBAC_LIST_TRANS + ---help--- + Put learned items into transaction with this number. The + transaction is created, if it does not exist. The default + value 0 means do not use transactions, all extra rights + get added immediately. + + Note: As the additional rights only appear in the transaction, + the same rights may seem to be added repeatedly, until + the transaction is committed. + Note: All transactions have a maximum lifetime, after which + all data is lost, unless you commit or refresh in time, + e.g. with the rsbac_list_ta command line tool. + Increase RSBAC_LIST_TRANS_MAX_TTL as desired. + +endif + +menuconfig RSBAC_RC + bool 'RC policy support' + default y + ---help--- + The Role Compatibility model is a powerful and flexible role based + model. It supports an unlimited number of roles and types. Types are + grouped per target type. Each role definition has compatibility + vectors for all types and other roles. + + Additionally, there are default create/chown/execute types and + several special values for inheritance options. + Roles can also be forced by executable file attributes, similar to + the setuid/setgid mechanism in Unix file systems. + + See for details. + + If unsure, say Y. + +if RSBAC_RC +config RSBAC_RC_AUTH_PROT + bool 'RC protection for AUTH module' + depends on RSBAC_AUTH + default y + ---help--- + This option makes RC care for AUTH module settings, e.g. attributes + auth_may_setuid, auth_may_set_cap and the kernel-only pseudo + attributes auth_add_f_cap, auth_remove_f_cap, auth_get_caplist. + + These settings are protected by SCD type compatibility with type + auth_administration, which is set for default role 1 (Role Admin). + + See AUTH model description for details. + +config RSBAC_RC_UM_PROT + bool 'RC protection for User Management' + depends on RSBAC_UM + default y + ---help--- + This option makes RC care for User Management settings, e.g. creation, + change or deletion of users or groups. + + See User Management description for details. + +config RSBAC_RC_GEN_PROT + bool 'RC protection for GENeral attributes' + default y + ---help--- + If on, RC protects general attributes (GEN module) like its own, e.g., + in default setup only Role Admins may change them. + +config RSBAC_RC_UDF_PROT + bool 'RC protection for UDF module' + depends on RSBAC_UDF + default n + ---help--- + This option makes RC care for UDF module settings, e.g. attributes + udf_role, udf_checker, udf_checked, udf_do_check, and + checker setting through proc interface. + + These settings are protected by SCD type compatibility with type + udf_administration. + + See UDF model description for details. + +config RSBAC_RC_BACKUP + bool 'Provide RC backup files' + depends on RSBAC_PROC + ---help--- + If enabled, RC provides its binary ACI data files in + /proc/rsbac-info/backup. + + Because of better backup options with admin tools, this is off by + default. + + If unsure, say N. + +config RSBAC_RC_NET_DEV_PROT + bool 'RC network device protection' + default y + depends on RSBAC_NET_DEV + ---help--- + If on, protect network devices based on RC NETDEV type + compatibilities. + +config RSBAC_RC_NET_OBJ_PROT + bool 'RC network object protection' + default y + depends on RSBAC_NET_OBJ + ---help--- + Turn this on to have real RC access control on network objects based + on RC type compatibilities. + + The NETOBJ default type values are derived from those of the matching + network template. + + Templates themselves are protected through their own template type + in attribute rc_type_nt and the nettemp type compatibility settings. + +config RSBAC_RC_NET_OBJ_UNIX_PROCESS + bool 'RC check access to UNIX partner process' + default n + ---help--- + This option enables additional checks for UNIX sockets: If a peer + process is known (via peer credential), the requesting process also + needs the same right as in the request to the RC type of the + other process. + + Affected request types are CONNECT, ACCEPT, SEND and RECEIVE. If + READ and WRITE checking of network sockets is enabled, these request + types are checked as RECEIVE and SEND to avoid possible confusion + about read and write accesses to processes. + +config RSBAC_RC_LEARN + bool 'Enable learning mode for missing role rights to types' + depends on RSBAC_DEBUG + ---help--- + This option allows to enable a learning mode per global switch. + In learning mode, missing role rights to types will be added + automatically. However, it will never add new roles or types + even when this would be a much better solution. + Enable temporarily for all roles with the rsbac_rc_learn + kernel parameter or temporarily at runtime via proc interface. + + Please check + for more info about how the RC model works. + +config RSBAC_RC_LEARN_TA + int 'Learning mode transaction number' + default 0 + depends on RSBAC_RC_LEARN && RSBAC_LIST_TRANS + ---help--- + Put learned items into transaction with this number. The + transaction is created, if it does not exist. The default + value 0 means do not use transactions, all extra rights + get added immediately. + + Note: As the additional rights only appear in the transaction, + the same rights may seem to be added repeatedly, until + the transaction is committed. + Note: All transactions have a maximum lifetime, after which + all data is lost, unless you commit or refresh in time, + e.g. with the rsbac_list_ta command line tool. + Increase RSBAC_LIST_TRANS_MAX_TTL as desired. + +config RSBAC_RC_KERNEL_PROCESS_TYPE + int 'RC kernel process type' + default 999999 + ---help--- + This is the type being assigned to all kernel processes, despite the + initiating process owner role's def_process_create_type. + + The default value is 999999. It should only be changed, if you have + role number conflicts with your existing configuration. +endif + +menuconfig RSBAC_ACL + bool 'ACL policy support' + default y + ---help--- + This turns on the Access Control List module. ACLs are kept on all + targets but those of type USER. For the IPC and PROCESS targets + there is only one default ACL each. + + Each ACL entry contains subject type (user, rc_role, acl_group), + subject id and the rights this subject has. Also, rights are inherited + from parents and from a target specific default ACL. + + Most settings have a time-to-live (TTL) option, which automatically + removes them after a certain amount of time. + + See for details. + +if RSBAC_ACL +config RSBAC_ACL_SUPER_FILTER + bool 'Allow masking out of SUPERVISOR right' + ---help--- + Normally, inheritance masks can never filter out the SUPERVISOR right + (which contains all other rights) - it is always inherited. + + If this switch is on, SUPERVISOR *can* be filtered out. This allows + separation of duties and privacy, but is also dangerous, because + administration can easily become impossible. In this case, you have to + reboot into a maintenance kernel to regain access. + + For safety reasons, you must have a USER ACL entry at the target + containing the SUPERVISOR right to set a new mask without SUPERVISOR. + +config RSBAC_ACL_AUTH_PROT + bool 'ACL protection for AUTH module' + depends on RSBAC_AUTH + default y + ---help--- + This option makes ACL care for AUTH module settings, e.g. attributes + auth_may_setuid, auth_may_set_cap and the kernel-only pseudo + attributes auth_add_f_cap, auth_remove_f_cap, auth_get_caplist. Those + settings are protected by SCD 'auth_administration' ACL. + + See AUTH model description for AUTH details. + +config RSBAC_ACL_UM_PROT + bool 'ACL protection for User Management' + depends on RSBAC_UM + default y + ---help--- + This option makes ACL care for User Management settings, e.g. + creation, change or deletion of users or groups. + + See User Management description for details. + +config RSBAC_ACL_GEN_PROT + bool 'ACL protection for GENeral attributes' + default y + ---help--- + If on, ACL protects general attributes (GEN module) through + the MODIFY_ATTRIBUTE right. + In default setup, only user 400 may change them. + +config RSBAC_ACL_UDF_PROT + bool 'ACL protection for UDF module' + depends on RSBAC_UDF + default n + ---help--- + This option makes ACL care for UDF module settings, e.g. attributes + udf_role, udf_checker, udf_checked, udf_do_check, and + checker setting through proc interface. + These settings are protected by SCD 'udf_administration' ACL. + + See UDF model description for UDF details. + +config RSBAC_ACL_BACKUP + bool 'Provide ACL backup files' + depends on RSBAC_PROC + ---help--- + If on, ACL provides its binary group and group membership data files + in /proc/rsbac-info/backup. + +config RSBAC_ACL_LEARN + bool 'ACL learning mode support' + ---help--- + If enabled, you can enable ACL learning mode with rsbac_acl_learn or + rsbac_acl_learn_fd kernel parameter. In learning mode, ACL module will + automatically add all missing acl entries for filesystem objects. + + WARNING: This option is useful, but dangerous, so it should be off on + production systems. + +config RSBAC_ACL_LEARN_TA + int 'Learning mode transaction number' + default 0 + depends on RSBAC_ACL_LEARN && RSBAC_LIST_TRANS + ---help--- + Put learned items into transaction with this number. The + transaction is created, if it does not exist. The default + value 0 means do not use transactions, all extra rights + get added immediately. + + Note: As the additional rights only appear in the transaction, + the same rights may seem to be added repeatedly, until + the transaction is committed. + Note: All transactions have a maximum lifetime, after which + all data is lost, unless you commit or refresh in time, + e.g. with the rsbac_list_ta command line tool. + Increase RSBAC_LIST_TRANS_MAX_TTL as desired. + +config RSBAC_ACL_NET_DEV_PROT + bool 'ACL network device protection' + default y + depends on RSBAC_NET_DEV + ---help--- + If on, protect network devices based on individual and default ACLs. + +config RSBAC_ACL_NET_OBJ_PROT + bool 'ACL network object protection' + default y + depends on RSBAC_NET_OBJ + ---help--- + Turn this on to have real ACL access control on network objects based + on inherited ACLs. + + When determining a subject's right to a network object (NETOBJ), the + following inheritance scheme is used: + - If there is an ACL entry at the NETOBJ itself, use it, else + - If there is an ACL entry at the matching template, use that, but + filter through individual mask, else + - If there is an ACL entry in the NETOBJ default ACL, use that, but + filter through individual mask and matching template's mask. + + Certainly, user, role and group rights are accumulated as usual. + + Templates themselves are protected through their own individual and + default ACLs, which are configured using the NETTEMP_NT target. +endif + +menuconfig RSBAC_MAC + bool 'MAC policy support' + ---help--- + Mandatory Access Control follows the Bell-LaPadula security model, + in which all users and resources are classified in levels of + confidentiality. Additionally, each subject and object has a set out + of 64 categories. + + To read from a resource, a user's level must be at least as high as + that of the resource, and the user's category set must be a superset + of the category set of the resource. + To write to a resource, it must be at least as confidential as the + user, and its category set must be a superset of the user's. + + See for details. + +if RSBAC_MAC +config RSBAC_MAC_DEF_INHERIT + bool 'MAC inherit as default' + default y + ---help--- + If enabled, the inheritable attributes security_level and + mac_categories for files, fifos and directories get the default value + 'inherit' instead of the old style real value. This reduces the amount + of attributes to be set significantly, because files, fifos and dirs + inherit their parent dir's attribute values automatically. Inheritance + ends at root dir /. + + This setting should be kept constant between different RSBAC kernels + in use to avoid confusion for administrators/security officers, + rsbac_check() and backup. + + Please note that inheritance is not conforming to the Bell-LaPadula + model, where all objects must be individually labeled. + +config RSBAC_MAC_SMART_INHERIT + bool 'Smart inherit' + default y + depends on RSBAC_MAC_DEF_INHERIT + ---help--- + If enabled, the MAC model checks whether the values of attributes + security_level and mac_categories for new objects would already be in + effect via inheritance. Only if the inherited value differs, the new + values are set explicitely. Otherwise the default value 'inherit' is + automatically applied. + + This option largely reduces the amount of new attribute objects needed + for whole created directory trees with same values. It thus saves + memory and CPU cycles. + + However, inheritance is not conforming to the Bell-LaPadula model, + where all objects must be individually labeled - here we are even + denying explicit labeling of new objects. Use with care. + +config RSBAC_MAC_AUTH_PROT + depends on RSBAC_AUTH + bool 'MAC protection for AUTH module' + ---help--- + This option makes MAC care for AUTH module settings, e.g. attributes + auth_may_setuid, auth_may_set_cap and the kernel-only pseudo + attributes auth_add_f_cap, auth_remove_f_cap, auth_get_caplist. These + settings are treated like MAC settings. + + See AUTH model description for details. + +config RSBAC_MAC_UM_PROT + bool 'MAC protection for User Management' + depends on RSBAC_UM + default y + ---help--- + This option makes MAC care for User Management settings, e.g. + creation, change or deletion of users or groups. + + See User Management description for details. + +config RSBAC_MAC_GEN_PROT + bool 'MAC protection for GENeral attributes' + ---help--- + If on, MAC protects general attributes (GEN module) like its own, + i.e., only security officers may change them. + +config RSBAC_MAC_LIGHT + bool 'Light MAC edition' + ---help--- + This option makes MAC easier to use, but a bit less conforming to the + Bell-LaPadula model. + 1. Allow R_CREATE of new files WITHOUT any checking. This way, higher + level objects can be created in a lower level directory. + 2. Allow R_MOUNT and R_UMOUNT to ANY user (only Administrator in base + MAC version). + +config RSBAC_MAC_TRUSTED_READ + bool 'Give trusted processes full read access' + ---help--- + Normally, a mac_trusted process may only violate *-property, i.e., it + may write to any level within its owner's level range from + min_security_level to security_level, regardless of its current level + and the max_read boundary. This makes a user's trusted flag equivalent + to the combination of write_up and write_down flag. + + With this option turned on, a trusted process may also read from any + such level despite its current level and the min_write boundary. This + adds the meaning of the read_up flag to the trusted flag. + + Please note that the mac_auto privilege with automatic current level + and read/write boundary adjustment as well as the object mac_shared + flag are always tried before trusted, write_up, write_down and + read_up. + +config RSBAC_MAC_RESET_CURR + bool 'Reset current level on each execute' + ---help--- + If enabled, the current process level is reset to the user's initial + level on every execute. + +config RSBAC_MAC_LOG_LEVEL_CHANGE + bool 'Log all automatic changes to current level' + default y + ---help--- + If both the effective mac_auto flag at an executable and the + mac_allow_auto flag at the user executing it are set, current levels + may be automatically adjusted to allow access, where it would + otherwise be denied. + + This option logs each such automatic change to the process current + level, because it means a change to the current access rights. + +config RSBAC_MAC_NET_DEV_PROT + bool 'MAC network device protection' + depends on RSBAC_NET_DEV + ---help--- + If enabled, The MAC module protects network devices in that only + System Administrators may configure them. + +config RSBAC_MAC_NET_OBJ_PROT + bool 'MAC network object protection' + depends on RSBAC_NET_OBJ + ---help--- + Turn this on to have real MAC access control on network objects based + on security levels and categories. + + The default attribute values are derived from those of the matching + network template. + +endif + +menuconfig RSBAC_PAX + bool 'PAX policy support' + default y + depends on PAX + ---help--- + The PAX module allows to administrate the PaX flags of programs and + processes. To have these flags enforced, you need to enable + "direct" MAC integration in the PaX control menu under the security + menu (CONFIG_PAX_NO_ACL_FLAGS). + + PaX is a separate Linux kernel patch available at + . + Please have a look at the homepage to get some more information. + +if RSBAC_PAX +config RSBAC_PAX_DEFAULT + bool 'Change PAX default flags (PeMRxS)' + help + This option allows to change the PaX default flags for all files from + PeMRxS to any other value. + Please be careful, if you change this setting, specially with existing + configurations - unexpected failures of previously running programs + might happen. Nothing you could not fix by reconfiguration, though. + +config RSBAC_PAX_PAGEEXEC + bool 'PAX Default P: Enable paging based non-exec pages' + depends on RSBAC_PAX_DEFAULT + default y + +config RSBAC_PAX_EMUTRAMP + bool 'PAX Default E: Emulate Trampolines' + depends on RSBAC_PAX_DEFAULT + +config RSBAC_PAX_MPROTECT + bool 'PAX Default M: Restrict mprotect' + depends on RSBAC_PAX_DEFAULT + default y + +config RSBAC_PAX_RANDMMAP + bool 'PAX Default R: Randomize mmap() base' + depends on RSBAC_PAX_DEFAULT + default y + +config RSBAC_PAX_RANDEXEC + bool 'PAX Default X: Randomize ET_EXEC base' + depends on RSBAC_PAX_DEFAULT + +config RSBAC_PAX_SEGMEXEC + bool 'PAX Default S: Segmentation based non-exec pages' + depends on RSBAC_PAX_DEFAULT + default y +endif + +menuconfig RSBAC_DAZ + bool 'DAZuko policy support' + ---help--- + The Dazuko policy provides the Dazuko malware scanning interface. + Scanning results may optionally be cached, see CONFIG_RSBAC_DAZ_CACHE + below. + + Only programs marked as scanners may connect to the Dazuko interface, + and only DAZ security administrators are allowed to modify daz_scanner + or daz_scanned. + +if RSBAC_DAZ +config RSBAC_DAZ_SELECT + bool 'Let scanners subselect paths' + default y + ---help--- + Through Dazuko interface, scanners can define a set of paths + they are interested in. Without this option, RSBAC will ignore + these paths for the sake of speed and full mandatory control. + + Please note that with RSBAC the daz_do_scan attribute on FD + objects controls which paths get scanned or not. The scanner + selection only reduces the set of paths, never increases. + + In previous RSBAC versions, subselection by scanners was + always on. It now defaults to on, will be off in next RSBAC + version. + +config RSBAC_DAZ_CACHE + bool 'Cache scanning results' + default y + ---help--- + With this option, all scanning results get cached for the time + specified below. + +config RSBAC_DAZ_TTL + int 'Scanning result lifetime in seconds' + default 86400 + depends on RSBAC_DAZ_CACHE + ---help--- + Specify the time in seconds a scanning result is kept. After this time + the object will be rescanned on the next access. + + Use 0 for unlimited, default is 86400 (1 day). Set to 1 to force a + fast rescan. + +config RSBAC_DAZ_PERSIST + bool 'Keep scanning results over reboot' + depends on RSBAC_DAZ_CACHE + ---help--- + If on, file scanning results, which are younger than their life time + limit, are kept persistently during reboots. + + Using this option can reduce the amount of scanning, but it cannot + protect against file modifications while another kernel is booted. + +config RSBAC_DAZ_DEV_MAJOR + int 'Dazuko device major number' + default 250 + ---help--- + Specify the major char device number for /dev/dazuko, + which is used for scanner registration and communication. + + Use 0 to let the system pick one. +endif + +menuconfig RSBAC_CAP + bool 'CAP (Linux CAP) policy support' + default y + ---help--- + The Linux Capability (CAP) module allows to set minimum and maximum + Linux capability sets for single users and programs. These boundaries + are applied at CHANGE_OWNER on processes (setuid) and EXECUTE. + + Minimum settings have precedence over maximums, and program settings + have precedence over user settings. + + Use this module to run programs that need root privileges from normal + user accounts, e.g. file server daemons, or to restrict programs run + by root, e.g. certain mail daemons. + + If softmode is enabled and turned on, only the minimum sets are + applied. + + +if RSBAC_CAP +config RSBAC_CAP_PROC_HIDE + bool 'Support CAP process hiding' + default y + ---help--- + If enabled, you can hide the process properties shown in /proc from + other users, e.g. command line and current state. The hiding level is + set with the cap_process_hiding process attribute. There are three + possible values: + 0 / off: no hiding. + 1 / from other users: only processes running for the same user, a CAP + security officer or a CAP system admin may read the properties. + 2 / full: only this process and CAP security officers may read the + properties. + + The kernel command line switch rsbac_cap_process_hiding changes the + default value from 0 to 1. Thus, every normal user can only see her + own process properties. + +config RSBAC_CAP_AUTH_PROT + depends on RSBAC_AUTH + bool 'CAP protection for AUTH module' + ---help--- + This option makes CAP care for AUTH module settings, e.g. attributes + auth_may_setuid, auth_may_set_cap and the kernel-only pseudo + attributes auth_add_f_cap, auth_remove_f_cap, auth_get_caplist. Those + settings are protected by the cap_roles admin (read) and security + officer (rw). + + See AUTH model description for AUTH details. + +config RSBAC_CAP_LOG_MISSING + bool 'Log missing capabilities in capable()' + ---help--- + If checked, the Linux capability check function capable() can log + all queries for capabilities, which are missing from the effective + set. Enable with the rsbac_cap_log_missing kernel parameter, or at + runtime via proc interface. + The only exception is CAP_SYS_ADMIN, which fails much too often + and thus never gets logged. + + Background: If you limit Linux capabilities for users or programs + with the CAP module, some programs fail in secure mode without + "NOT_GRANTED" RSBAC log messages, because this Linux internal check + failed. + + Please check + for more info about how the CAP module works. + +config RSBAC_CAP_LEARN + bool 'Learn missing capabilities in capable()' + ---help--- + If checked, the Linux capability check function capable() will + set all capabilities in the max_caps set of user or program, + which are missing from the current process effective set because + of RSBAC max_caps restrictions. + Enable with the rsbac_cap_learn kernel parameter or at runtime + via proc interface. + Warning: In learning mode, a program with reduced max_caps might + temporarily get more effective caps assigned than granted by + standard kernel! + + Background: If you limit Linux capabilities for users or programs + with the CAP module, some programs fail in secure mode without + "NOT_GRANTED" RSBAC log messages, because this Linux internal check + failed. + + Please check + for more info about how the CAP module works. + +config RSBAC_CAP_LEARN_TA + int 'Learning mode transaction number' + default 0 + depends on RSBAC_CAP_LEARN && RSBAC_LIST_TRANS + ---help--- + Put learned items into transaction with this number. The + transaction is created, if it does not exist. The default + value 0 means do not use transactions, all extra rights + get added immediately. + + Note: As the additional rights only appear in the transaction, + the same rights may seem to be added repeatedly, until + the transaction is committed. + Note: All transactions have a maximum lifetime, after which + all data is lost, unless you commit or refresh in time, + e.g. with the rsbac_list_ta command line tool. + Increase RSBAC_LIST_TRANS_MAX_TTL as desired. +endif + +menuconfig RSBAC_JAIL + bool 'JAIL policy support' + default y + ---help--- + The JAIL module gives you an extended chroot facility, similar to + FreeBSD Jails. To put a process into a jail, start it with the + rsbac_jail wrapper or make it call the sys_rsbac_jail syscall + directly. + + With RSBAC network object support, jailed processes can only use a + designated IP address (if designated address is not 0.0.0.0), and + UNIX or INET sockets of type STREAM, DGRAM or RDM. All other families + and types, e.g. RAW network access, are generally prohibited. + + From within a jail, only processes and IPC objects of the same jail + can be accessed. Jails can be created from within jails, but get + limited to the parent jail's filesystem root, IP and flags. + + Additionally, most kernel based administration tasks are forbidden, + e.g. creating device special files, setting network addresses, + getting or setting RSBAC attributes, changing system settings like + name or rlimits etc. + + Several sys_rsbac_jail flags change the jail behaviour: + - allow_external_ipc: allow to access IPC objects outside this jail + - allow_rlimit: allow to change rlimit + - allow_all_net_family: allow to use all network families, not only + UNIX and INET (IPv4) + - allow_inet_raw: allow to use RAW INET sockets, e.g. for ping + - auto_adjust_inet_any: also allow to bind to INET ANY address + (0.0.0.0), but always change it to specified address + (requires CONFIG_RSBAC_JAIL_NET_ADJUST) + +if RSBAC_JAIL +config RSBAC_JAIL_NET_ADJUST + bool 'JAIL allow to auto-adjust INET ANY (0.0.0.0) address' + default y + depends on RSBAC_NET_OBJ + ---help--- + Turn this option on to allow automatic adjusting of the INET ANY + address 0.0.0.0 to the specified address with the + auto_adjust_inet_any syscall flag. + +config RSBAC_JAIL_NET_DEV_PROT + bool 'JAIL network device protection' + default y + depends on RSBAC_NET_DEV + ---help--- + Only with this option enabled can the JAIL module prevent network + device configuration from within a jail. Recommended. + +config RSBAC_JAIL_LOG_MISSING + bool 'Log missing capabilities in capable()' + ---help--- + If checked, the Linux capability check function capable() can log + all queries for capabilities, which are missing from the effective + set. Enable with the rsbac_jail_log_missing kernel parameter, or at + runtime via proc interface. + + Background: If you limit Linux capabilities for users or programs + within a JAIL, some programs fail in secure mode without + "NOT_GRANTED" RSBAC log messages, because this Linux internal check + failed. + + Please check + + for more info about how the JAIL module works. +endif + +config RSBAC_RES + bool 'RES (System Resources) policy support' + default y + ---help--- + The Linux Resources (RES) module allows to set minimum and maximum + Linux resource sets for single users and programs. These boundaries + are applied at CHANGE_OWNER on processes (setuid) and EXECUTE. + + Minimum settings have precedence over maximums, and program settings + have precedence over user settings. + + Default values for all users can be set at user RSBAC_ALL_USER with + uid 4294967292 ((rsbac_uid_t) -4). + + If softmode is enabled and turned on, only the minimum sets are + applied. + +menuconfig RSBAC_FF + bool 'FF policy support' + default y + ---help--- + The File Flag module adds some flags for files and dirs to the + system. Current flags are: + + execute_only (files): Only request EXECUTE is granted + + read_only (files and dirs): Only non-modifying requests are granted + + search_only (dirs): All file/subdir accesses need full path, no + listing or modification of dir is granted. + + write_only (files): Only writing requests are granted, useful for + logging etc. Specially good if inherited to new files from a dir. + + no_execute (files): No execution of this file allowed. + + add_inherited (files and dirs): Add (or) flags of parent dir to own + flags. This last flag makes the file flags powerful: simply set + a file flag for a dir (e.g. no_execute on /home), and the whole + subtree is affected. + + no_rename_or_delete (files and dirs, not inherited): Prevents renaming + or deleting an object, e.g to keep a directory structure fixed. + + append_only (files): the only write access allowed is APPEND_OPEN. + Good for log files. + +if RSBAC_FF +config RSBAC_FF_AUTH_PROT + depends on RSBAC_AUTH + bool 'FF protection for AUTH module' + ---help--- + This option makes FF care for AUTH module settings, e.g. attributes + auth_may_setuid, auth_may_set_cap and the kernel-only pseudo + attributes auth_add_f_cap, auth_remove_f_cap, auth_get_caplist. Those + settings are treated like FF settings. + + See AUTH model description for details. + +config RSBAC_FF_UM_PROT + bool 'FF protection for User Management' + depends on RSBAC_UM + default y + ---help--- + This option makes FF care for User Management settings, e.g. creation, + change or deletion of users or groups. + + See User Management description for details. + +config RSBAC_FF_GEN_PROT + bool 'FF protection for GENeral attributes' + ---help--- + If on, FF protects general attributes (GEN module) like its own, i.e., + only security officers may change them. +endif + +menuconfig RSBAC_UDF + bool 'UDF policy support' + ---help--- + User Space Decision Facility (UDF) allows to register a user + space program (checker) through RSBAC proc interface or kernel + parameter rsbac_udf_checker=/path/to/prog to be called for + decisions, e.g. a virus scanner wrapper. + The request types leading to a check are listed in + include/rsbac/adf_main.h in the macro RSBAC_UDF_REQUEST_VECTOR. + Checking results may optionally be cached, see + CONFIG_RSBAC_UDF_CACHE below. + + To avoid loops, the checker program should be marked as + udf_checker to bypass checking for this program. + Only UDF security administrators are allowed to modify udf_checker + or udf_checked. + + The checker program has to exit with 0 for "allow", 1 for "deny", + 254 for "temporary failure, allow" (do not cache) or 255 for + "temporary failure, deny" (do not cache). Any other exit code is + undefined, but for now treated as "deny". If the checker got + killed by a signal, it is treated as "temporary failure, deny". + + Please note that the checker is started as user mode process, + but with attributes inherited from kernel context. E.g. its RC + role is the kernel role, explicitly set a force role for the + checker to have different rights. + +if RSBAC_UDF +config RSBAC_UDF_CACHE + bool 'Cache checking results' + default y + ---help--- + With this option, all checking results get cached for the time + specified below. Cache entries get removed immediately on every + write access to the file. + +config RSBAC_UDF_TTL + int 'Checking result lifetime in seconds' + default 86400 + depends on RSBAC_UDF_CACHE + ---help--- + Specify the time in seconds a checking result is kept. After this time + the object will be rechecked on the next access. + + Use 0 for unlimited, default is 86400 (1 day). Set to 1 to force a + fast recheck. + +config RSBAC_UDF_PERSIST + bool 'Keep checking results over reboot' + depends on RSBAC_UDF_CACHE + ---help--- + If on, file checking results, which are younger than their life time + limit, are kept persistently during reboots. + + Using this option can reduce the amount of checking, but it cannot + protect against file modifications while another kernel is booted. + +config RSBAC_UDF_ON_CLOSE + bool 'Check after closing written file' + default n + depends on RSBAC_UDF_CACHE + ---help--- + Enable this to check a file after close, if it has been opened + for writing. This fills the cache so that there is no delay at + the next read open or execute, but it delays the close. + +config RSBAC_UDF_UDF_PROT + bool 'UDF module and attribute protection' + default y + ---help--- + Only, if this option is on, the UDF module cares for its own + protection, otherwise it fully depends on other modules + (CONFIG_RSBAC_XX_UDF_PROT). + This is meant for more sophisticated access control than a simple + system_role setting to security_officer. + + See UDF model description for details. + +endif + +endmenu +# Policies + + +menu 'Softmode and switching' + depends on RSBAC + +config RSBAC_SOFTMODE + default y + bool 'RSBAC soft mode' + ---help--- + This option enables RSBAC softmode support. In softmode, all + decisions and logging are performed, but the result that is returned + to enforcement is always DO_NOT_CARE. This means that access control + is effectively off! + + Single exception: even in softmode, all access to rsbac attribute dirs + is always NOT_GRANTED. + + After boot, softmode will be off, unless kernel parameter + 'rsbac_softmode' has been given. It can be turned on via proc + interface with + + echo debug softmode > /proc/rsbac-info/debug, + + where is 1 (on) or 0 (off). + If policy switching is enabled, you can also use sys_rsbac_switch, + e.g. via switch_module command line tool. + + Switching softmode on or off is access controlled with an ADF request + SWITCH_MODULE for module SOFTMODE. The RSBAC builtin modules only + allow softmode under the same conditions as switching themselves off. + + WARNING: For security reasons, this option should only be used for + debugging of your RSBAC administration settings! + + Additionally, you might get strange effects during the notification + call rsbac_adf_set_attr(), because the request should not have been + granted in the first place. Unexpected access decisions might occur, + because attributes might have misleading values! + +config RSBAC_SOFTMODE_SYSRQ + bool 'Toggle soft mode with SysRq-X' + depends on RSBAC_SOFTMODE + ---help--- + If this setting and kernel SysRq are enabled, you can toggle softmode + with SysRq-X (char can be changed in rsbac/debug.h). + This makes debugging of your RSBAC administration settings much + easier. + + WARNING: This is dangerous, because everyone with physical access to + your keyboard can effectively turn off access control! + + Do not use in production systems! + + If unsure, say N. + +config RSBAC_SOFTMODE_IND + bool 'Individual module softmode support' + default y + depends on RSBAC_SOFTMODE + ---help--- + If on, you can toggle softmode individually for each module. + Softmode for a module can be switched via proc interface with + + echo debug ind_softmode > /proc/rsbac-info/debug + + where is the module short name in capitals, e.g. RC, and + is 1 (on) or 0 (off). + If policy switching is enabled, you can also use sys_rsbac_switch, + e.g. via switch_module command line tool. + +config RSBAC_SWITCH + default y + bool 'RSBAC policies switchable' + ---help--- + If enabled, the configured policies can be switched on or off by + syscall sys_rsbac_switch(). + + Of course, switching modules off is performed under their own control. + + Warning: Though switching off is access controlled itself, any way to + switch off access control is always dangerous! + +config RSBAC_SWITCH_ON + bool 'Allow to switch stateful modules back on' + depends on RSBAC_SWITCH + ---help--- + Some modules must be active all the time to keep their state intact, + e.g. to have correct process roles or security levels. This means + that after turning such a module off, it is in an inconsistent state + and can block the whole system when turned back on. Most prominent + examples are RC and MAC. Some modules only loose part of their + ability to protect the system, e.g. JAIL does not jail new processes. + + By default, modules that can block the system may never be turned on, + only off. Enable this switch to be able to turn them back on - you + have been warned! + +config RSBAC_SWITCH_BOOT_OFF + bool 'Allow to switch modules off with kernel parameter' + depends on RSBAC_SWITCH + ---help--- + Enable this to allow switching modules off by kernel parameter + rsbac_switch_off_xyz with xyz = module name in small letters, + e.g. rc or auth. Module needs to be set switchable below. + +config RSBAC_SWITCH_REG + default y + bool 'Switch REG modules' + depends on RSBAC_SWITCH && RSBAC_REG + ---help--- + Select to switch REG modules on and off at runtime. + +config RSBAC_SWITCH_AUTH + bool 'Switch AUTH policy' + depends on RSBAC_SWITCH && RSBAC_AUTH + ---help--- + Select to switch AUTH module on and off at runtime. + +config RSBAC_SWITCH_RC + bool 'Switch RC policy' + depends on RSBAC_SWITCH && RSBAC_RC + ---help--- + Select to switch RC module on and off at runtime. + +config RSBAC_SWITCH_ACL + bool 'Switch ACL policy' + depends on RSBAC_SWITCH && RSBAC_ACL + ---help--- + Select to switch ACL module on and off at runtime. + +config RSBAC_SWITCH_MAC + bool 'Switch MAC policy' + depends on RSBAC_SWITCH && RSBAC_MAC + ---help--- + Select to switch MAC module on and off at runtime. + +config RSBAC_SWITCH_PAX + bool 'Switch PAX policy' + depends on RSBAC_SWITCH && RSBAC_PAX + ---help--- + Select to switch PAX module on and off at runtime. + +config RSBAC_SWITCH_DAZ + bool 'Switch DAZ policy' + depends on RSBAC_SWITCH && RSBAC_DAZ + ---help--- + Select to switch DAZ module on and off at runtime. + +config RSBAC_SWITCH_CAP + bool 'Switch CAP policy' + depends on RSBAC_SWITCH && RSBAC_CAP + ---help--- + Select to switch CAP module on and off at runtime. + +config RSBAC_SWITCH_JAIL + bool 'Switch JAIL policy' + depends on RSBAC_SWITCH && RSBAC_JAIL + ---help--- + Select to switch JAIL module on and off at runtime. + +config RSBAC_SWITCH_RES + bool 'Switch RES policy' + depends on RSBAC_SWITCH && RSBAC_RES + ---help--- + Select to switch RES module on and off at runtime. + +config RSBAC_SWITCH_FF + bool 'Switch FF policy' + depends on RSBAC_SWITCH && RSBAC_FF + ---help--- + Select to switch FF module on and off at runtime. + +config RSBAC_SWITCH_UDF + bool 'Switch UDF policy' + depends on RSBAC_SWITCH && RSBAC_UDF + ---help--- + Select to switch UDF module on and off at runtime. + +config RSBAC_SWITCH_MPROTECT + bool 'Switch memory write and execute protection' + depends on RSBAC_SWITCH && RSBAC_MPROTECT + ---help--- + Select to switch memory write and execute protection + on and off at runtime. +endmenu + +menu 'Logging' + depends on RSBAC + +config RSBAC_IND_LOG + bool 'Individual file/dir/dev object logging' + default y + ---help--- + Enable individual log levels for every request type for every file, + dir and device. Log levels are none, denied requests, full, request + based. Default value is request based for all request types. + + If this option is off, only general log levels for requests are used + (same as individual logging for all objects set to request based). + +config RSBAC_IND_USER_LOG + bool 'Individual user logging' + default y + ---help--- + When enabled, you can specify for every single user, which request + type(s) will always be logged. + +config RSBAC_IND_PROG_LOG + bool 'Individual program logging' + default y + ---help--- + When enabled, you can specify for every single program file, which + request type(s) will always be logged. + +config RSBAC_LOG_PROGRAM_FILE + bool 'Log program file' + default y + ---help--- + Enable this option to get the full program file path logged together + with the process name. + +config RSBAC_LOG_FULL_PATH + bool 'Log full path' + default y + ---help--- + If this is turned on, logging messages for file and dir targets will + contain the full path. This makes the log significantly longer and + takes some extra CPU time, but also increases log usability. + +config RSBAC_MAX_PATH_LEN + int 'Maximum path length (256 - 2000)' + default 512 + depends on RSBAC_LOG_FULL_PATH + ---help--- + If the full path is longer than CONFIG_RSBAC_MAX_PATH_LEN, the + leading dirnames will be left out until it fits. The bigger this + value, the more memory will be allocated in the logging routine. + +config RSBAC_LOG_PSEUDO + bool 'Pseudonymous logging support' + default n + ---help--- + Enable to get pseudo values for users honoured in all request logging + entries. If a pseudo value is not 0, it is logged instead of the uid. + +config RSBAC_LOG_PSEUDO_FS + bool 'Pseudonymize filesystem objects' + default n + depends on RSBAC_LOG_PSEUDO + ---help--- + If enabled, the logging code exchanges filesystem object names with + their owner's pseudo, if the pseudo value is not 0 and the parent + object has another owner. + +config RSBAC_SYSLOG_RATE + bool 'Syslog rate limit' + default y + ---help--- + Enable the limiting of the number of log message lines sent to syslog + per second. + +config RSBAC_SYSLOG_RATE_DEF + int 'Default allowed message lines per second' + depends on RSBAC_SYSLOG_RATE + default 1000 + ---help--- + Number of allowed syslog message lines per second. This value can be + changed with kernel parameter rsbac_syslog_rate= or at runtime via + the proc interface. + + Default value is 1000. + +config RSBAC_RMSG + bool 'RSBAC own logging facility' + default y + ---help--- + Add logging of requests with extra facility, which is basically a + clone of printk/sys_syslog. If proc is supported, a file rmsg appears + in rsbac-info and can be used like kmsg, e.g. with a patched klogd, + cat or tail -f. + This file is protected by RSBAC with object type SCD/rsbac_log. + A new syscall sys_rsbac_log, similar to sys_syslog, also gives access + to logging stuff. + +config RSBAC_RMSG_MAXENTRIES + int 'Maximum number of messages in the log buffer' + depends on RSBAC_RMSG + default 200 + ---help--- + Number of allowed messages in the RSBAC log buffer. Each message + takes from 32 to 2048 bytes of memory. + + Default value is 200. + +config RSBAC_RMSG_NOSYSLOG + bool 'Allow to disable logging to syslog' + default y + depends on RSBAC_RMSG + ---help--- + When on, you can temporarily disable logging to syslog with kernel + parameter rsbac_nosyslog or via /proc/rsbac-info/debug. Useful for + initial configuration on system installation or if you need a clean + separation. + + If unsure, say Y. + +config RSBAC_LOG_REMOTE + bool 'Log to remote UDP network socket' + depends on RSBAC_RMSG + ---help--- + If enabled, copies of every message in the RSBAC log facility will be + sent to a remote system over network. + +if RSBAC_LOG_REMOTE=y + +config RSBAC_LOG_REMOTE_TCP + bool 'Use TCP for remote logging' + depends on RSBAC_RMSG + ---help--- + If enabled, use more reliable TCP protocol to transfer logs. + +config RSBAC_LOG_REMOTE_MAXENTRIES + int 'Maximum number of messages in the remote log buffer' + depends on RSBAC_RMSG + default 200 + ---help--- + Number of allowed messages in the RSBAC remote log buffer. Each + message takes from 32 to 2048 bytes of memory. + + Default value is 200. + +#config RSBAC_LOG_REMOTE_SYNC +# bool 'Immediate remote logging' + +config RSBAC_LOG_INTERVAL + int 'Logging interval in timer ticks' + default 100 +# depends on RSBAC_LOG_REMOTE_SYNC=n + +config RSBAC_LOG_LOCAL_ADDR + string 'Local UDP address' + default "0.0.0.0" + +config RSBAC_LOG_LOCAL_PORT + int 'Local UDP port' + default 0 + +config RSBAC_LOG_REMOTE_ADDR + string 'Remote UDP address' + default "0.0.0.0" + +config RSBAC_LOG_REMOTE_PORT + int 'Remote UDP port' + default 514 + +endif + +endmenu + +config RSBAC_SYM_REDIR + bool 'RSBAC symlink redirection' + depends on RSBAC + ---help--- + This feature optionally changes the contents of a symlink, based on + the owner ID, the current MAC security level or the current RC role + ID of the process accessing it. + + NOTE: For technical reasons, all numeric characters at the end of the + original symlink contents will be replaced, not appended to. + This can be used to e.g. get the uid itself as final name and + the parent dir (or nothing...), if redirection is off. + +if RSBAC_SYM_REDIR + +config RSBAC_SYM_REDIR_REMOTE_IP + bool 'Add remote IP address' + depends on RSBAC_NET_OBJ + ---help--- + With this option enabled, every read from a symlink, which has a + symlink_add_remote_ip value > 0, gets this number of bytes added + in dot notation, e.g. 192.168.0 with value 3. + + This option is e.g. useful, if you want to provide different user + shells, depending on the origin of a connection: + Set user shell to /bin/linkshell. Make this a symlink to + /bin/usershell-, provide /bin/usershell-192.168.0 for users from + that network and /bin/usershell-0.0.0 for local users. + + As a side effect, users connecting from other networks have no + valid shell at all. + +config RSBAC_SYM_REDIR_UID + bool 'Add user ID number' + ---help--- + With this option enabled, every read from a symlink, which has the + symlink_add_uid flag set, gets the caller uid added in decimal + notation. + + This feature can e.g. be used to setup individual /tmp dirs for all + users, as root call: + + cd / + mkdir tmpdirs && chmod 777 tmpdirs && chmod o+t tmpdirs + # stay compatible, if redirection is off, by reusing old /tmp + mv tmp tmpdirs + ln -s tmpdirs/tmp tmp + mkdir tmpdirs/tmp0 ; chmod 700 tmpdirs/tmp0 + echo 'mkdir /tmpdirs/tmp$UID && chmod 700 /tmpdirs/tmp$UID' \ + >>/etc/profile + + As user with modify right for general attributes (e.g. user 400), set + symlink_add_uid to on for /tmp: + attr_set_file_dir SYMLINK /tmp symlink_add_uid 1 + + From now on, root accesses to /tmp show /tmpdirs/tmp0, user 400 + accesses show /tmpdir/tmp400, etc. It is of course advisable to + protect the individual dirs against root. + +config RSBAC_SYM_REDIR_MAC + bool 'Add MAC current security level' + depends on RSBAC_MAC + ---help--- + With this option enabled, every read from a symlink, which has the + symlink_add_mac_level flag set, gets the calling process's current + MAC security level added in decimal notation. + + It can be used to e.g. provide separate /tmp dirs for all MAC levels + and thus avoid unwanted flow of information. + See 'Add user ID number' help to get an idea of how to do this. + +config RSBAC_SYM_REDIR_MAC_CAT + bool 'Also add MAC current category vector' + depends on RSBAC_SYM_REDIR_MAC + ---help--- + If enabled, the redirected symlink contents will not only contain the + process current MAC security level, but also its current category set + as the usual string of 0 and 1, separated by a colon. + + WARNING: This will result in more possible values than your + filesystem can handle names and inodes, so please be + careful. + +config RSBAC_SYM_REDIR_RC + bool 'Add RC role number' + depends on RSBAC_SYM_REDIR && RSBAC_RC + ---help--- + With this option enabled, every read from a symlink, which has the + symlink_add_rc_role flag set, gets the calling process's current RC + role ID added in decimal notation. + + It can be used to e.g. provide individual /tmp dirs for all roles. + See 'Add user ID number' help to get an idea of how to do this. +endif + +menu 'Other RSBAC options' + depends on RSBAC + +config RSBAC_SECDEL + bool 'Support secure_delete' + depends on EXT2_FS || EXT3_FS || EXT4_FS || MSDOS_FS || VFAT_FS + ---help--- + This option enables secure deletion and truncation of all files. + The decision whether to overwrite is dispatched to all modules, + if one says yes, the file is overwritten. Currently only FF + supports this. + + FF returns yes, if file is marked with ff_flag secure_delete. This + flag can, as usual, be inherited from parent dir, if flag + add_inherited is set (default, if option 'Inherit as default' has + been chosen). + + Secure deletion and truncation is currently done by overwriting once + with zeros, because this is enough against hackers and standard level + analysers. Against well-fed organisations who got hold of your disk + there is no protection anyway. + + This mechanism is currently only supported for ext2, ext3, minix, + msdos and vfat, but could be extended to other file systems, if + needed. + +config RSBAC_RW + bool 'Intercept sys_read and sys_write' + default y + ---help--- + If enabled, the syscalls sys_read() and sys_write() for reading from + and writing to opened files, fifos and devices are also intercepted. + This slows down the system a bit, but allows more control of object + accesses to adapt to configuration changes. + + Please note that the interception for sockets only takes place, if + net support and socket read/write interception are also enabled + (CONFIG_RSBAC_NET and CONFIG_RSBAC_NET_RW). + +config RSBAC_IPC_SEM + bool 'Intercept Semaphore IPC operations' + default y + ---help--- + If on, System V IPC Semaphores are also protected. As there is no + direct data flow over semaphores, they can mostly be misused for + denial of service attacks. Turn on for special needs, keep off + otherwise. + +config RSBAC_DAC_OWNER + bool 'Control DAC process owner (seteuid, setfsuid)' + ---help--- + Usually, only set*uid calls, which affect the real user ID used for + RSBAC decisions, issue a decision request CHANGE_OWNER for processes. + With this option, changes to the effective (CHANGE_DAC_EFF_OWNER) and + the filesystem (CHANGE_DAC_FS_OWNER) owner are also controlled. + + Please also see AUTH option 'AUTH support for effective and fs owner + control'. + +config RSBAC_DAC_GROUP + bool 'Control DAC process group (setegid, setfsgid)' + ---help--- + Usually, set*gid calls issue only the decision request CHANGE_GROUP + for changes to the process group. + With this option, changes to the effective (CHANGE_DAC_EFF_GROUP) and + the filesystem (CHANGE_DAC_FS_GROUP) group are also controlled. + + Please also see AUTH option 'AUTH support for effective and fs group + control'. + + +config RSBAC_PROC_HIDE + bool 'Hide processes in /proc' + ---help--- + If enabled, a process is also hidden in /proc listing, if the reading + process has no GET_STATUS_DATA right to it. + This option adds a significant amount of requests, when reading + /proc, so it is off by default. + +config RSBAC_FSOBJ_HIDE + bool 'Hide filesystem objects' + ---help--- + If enabled, every filesystem object (file, dir, named pipe, + unix socket) will be completely hidden from every process that + has no SEARCH right to it. + + WARNING! You need to remove all rights to that object you are + trying to hide to make it fully protected! Otherwise + overwriting may be possible by a process that knows this + object's name! + +config RSBAC_FREEZE + bool 'Support freezing of RSBAC configuration' + default y + ---help--- + If enabled, the kernel parameter rsbac_freeze disables all + administrative system calls, which change settings. + +config RSBAC_FREEZE_UM + bool 'Also freeze User Management' + depends on RSBAC_FREEZE && RSBAC_UM + ---help--- + If enabled, the RSBAC User Management gets frozen, too. + +config RSBAC_SYSLOG + bool 'RSBAC check sys_syslog' + ---help--- + If enabled, the syscall sys_syslog() for system log is also checked, + leading to less performance for a minor security issue. + +config RSBAC_IOCTL + bool 'Generic check in sys_ioctl' + default y + ---help--- + Enable this switch to get all calls to sys_ioctl for DEV and NETOBJ + targets checked by RSBAC. In any case, some important sys_ioctl calls + will also be checked as GET_STATUS_DATA or MODIFY_SYSTEM_DATA + requests. + + This interception produces some overhead on desktop systems, so it + should be considered to turn it off on such systems. + +config RSBAC_USER_CHOWN + bool 'Check CHANGE_OWNER on PROCESS against USER target' + default n + ---help--- + With this option, each CHANGE_OWNER request on PROCESS targets + creates an additional CHANGE_OWNER request on the new owner as + USER target. + + The additional check allows modules to control user changes + depending on the current state of the process attributes, + e.g. current role or owner. + +config RSBAC_DAT_VISIBLE + bool 'Make RSBAC data files visible' + ---help--- + By default, the rsbac.dat directories containing the list data + backups are unreadable for any user. Unfortunately, some programs + must be able to read all directories, e.g. the quota tools. + + This option enables read and status access to the rsbac.dat + directories, but the files themselves are kept unreadable. + +config RSBAC_NO_DECISION_ON_NETMOUNT + bool 'No decision on net mounts' + ---help--- + If this option is turned on, no decisions are made and no attributes + are set for all accesses to files and dirs on network mounts. For + these targets, RSBAC behaves like a maintenance kernel. So even + Dazuko is turned off. Attribute saving or restoring is not done + anyway. + + Use this option, if you cannot access your network files properly, + and keep it off otherwise. + +config RSBAC_ENFORCE_CLOSE + bool 'Enforce denied close access' + ---help--- + By default, RSBAC only logs denied CLOSE access on filesystem + objects and still performs the close, because many broken + programs rely on close to always succeed. With this switch on, + RSBAC really returns -EPERM and keeps the object opened. + +config RSBAC_MOVETO + bool 'Use MOVETO requests when writing to DIR' + default n + ---help--- + When moving an object into a directory, use request + MOVETO, not the old WRITE. + Default is n for backwards compatibility. + +config RSBAC_MOVETO_EXDEV + bool 'Treat denied MOVETO on DIR like different device' + default n + ---help--- + By default, RSBAC just returns -EPERM, if moving an object + into a dir is denied because of missing WRITE or MOVETO right. + With this option on, it will instead return -EXDEV, as if + the new dir was on a different partition. Most tools will + then try to copy the old item and delete it afterwards. + +config RSBAC_USER_MOD_IOPERM + bool 'X support (normal user MODIFY_PERM access to ST_ioports)' + ---help--- + Normally, MODIFY_PERMISSIONS_DATA access to SCD target ST_ioports is + not granted for normal users, because this would allow direct + hardware access. Unfortunately, X servers depend on this. So if you + need X on your system, enable this, otherwise keep it off. + + This switch enables the following changes: + - MAC, FC, SIM and AUTH hardwired policies are adjusted to allow + this access type for every user. + - RC and ACL default settings are adjusted accordingly, but + existing or later settings are not affected. + +config RSBAC_FAKE_ROOT_UID + bool 'Faked root uid' + ---help--- + With this turned on, programs can optionally get uid 0 returned from + every getuid() and/or geteuid() call. + + Some programs check, whether they really run as root, although they + already have sufficient rights to do their jobs. This forces users + to keep them running under the dangerous root account. + + +config RSBAC_MPROTECT + bool 'Prevent memory write and execute (w^x)' + ---help--- + This option enables the RSBAC prevention of process memory + segments being both writable and executable. + + The check can be disabled per program with the general FD + and process attribute allow_write_exec. + + +config RSBAC_XSTATS + bool 'RSBAC extra statistics' + default y + depends on RSBAC_PROC + ---help--- + If enabled, extended RSBAC statistics are collected. Currently these + are mostly count matrices of adf_request and adf_set_attr calls by + target type and request type. These matrices give a detailed overview + of the request and thus the system call behaviour. + + Also, there is an access count for calls to data structures by target + type. + + The extra data can be read from another proc file called xstats. +endmenu + +endif diff --git a/rsbac/Makefile b/rsbac/Makefile new file mode 100644 index 000000000000..c4e038553533 --- /dev/null +++ b/rsbac/Makefile @@ -0,0 +1,11 @@ +# +# Main Makefile for the Rule Set Based Access Control subsystem. +# +# Author and (c) 1999-2013 Amon Ott + +obj-y := help/ data_structures/ adf/ +obj-m := adf/ + +clean: Makefile + rm -f `find . -name modules.builtin -o -name modules.order -name '*.o' -o -name '*.o.cmd' -o -name '*.ko' -o -name '*.ko.cmd' -print` + diff --git a/rsbac/adf/Makefile b/rsbac/adf/Makefile new file mode 100644 index 000000000000..5fed80e98af6 --- /dev/null +++ b/rsbac/adf/Makefile @@ -0,0 +1,54 @@ +# +# File: rsbac/adf/Makefile +# +# Makefile for the Linux RSBAC Access Control Decision Facility (ADF) +# +# Author and (c) 1999-2013 Amon Ott +# + +obj-y := adf_main.o + +ifeq ($(CONFIG_RSBAC_DEBUG),y) +obj-y += adf_check.o +endif + +# Adding policies +subdir-$(CONFIG_RSBAC_MAC) += mac +obj-$(CONFIG_RSBAC_MAC) += mac/ + +subdir-$(CONFIG_RSBAC_DAZ) += daz +obj-$(CONFIG_RSBAC_DAZ) += daz/ + +subdir-$(CONFIG_RSBAC_FF) += ff +obj-$(CONFIG_RSBAC_FF) += ff/ + +subdir-$(CONFIG_RSBAC_RC) += rc +obj-$(CONFIG_RSBAC_RC) += rc/ + +subdir-$(CONFIG_RSBAC_AUTH) += auth +obj-$(CONFIG_RSBAC_AUTH) += auth/ + +subdir-$(CONFIG_RSBAC_ACL) += acl +obj-$(CONFIG_RSBAC_ACL) += acl/ + +subdir-$(CONFIG_RSBAC_CAP) += cap +obj-$(CONFIG_RSBAC_CAP) += cap/ + +subdir-$(CONFIG_RSBAC_JAIL) += jail +obj-$(CONFIG_RSBAC_JAIL) += jail/ + +subdir-$(CONFIG_RSBAC_PAX) += pax +obj-$(CONFIG_RSBAC_PAX) += pax/ + +subdir-$(CONFIG_RSBAC_RES) += res +obj-$(CONFIG_RSBAC_RES) += res/ + +subdir-$(CONFIG_RSBAC_UDF) += udf +obj-$(CONFIG_RSBAC_UDF) += udf/ + +subdir-$(CONFIG_RSBAC_REG) += reg +obj-$(CONFIG_RSBAC_REG) += reg/ +ifeq ($(CONFIG_RSBAC_REG_SAMPLES),y) +subdir-m += reg +endif + diff --git a/rsbac/adf/acl/Makefile b/rsbac/adf/acl/Makefile new file mode 100644 index 000000000000..448fe5324433 --- /dev/null +++ b/rsbac/adf/acl/Makefile @@ -0,0 +1,10 @@ +# +# File: rsbac/adf/auth/Makefile +# +# Makefile for the Linux rsbac auth decision module. +# +# Author and (c) 1999-2013 Amon Ott +# + +obj-y := acl_syscalls.o acl_main.o + diff --git a/rsbac/adf/acl/acl_main.c b/rsbac/adf/acl/acl_main.c new file mode 100644 index 000000000000..3522c57d61dc --- /dev/null +++ b/rsbac/adf/acl/acl_main.c @@ -0,0 +1,534 @@ +/**************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - Access Control Lists (ACL) */ +/* File: rsbac/adf/acl/acl_main.c */ +/* */ +/* Author and (c) 1999-2017: Amon Ott */ +/* */ +/* Last modified: 21/Mar/2017 */ +/**************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +#if defined(CONFIG_RSBAC_ACL_LEARN) +#ifdef CONFIG_RSBAC_ACL_LEARN_TA +rsbac_list_ta_number_t acl_learn_ta = CONFIG_RSBAC_ACL_LEARN_TA; +#else +rsbac_list_ta_number_t acl_learn_ta = 0; +#endif +#endif + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +/* in acl_syscalls.c */ +rsbac_boolean_t rsbac_acl_check_super(enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_uid_t user); + +rsbac_boolean_t rsbac_acl_check_right(enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_uid_t user, + rsbac_pid_t caller_pid, + enum rsbac_adf_request_t request) + { + rsbac_boolean_t result = FALSE; + int err=0, tmperr; + int i; + rsbac_acl_group_id_t * group_p; + #if defined(CONFIG_RSBAC_RC) + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + #endif + + /* Only check implemented targets */ + switch(target) + { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_DEV: + case T_IPC: + case T_SCD: + case T_USER: + case T_PROCESS: +#ifdef CONFIG_RSBAC_ACL_UM_PROT + case T_GROUP: +#endif +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + case T_NETDEV: +#endif +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + case T_NETTEMP_NT: + case T_NETTEMP: + case T_NETOBJ: +#endif + break; + default: + return TRUE; + } + /* inherited own rights */ + err = rsbac_acl_get_single_right(target, + tid, + ACLS_USER, + (rsbac_acl_subject_id_t) user, + request, + &result); + if(err) + { + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_check_right(): rsbac_acl_get_single_right() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + return FALSE; + } + if(result) + return TRUE; + + /* add group and role rights */ + /* group everyone */ + err = rsbac_acl_get_single_right(target, + tid, + ACLS_GROUP, + RSBAC_ACL_GROUP_EVERYONE, + request, + &result); + if(err) + { + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_check_right(): rsbac_acl_get_single_right() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + return FALSE; + } + if(result) + return TRUE; + + #if defined(CONFIG_RSBAC_RC) + /* use process role */ + /* first get role */ + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_RC, + T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, + FALSE)) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_check_right(): rsbac_get_attr() for process rc_role returned error!\n"); + } + else + { + err = rsbac_acl_get_single_right(target, + tid, + ACLS_ROLE, + i_attr_val1.rc_role, + request, + &result); + if(err) + { + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp) + { + get_error_name(tmp,err); + rsbac_printk(KERN_WARNING + "rsbac_acl_check_right(): rsbac_acl_get_single_right() returned error %s!\n", + tmp); + rsbac_kfree(tmp); + } + return FALSE; + } + if(result) + return TRUE; + } + #endif + + /* other groups */ + /* first get user groups */ + group_p = NULL; + err = rsbac_acl_get_user_groups(0, user, &group_p, NULL); + if(err<0) + { + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_check_right(): rsbac_acl_get_user_groups() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + return err; + } + for(i=0; i */ +/* */ +/* Last modified: 04/Apr/2016 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_RSBAC_NET_OBJ +#include +#endif + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +rsbac_boolean_t rsbac_acl_check_super(enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_uid_t user) +{ + rsbac_boolean_t i_result = FALSE; + int err=0, tmperr; + int i; + rsbac_acl_group_id_t * group_p; + #if defined(CONFIG_RSBAC_RC) + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + #endif + + /* Only check implemented targets */ + switch(target) + { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_DEV: + case T_IPC: + case T_SCD: + case T_USER: + case T_PROCESS: +#ifdef CONFIG_RSBAC_ACL_UM_PROT + case T_GROUP: +#endif + case T_NETDEV: + case T_NETTEMP_NT: + case T_NETTEMP: + case T_NETOBJ: + break; + default: + return TRUE; + } + /* own right */ + err = rsbac_acl_get_single_right(target, + tid, + ACLS_USER, + (rsbac_acl_subject_id_t) user, + ACLR_SUPERVISOR, + &i_result); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_check_super(): rsbac_acl_get_single_right() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + return FALSE; + } + if(i_result) + return(TRUE); + + /* try SUPERVISOR for group and role */ + /* group everyone */ + err = rsbac_acl_get_single_right(target, + tid, + ACLS_GROUP, + RSBAC_ACL_GROUP_EVERYONE, + ACLR_SUPERVISOR, + &i_result); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_check_super(): rsbac_acl_get_single_right() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + return FALSE; + } + if(i_result) + return(TRUE); + + #if defined(CONFIG_RSBAC_RC) + /* use process role */ + /* first get role */ + i_tid.process = task_pid(current); + if (rsbac_get_attr(SW_RC, + T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, + FALSE)) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_check_super(): rsbac_get_attr() for process rc_role returned error!\n"); + } + else + { + err = rsbac_acl_get_single_right(target, + tid, + ACLS_ROLE, + i_attr_val1.rc_role, + ACLR_SUPERVISOR, + &i_result); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + get_error_name(tmp,err); + rsbac_printk(KERN_WARNING + "rsbac_acl_check_super(): rsbac_acl_get_single_right() returned error %s!\n", + tmp); + rsbac_kfree(tmp); + } + return FALSE; + } + if(i_result) + return(TRUE); + } + #endif + + /* other groups */ + /* first get user groups */ + group_p = NULL; + err = rsbac_acl_get_user_groups(0, user, &group_p, NULL); + if(err<0) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_check_super(): rsbac_acl_get_user_groups() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + return err; + } + for(i=0; ifile + || !tid.netobj.sock_p->file->f_path.dentry + || !tid.netobj.sock_p->file->f_path.dentry->d_inode + || (SOCKET_I(tid.netobj.sock_p->file->f_path.dentry->d_inode) != tid.netobj.sock_p) + ) + ) + return -RSBAC_EINVALIDTARGET; +#endif + +#ifdef CONFIG_RSBAC_SWITCH_ACL + if(rsbac_switch_acl) +#endif + { + rsbac_uid_t user; + + if(rsbac_get_owner(&user)) + return -RSBAC_EREADFAILED; + /* first try access control right (SUPERVISOR try is included) */ + if(!rsbac_acl_check_right(target, tid, user, task_pid(current), ACLR_ACCESS_CONTROL)) + { + /* no access control -> try forward for these rights */ + /* but only, if no ttl requested */ + if( (ttl != RSBAC_LIST_TTL_KEEP) + || !rsbac_acl_check_forward(target, tid, user, rights) + ) + { + char * rights_string = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + char * subject_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + char * target_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + char * target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + char * target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + + u64tostracl(rights_string, rights); + get_acl_subject_type_name(subject_type_name, subj_type); + get_target_name(target_type_name, target, target_id_name, tid); + rsbac_printk(KERN_INFO + "rsbac_acl_sys_set_acl_entry(): setting rights %s for %s %u to %s %s denied for user %u!\n", + rights_string, + subject_type_name, + subj_id, + target_type_name, + target_id_name, + user); + rsbac_kfree(rights_string); + rsbac_kfree(subject_type_name); + rsbac_kfree(target_type_name); + rsbac_kfree(target_id_name); + + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_ACL] + #endif + ) + #endif + return -EPERM; + } + } + if(rights & RSBAC_ACL_SUPERVISOR_RIGHT_VECTOR) + { + /* you must have SUPERVISOR to set SUPERVISOR */ + if(!rsbac_acl_check_super(target, tid, user)) + { + char * subject_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + char * target_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + char * target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + char * target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + + get_acl_subject_type_name(subject_type_name, subj_type); + get_target_name(target_type_name, target, target_id_name, tid); + rsbac_printk(KERN_INFO + "rsbac_acl_sys_set_acl_entry(): setting SUPERVISOR for %s %u to %s %s denied for user %u!\n", + subject_type_name, + subj_id, + target_type_name, + target_id_name, + user); + rsbac_kfree(subject_type_name); + rsbac_kfree(target_type_name); + rsbac_kfree(target_id_name); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_ACL] + #endif + ) + #endif + return -EPERM; + } + } + } + + /* OK, check passed. Set ACL. */ + err = rsbac_acl_set_acl_entry(ta_number, target, tid, subj_type, subj_id, rights, ttl); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_sys_set_acl_entry(): rsbac_acl_set_acl_entry() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + } + return err; + } + +int rsbac_acl_sys_remove_acl_entry( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id) + { + int err=0; + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + /* sanity check before using pointer */ + if( (target == T_NETOBJ) + && tid.netobj.sock_p + && ( tid.netobj.remote_addr + || !tid.netobj.sock_p->file + || !tid.netobj.sock_p->file->f_path.dentry + || !tid.netobj.sock_p->file->f_path.dentry->d_inode + || (SOCKET_I(tid.netobj.sock_p->file->f_path.dentry->d_inode) != tid.netobj.sock_p) + ) + ) + return -RSBAC_EINVALIDTARGET; +#endif + +#ifdef CONFIG_RSBAC_SWITCH_ACL + if(rsbac_switch_acl) +#endif + { + rsbac_uid_t user; + rsbac_acl_rights_vector_t res_rights = 0; + + if(rsbac_get_owner(&user)) + return -RSBAC_EREADFAILED; + /* first try access control right (SUPERVISOR is included) */ + if(!rsbac_acl_check_right(target, tid, user, task_pid(current), ACLR_ACCESS_CONTROL)) + { + char * subject_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + char * target_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + char * target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + char * target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + + get_acl_subject_type_name(subject_type_name, subj_type); + get_target_name(target_type_name, target, target_id_name, tid); + rsbac_printk(KERN_INFO + "rsbac_acl_sys_remove_acl_entry(): removing ACL entry for %s %u at %s %s denied for user %u!\n", + subject_type_name, + subj_id, + target_type_name, + target_id_name, + user); + rsbac_kfree(subject_type_name); + rsbac_kfree(target_type_name); + rsbac_kfree(target_id_name); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_ACL] + #endif + ) + #endif + return -EPERM; + } + + err = rsbac_acl_get_rights(0, target, tid, subj_type, subj_id, &res_rights, FALSE); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_sys_remove_acl_entry(): rsbac_acl_get_rights() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + return err; + } + if(res_rights & RSBAC_ACL_SUPERVISOR_RIGHT_VECTOR) + { + /* you must have SUPERVISOR to remove an entry with SUPERVISOR */ + if(!rsbac_acl_check_super(target, tid, user)) + { + char * subject_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + char * target_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + char * target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + char * target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + + get_acl_subject_type_name(subject_type_name, subj_type); + get_target_name(target_type_name, target, target_id_name, tid); + rsbac_printk(KERN_INFO + "rsbac_acl_sys_remove_acl_entry(): removing ACL entry with SUPERVISOR for %s %u at %s %s denied for user %u!\n", + subject_type_name, + subj_id, + target_type_name, + target_id_name, + user); + rsbac_kfree(subject_type_name); + rsbac_kfree(target_type_name); + rsbac_kfree(target_id_name); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_ACL] + #endif + ) + #endif + return -EPERM; + } + } + } + + /* OK, check passed. Set ACL. */ + err = rsbac_acl_remove_acl_entry(ta_number, target, tid, subj_type, subj_id); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_sys_remove_acl_entry(): rsbac_acl_remove_acl_entry() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + } + return err; + } + +int rsbac_acl_sys_remove_acl( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid) + { + int err=0; + +#ifdef CONFIG_RSBAC_SWITCH_ACL + if(rsbac_switch_acl) +#endif + { + rsbac_uid_t user; + + if(rsbac_get_owner(&user)) + return -RSBAC_EREADFAILED; + /* check SUPERVISOR */ + if(!rsbac_acl_check_super(target, tid, user)) + { + char * target_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + char * target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + char * target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + + get_target_name(target_type_name, target, target_id_name, tid); + rsbac_printk(KERN_INFO + "rsbac_acl_sys_remove_acl(): removing ACL from %s %s denied for user %u!\n", + target_type_name, + target_id_name, + user); + rsbac_kfree(target_type_name); + rsbac_kfree(target_id_name); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_ACL] + #endif + ) + #endif + return -EPERM; + } + } + + /* OK, check passed. Set ACL. */ + err = rsbac_acl_remove_acl(ta_number, target, tid); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_sys_remove_acl(): rsbac_acl_remove_acl() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + } + return err; + } + +int rsbac_acl_sys_add_to_acl_entry( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t rights, + rsbac_time_t ttl) + { + int err=0; + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + /* sanity check before using pointer */ + if( (target == T_NETOBJ) + && tid.netobj.sock_p + && ( tid.netobj.remote_addr + || !tid.netobj.sock_p->file + || !tid.netobj.sock_p->file->f_path.dentry + || !tid.netobj.sock_p->file->f_path.dentry->d_inode + || (SOCKET_I(tid.netobj.sock_p->file->f_path.dentry->d_inode) != tid.netobj.sock_p) + ) + ) + return -RSBAC_EINVALIDTARGET; +#endif + +#ifdef CONFIG_RSBAC_SWITCH_ACL + if(rsbac_switch_acl) +#endif + { + rsbac_uid_t user; + + if(rsbac_get_owner(&user)) + return -RSBAC_EREADFAILED; + /* first try access control right (SUPERVISOR is included) */ + if(!rsbac_acl_check_right(target, tid, user, task_pid(current), ACLR_ACCESS_CONTROL)) + { + /* no access control -> try forward for these rights */ + /* but only, if no ttl requested */ + if( (ttl != RSBAC_LIST_TTL_KEEP) + || !rsbac_acl_check_forward(target, tid, user, rights) + ) + { + char * rights_string = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + char * subject_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + char * target_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + char * target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + char * target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + + u64tostracl(rights_string, rights); + get_acl_subject_type_name(subject_type_name, subj_type); + get_target_name(target_type_name, target, target_id_name, tid); + rsbac_printk(KERN_INFO + "rsbac_acl_sys_add_to_acl_entry(): adding rights %s for %s %u to %s %s denied for user %u!\n", + rights_string, + subject_type_name, + subj_id, + target_type_name, + target_id_name, + user); + rsbac_kfree(rights_string); + rsbac_kfree(subject_type_name); + rsbac_kfree(target_type_name); + rsbac_kfree(target_id_name); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_ACL] + #endif + ) + #endif + return -EPERM; + } + } + if(rights & RSBAC_ACL_SUPERVISOR_RIGHT_VECTOR) + { + /* you must have SUPERVISOR to add SUPERVISOR */ + if(!rsbac_acl_check_super(target, tid, user)) + { + char * subject_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + char * target_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + char * target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + char * target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + + get_acl_subject_type_name(subject_type_name, subj_type); + get_target_name(target_type_name, target, target_id_name, tid); + rsbac_printk(KERN_INFO + "rsbac_acl_sys_add_to_acl_entry(): adding SUPERVISOR for %s %u to %s %s denied for user %u!\n", + subject_type_name, + subj_id, + target_type_name, + target_id_name, + user); + rsbac_kfree(subject_type_name); + rsbac_kfree(target_type_name); + rsbac_kfree(target_id_name); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_ACL] + #endif + ) + #endif + return -EPERM; + } + } + } + + /* OK, check passed. Set ACL. */ + err = rsbac_acl_add_to_acl_entry(ta_number, target, tid, subj_type, subj_id, rights, ttl); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_sys_add_to_acl_entry(): rsbac_acl_add_to_acl_entry() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + } + return err; + } + +int rsbac_acl_sys_remove_from_acl_entry( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t rights) + { + int err=0; + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + /* sanity check before using pointer */ + if( (target == T_NETOBJ) + && tid.netobj.sock_p + && ( tid.netobj.remote_addr + || !tid.netobj.sock_p->file + || !tid.netobj.sock_p->file->f_path.dentry + || !tid.netobj.sock_p->file->f_path.dentry->d_inode + || (SOCKET_I(tid.netobj.sock_p->file->f_path.dentry->d_inode) != tid.netobj.sock_p) + ) + ) + return -RSBAC_EINVALIDTARGET; +#endif + +#ifdef CONFIG_RSBAC_SWITCH_ACL + if(rsbac_switch_acl) +#endif + { + rsbac_uid_t user; + + if(rsbac_get_owner(&user)) + return -RSBAC_EREADFAILED; + /* first try access control right (SUPERVISOR is included) */ + if(!rsbac_acl_check_right(target, tid, user, task_pid(current), ACLR_ACCESS_CONTROL)) + { + char * rights_string = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + char * subject_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + char * target_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + char * target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + char * target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + + u64tostracl(rights_string, rights); + get_acl_subject_type_name(subject_type_name, subj_type); + get_target_name(target_type_name, target, target_id_name, tid); + rsbac_printk(KERN_INFO + "rsbac_acl_sys_remove_from_acl_entry(): removing rights %s for %s %u to %s %s denied for user %u!\n", + rights_string, + subject_type_name, + subj_id, + target_type_name, + target_id_name, + user); + rsbac_kfree(rights_string); + rsbac_kfree(subject_type_name); + rsbac_kfree(target_type_name); + rsbac_kfree(target_id_name); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_ACL] + #endif + ) + #endif + return -EPERM; + } + if(rights & RSBAC_ACL_SUPERVISOR_RIGHT_VECTOR) + { + /* you must have SUPERVISOR to revoke SUPERVISOR */ + if(!rsbac_acl_check_super(target, tid, user)) + { + char * subject_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + char * target_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + char * target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + char * target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + + get_acl_subject_type_name(subject_type_name, subj_type); + get_target_name(target_type_name, target, target_id_name, tid); + rsbac_printk(KERN_INFO + "rsbac_acl_sys_remove_from_acl_entry(): removing SUPERVISOR for %s %u to %s %s denied for user %u!\n", + subject_type_name, + subj_id, + target_type_name, + target_id_name, + user); + rsbac_kfree(subject_type_name); + rsbac_kfree(target_type_name); + rsbac_kfree(target_id_name); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_ACL] + #endif + ) + #endif + return -EPERM; + } + } + } + + /* OK, check passed. Remove ACL. */ + err = rsbac_acl_remove_from_acl_entry(ta_number, target, tid, subj_type, subj_id, rights); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_sys_remove_from_acl_entry(): rsbac_acl_remove_from_acl_entry() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + } + return err; + } + +int rsbac_acl_sys_set_mask( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_acl_rights_vector_t mask) + { + int err=0; + + rsbac_uid_t user; + + if(rsbac_get_owner(&user)) + return -RSBAC_EREADFAILED; + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + /* sanity check before using pointer */ + if( (target == T_NETOBJ) + && tid.netobj.sock_p + && ( tid.netobj.remote_addr + || !tid.netobj.sock_p->file + || !tid.netobj.sock_p->file->f_path.dentry + || !tid.netobj.sock_p->file->f_path.dentry->d_inode + || (SOCKET_I(tid.netobj.sock_p->file->f_path.dentry->d_inode) != tid.netobj.sock_p) + ) + ) + return -RSBAC_EINVALIDTARGET; +#endif + +#ifdef CONFIG_RSBAC_SWITCH_ACL + if(rsbac_switch_acl) +#endif + { + /* first try access control right (SUPERVISOR is included) */ + if(!rsbac_acl_check_right(target, tid, user, task_pid(current), ACLR_ACCESS_CONTROL)) + { + char * rights_string = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + char * target_type_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + char * target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + char * target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + + u64tostracl(rights_string, mask); + get_target_name(target_type_name, target, target_id_name, tid); + rsbac_printk(KERN_INFO + "rsbac_acl_sys_set_mask(): setting mask %s for %s %s denied for user %u!\n", + rights_string, + target_type_name, + target_id_name, + user); + rsbac_kfree(rights_string); + rsbac_kfree(target_type_name); + rsbac_kfree(target_id_name); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_ACL] + #endif + ) + #endif + return -EPERM; + } + } + +#ifdef CONFIG_RSBAC_ACL_SUPER_FILTER + if(!(mask & RSBAC_ACL_SUPERVISOR_RIGHT_VECTOR)) + { /* trial to mask out SUPERVISOR */ + rsbac_acl_rights_vector_t res_rights = 0; + + /* you must have direct SUPERVISOR as a USER to set a mask without SUPERVISOR */ + /* get direct own rights (still uses default_fd_rights) */ + err = rsbac_acl_get_rights(0, target, tid, ACLS_USER, user, &res_rights, FALSE); + if(err) + return -RSBAC_EREADFAILED; + if(!(res_rights & RSBAC_ACL_SUPERVISOR_RIGHT_VECTOR)) + mask |= RSBAC_ACL_SUPERVISOR_RIGHT_VECTOR; + } +#else + /* SUPERVISOR must never be masked out */ + mask |= RSBAC_ACL_SUPERVISOR_RIGHT_VECTOR; +#endif + + /* OK, checks passed. Set mask. */ + err = rsbac_acl_set_mask(ta_number, target, tid, mask); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_sys_set_mask(): rsbac_acl_set_mask() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + } + return err; + } + +int rsbac_acl_sys_remove_user( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t uid) + { + int err=0; + +#ifdef CONFIG_RSBAC_SWITCH_ACL + if(rsbac_switch_acl) +#endif + { + rsbac_uid_t user; + union rsbac_target_id_t tid; + + if(rsbac_get_owner(&user)) + return -RSBAC_EREADFAILED; + tid.user = uid; + /* first try access control right (SUPERVISOR is included) */ + if(!rsbac_acl_check_right(T_USER, tid, user, task_pid(current), R_DELETE)) + { + rsbac_printk(KERN_INFO + "rsbac_acl_sys_remove_user(): removing all data for user %u denied for user %u!\n", + uid, + user); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_ACL] + #endif + ) + #endif + return -EPERM; + } + } + + rsbac_printk(KERN_INFO + "rsbac_acl_sys_remove_user(): removing all data for user %u!\n", + uid); + /* OK, checks passed. Set mask. */ + err = rsbac_acl_remove_user(ta_number, uid); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_sys_remove_user(): rsbac_acl_remove_user() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + } + return err; + } + +/*********/ + +int rsbac_acl_sys_get_mask( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_acl_rights_vector_t * mask_p) + { + int err=0; + +/* no check */ + + /* OK, check passed. Get mask. */ + err = rsbac_acl_get_mask(ta_number, target, tid, mask_p); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_sys_get_mask(): rsbac_acl_get_mask() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + } + return err; + } + +int rsbac_acl_sys_get_rights( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t * rights_p, + rsbac_boolean_t effective) + { + int err=0; + rsbac_acl_rights_vector_t res_rights; + #if defined(CONFIG_RSBAC_RC) + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + #endif + + /* no check (Attention: rsbac_acl_check_forward depends on this to be allowed!) */ + + if( (subj_type == ACLS_USER) + && (subj_id == RSBAC_NO_USER) + ) + rsbac_get_owner((rsbac_uid_t *) &subj_id); + /* OK, check passed. Call ACL. */ + if(effective) + { + /* inherited own rights */ + res_rights = 0; + err = rsbac_acl_get_rights(ta_number, target, tid, subj_type, subj_id, &res_rights, TRUE); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_sys_get_rights(): rsbac_acl_get_rights() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + return err; + } + *rights_p = res_rights; + /* add group and role rights, if normal user */ + if(subj_type == ACLS_USER) + { + rsbac_acl_group_id_t * group_p; + int i; + int tmperr; + + /* group everyone */ + res_rights = 0; + err = rsbac_acl_get_rights(ta_number, target, tid, + ACLS_GROUP, RSBAC_ACL_GROUP_EVERYONE, + &res_rights, TRUE); + if(err) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_sys_get_rights(): rsbac_acl_get_rights() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + return err; + } + *rights_p |= res_rights; + + /* other groups */ + /* first get user groups */ + group_p = NULL; + err = rsbac_acl_get_user_groups(ta_number, subj_id, &group_p, NULL); + if(err<0) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_acl_sys_get_rights(): rsbac_acl_get_user_groups() returned error %s!\n", + get_error_name(tmp,err)); + rsbac_kfree(tmp); + } + return err; + } + for(i=0; i= ACLGS_none) + return -RSBAC_EINVALIDREQUEST; + if(rsbac_get_owner(&caller)) + return -RSBAC_EREADFAILED; + +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_aef_acl) + { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_DEBUG + "rsbac_acl_sys_group(): %s called\n", + get_acl_group_syscall_name(tmp,call)); + rsbac_kfree(tmp); + } + } +#endif + + switch(call) + { + case ACLGS_add_group: + if(arg.add_group.type >= ACLG_NONE) + { + err = -RSBAC_EINVALIDVALUE; + break; + } + k_name = rsbac_getname(arg.add_group.name); + if(!k_name) + { + err = -RSBAC_EINVALIDVALUE; + break; + } + err = rsbac_get_user(&k_group, arg.add_group.group_id_p, sizeof(k_group)); + if(err) + break; + err = rsbac_acl_add_group(ta_number, + caller, + arg.add_group.type, + k_name->name, + &k_group); + rsbac_putname(k_name); + if(!err) + err = rsbac_put_user(&k_group, arg.add_group.group_id_p, sizeof(k_group)); + break; + + case ACLGS_change_group: + if(arg.change_group.type >= ACLG_NONE) + { + err = -RSBAC_EINVALIDVALUE; + break; + } + err = rsbac_acl_get_group_entry(ta_number, arg.change_group.id, &entry); + if(err) + break; +#ifdef CONFIG_RSBAC_SWITCH_ACL + if(rsbac_switch_acl) +#endif + { + if(entry.owner != caller) + { + rsbac_printk(KERN_INFO + "rsbac_acl_group(): changing group %u denied for user %u - not owner!\n", + entry.id, + caller); + err = -EPERM; + break; + } + } + { + struct filename * k_name; + + k_name = rsbac_getname(arg.change_group.name); + if(k_name) + { + err = rsbac_acl_change_group(ta_number, + arg.change_group.id, + arg.change_group.owner, + arg.change_group.type, + k_name->name); + putname(k_name); + } + else + err = -RSBAC_EINVALIDVALUE; + } + break; + + case ACLGS_remove_group: + err = rsbac_acl_get_group_entry(ta_number, arg.remove_group.id, &entry); + if(err) + break; +#ifdef CONFIG_RSBAC_SWITCH_ACL + if(rsbac_switch_acl) +#endif + { + if(entry.owner != caller) + { + rsbac_printk(KERN_INFO + "rsbac_acl_group(): removing group %u denied for user %u - not owner!\n", + entry.id, + caller); + err = -EPERM; + break; + } + } + err = rsbac_acl_remove_group(ta_number, arg.remove_group.id); + break; + + case ACLGS_get_group_entry: + if(!arg.get_group_entry.entry_p) + { + err = -RSBAC_EINVALIDPOINTER; + break; + } + if(!arg.get_group_entry.id) + { /* Everyone -> fill by hand */ + entry.id=0; + entry.owner=RSBAC_NO_USER; + entry.type=ACLG_GLOBAL; + strcpy(entry.name, "Everyone"); + err=0; + } + else + { + err = rsbac_acl_get_group_entry(ta_number, + arg.get_group_entry.id, + &entry); + } + if(!err) + { + if( (entry.owner != caller) + &&(entry.type != ACLG_GLOBAL) + ) + { + rsbac_printk(KERN_INFO + "rsbac_acl_group(): getting group entry %u denied for user %u - neither owner nor global!\n", + entry.id, + caller); + err = -EPERM; + } + else + err = rsbac_put_user(&entry, arg.get_group_entry.entry_p, sizeof(entry)); + } + break; + + case ACLGS_list_groups: + if(arg.list_groups.maxnum <= 0) + { + err = -RSBAC_EINVALIDVALUE; + break; + } + if(!arg.list_groups.group_entry_array) + { + err = -RSBAC_EINVALIDPOINTER; + break; + } + { + struct rsbac_acl_group_entry_t * entry_p; + int tmperr=0; + + if(arg.list_groups.include_global) + { + struct rsbac_acl_group_entry_t entry_0; + + entry_0.id=0; + entry_0.owner=RSBAC_NO_USER; + entry_0.type=ACLG_GLOBAL; + strcpy(entry_0.name, "Everyone"); + tmperr = rsbac_put_user(&entry_0, + arg.list_groups.group_entry_array, + sizeof(entry_0)); + if(tmperr) + { + err = tmperr; + break; + } + else + err = 1; + arg.list_groups.maxnum--; + arg.list_groups.group_entry_array++; + } + else + err = 0; + + if(arg.list_groups.maxnum) + { + long count; + + count = rsbac_acl_list_groups(ta_number, + caller, + arg.list_groups.include_global, + &entry_p); + if(count>0) + { + if(count > arg.list_groups.maxnum) + count = arg.list_groups.maxnum; + err+=count; + tmperr = rsbac_put_user(entry_p, + arg.list_groups.group_entry_array, + count * sizeof(*entry_p)); + if(tmperr) + err=tmperr; + rsbac_kfree(entry_p); + } + else + if(count < 0) + err=count; + } + } + break; + + case ACLGS_add_member: +#ifdef CONFIG_RSBAC_SWITCH_ACL + if(rsbac_switch_acl) +#endif + { + err = rsbac_acl_get_group_entry(ta_number, arg.add_member.group, &entry); + if(err) + break; + if(entry.owner != caller) + { + rsbac_printk(KERN_INFO + "rsbac_acl_group(): adding group member to group %u denied for user %u - not owner!\n", + entry.id, + caller); + err = -EPERM; + break; + } + } +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(arg.add_member.user) == RSBAC_UM_VIRTUAL_KEEP) + arg.add_member.user = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(arg.add_member.user)); + else + if (RSBAC_UID_SET(arg.add_member.user) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + arg.add_member.user = RSBAC_UID_NUM(arg.add_member.user); +#endif + err = rsbac_acl_add_group_member(ta_number, + arg.add_member.group, + arg.add_member.user, + arg.add_member.ttl); + break; + + case ACLGS_remove_member: +#ifdef CONFIG_RSBAC_SWITCH_ACL + if(rsbac_switch_acl) +#endif + { + err = rsbac_acl_get_group_entry(ta_number, arg.remove_member.group, &entry); + if(err) + break; + if(entry.owner != caller) + { + rsbac_printk(KERN_INFO + "rsbac_acl_group(): removing group member from group %u denied for user %u - not owner!\n", + entry.id, + caller); + err = -EPERM; + break; + } + } +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(arg.remove_member.user) == RSBAC_UM_VIRTUAL_KEEP) + arg.remove_member.user = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(arg.remove_member.user)); + else + if (RSBAC_UID_SET(arg.remove_member.user) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + arg.remove_member.user = RSBAC_UID_NUM(arg.remove_member.user); +#endif + err = rsbac_acl_remove_group_member(ta_number, arg.remove_member.group, arg.remove_member.user); + break; + + case ACLGS_get_user_groups: + { + rsbac_acl_group_id_t * group_p = NULL; + rsbac_time_t * ttl_p = NULL; + + if(arg.get_user_groups.maxnum <= 0) + { + err = -RSBAC_EINVALIDVALUE; + break; + } + if(!arg.get_user_groups.group_array) + { + err = -RSBAC_EINVALIDPOINTER; + break; + } + if(arg.get_user_groups.user == RSBAC_NO_USER) + arg.get_user_groups.user = caller; + else +#ifdef CONFIG_RSBAC_SWITCH_ACL + if(rsbac_switch_acl) +#endif + { + if(arg.get_user_groups.user != caller) + { + rsbac_printk(KERN_INFO + "rsbac_acl_group(): getting user groups for user %u denied for user %u!\n", + arg.get_user_groups.user, + caller); + err = -EPERM; + break; + } + } +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(arg.get_user_groups.user) == RSBAC_UM_VIRTUAL_KEEP) + arg.get_user_groups.user = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(arg.get_user_groups.user)); + else + if (RSBAC_UID_SET(arg.get_user_groups.user) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + arg.get_user_groups.user = RSBAC_UID_NUM(arg.get_user_groups.user); +#endif + err = rsbac_acl_get_user_groups(ta_number, arg.get_user_groups.user, &group_p, &ttl_p); + if(err>0) + { + int tmperr; + + err = rsbac_min(err, arg.get_user_groups.maxnum); + tmperr = rsbac_put_user(group_p, + arg.get_user_groups.group_array, + err * sizeof(*group_p)); + if(tmperr) + err=tmperr; + if(arg.get_user_groups.ttl_array) + { + tmperr = rsbac_put_user(ttl_p, + arg.get_user_groups.ttl_array, + err * sizeof(*ttl_p)); + if(tmperr) + err=tmperr; + } + } + if(group_p) + rsbac_kfree(group_p); + if(ttl_p) + rsbac_kfree(ttl_p); + break; + } + + case ACLGS_get_group_members: + if( (arg.get_group_members.maxnum <= 0) + || !arg.get_group_members.group + ) + { + err = -RSBAC_EINVALIDVALUE; + break; + } + if(arg.get_group_members.maxnum > RSBAC_ACL_MAX_MAXNUM) + arg.get_group_members.maxnum = RSBAC_ACL_MAX_MAXNUM; + if(!arg.get_group_members.user_array) + { + err = -RSBAC_EINVALIDPOINTER; + break; + } + err = rsbac_acl_get_group_entry(ta_number, + arg.get_group_members.group, + &entry); + if(err) + break; + if( (entry.owner != caller) + &&(entry.type != ACLG_GLOBAL) + ) + { + rsbac_printk(KERN_INFO + "rsbac_acl_group(): getting group members of group %u denied for user %u - neither owner nor global!\n", + entry.id, + caller); + err = -EPERM; + break; + } + { + rsbac_uid_t * user_array; + rsbac_time_t * ttl_array; + + user_array = rsbac_kmalloc_unlocked(sizeof(*user_array) * arg.get_group_members.maxnum); + if(!user_array) + return -RSBAC_ENOMEM; + ttl_array = rsbac_kmalloc_unlocked(sizeof(*ttl_array) * arg.get_group_members.maxnum); + if(!ttl_array) + { + rsbac_kfree(user_array); + return -RSBAC_ENOMEM; + } + + err = rsbac_acl_get_group_members(ta_number, + arg.get_group_members.group, + user_array, + ttl_array, + arg.get_group_members.maxnum); + if(err>0) + { + int tmperr; + + tmperr = rsbac_put_user(user_array, + arg.get_group_members.user_array, + err * sizeof(*user_array)); + if(tmperr) + err=tmperr; + if(arg.get_group_members.ttl_array) + { + tmperr = rsbac_put_user(ttl_array, + arg.get_group_members.ttl_array, + err * sizeof(*ttl_array)); + if(tmperr) + err=tmperr; + } + } + rsbac_kfree(user_array); + rsbac_kfree(ttl_array); + } + break; + + default: + break; + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( ( rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + || rsbac_ind_softmode[SW_ACL] + #endif + ) + && (err == -EPERM) + ) + return 0; + else + #endif + return err; + } +/* end of rsbac/adf/acl/syscalls.c */ diff --git a/rsbac/adf/adf_check.c b/rsbac/adf/adf_check.c new file mode 100644 index 000000000000..f5b04f562371 --- /dev/null +++ b/rsbac/adf/adf_check.c @@ -0,0 +1,1034 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - check for well defined requests */ +/* File: rsbac/adf/check.c */ +/* */ +/* Author and (c) 1999-2016: Amon Ott */ +/* */ +/* Last modified: 01/Aug/2016 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +enum rsbac_adf_req_ret_t +rsbac_adf_request_check(enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *attr_val_p, + rsbac_uid_t owner) +{ + switch (request) { + case R_SEARCH: + switch (target) { + case T_DIR: + case T_FILE: + case T_SYMLINK: + case T_FIFO: + case T_UNIXSOCK: + case T_DEV: + case T_NETOBJ: +#if defined(CONFIG_RSBAC_UM) + case T_USER: + case T_GROUP: +#endif + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_CLOSE: /* only notifying for clean-up of opened-tables */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_UNIXSOCK: + case T_DEV: + case T_IPC: + case T_NETOBJ: + return DO_NOT_CARE; + default: + return UNDEFINED; + } + + case R_GET_STATUS_DATA: + switch (target) { + case T_PROCESS: + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_DEV: + case T_IPC: + case T_SCD: + case T_NETDEV: + case T_NETOBJ: +#if defined(CONFIG_RSBAC_UM) + case T_USER: + case T_GROUP: +#endif + return DO_NOT_CARE; + default: + return UNDEFINED; + } + + case R_READ: + switch (target) { + case T_DIR: +#ifdef CONFIG_RSBAC_RW + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + case T_DEV: + case T_IPC: +#endif +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETTEMP: +#endif +#if defined(CONFIG_RSBAC_NET_OBJ_RW) + case T_NETOBJ: +#endif +#if defined(CONFIG_RSBAC_UM) + case T_USER: + case T_GROUP: +#endif + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_GET_PERMISSIONS_DATA: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: + case T_SCD: + case T_DEV: + case T_NETOBJ: +#if defined(CONFIG_RSBAC_UM) + case T_USER: + case T_GROUP: +#endif + return DO_NOT_CARE; + default: + return UNDEFINED; + }; + + case R_MAP_EXEC: + switch (target) { + case T_FILE: + case T_NONE: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_SEND: + switch (target) { + case T_DEV: + case T_UNIXSOCK: + case T_IPC: + case T_PROCESS: +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETOBJ: +#endif + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_RECEIVE: + switch (target) { + case T_UNIXSOCK: + case T_IPC: + case T_PROCESS: +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETOBJ: +#endif + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_LISTEN: + case R_ACCEPT: + case R_CONNECT: + case R_NET_SHUTDOWN: + switch (target) { + case T_UNIXSOCK: + case T_IPC: +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETOBJ: +#endif + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_EXECUTE: + switch (target) { + case T_FILE: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_READ_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_IPC: + case T_DEV: + case T_UNIXSOCK: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_WRITE: + switch (target) { + case T_DIR: + case T_UNIXSOCK: + case T_SCD: + case T_IPC: +#ifdef CONFIG_RSBAC_RW + case T_FILE: + case T_FIFO: + case T_DEV: +#endif +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETTEMP: +#endif +#if defined(CONFIG_RSBAC_NET_OBJ_RW) + case T_NETOBJ: +#endif +#if defined(CONFIG_RSBAC_UM) + case T_USER: + case T_GROUP: +#endif + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_APPEND_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_DEV: + case T_UNIXSOCK: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_READ_WRITE_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_IPC: + case T_DEV: + case T_UNIXSOCK: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_WRITE_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_IPC: + case T_DEV: + case T_UNIXSOCK: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_IOCTL: + switch (target) { + case T_UNIXSOCK: + case T_IPC: + case T_DEV: +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETOBJ: +#endif + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_MOVETO: + switch (target) { + case T_DIR: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_ADD_TO_KERNEL: + switch (target) { + case T_FILE: + case T_DEV: + case T_NONE: + return DO_NOT_CARE; + default: + return UNDEFINED; + } + + case R_ALTER: + /* only for IPC */ + if (target == T_IPC) + return DO_NOT_CARE; + else + /* all other targets are undefined */ + return UNDEFINED; + break; + + case R_CHANGE_GROUP: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: + case T_PROCESS: + case T_NONE: +#if defined(CONFIG_RSBAC_UM) + case T_USER: +#endif + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + +#ifdef CONFIG_RSBAC_DAC_GROUP + case R_CHANGE_DAC_EFF_GROUP: + case R_CHANGE_DAC_FS_GROUP: + switch (target) { + case T_PROCESS: + /* there must be a new group specified */ + if (attr == A_group) + return DO_NOT_CARE; + /* fall through */ + /* all other cases are undefined */ + default: + return UNDEFINED; + } +#endif + + case R_CHANGE_OWNER: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: + return DO_NOT_CARE; + case T_PROCESS: + /* there must be a new owner specified */ + if (attr == A_owner) + return DO_NOT_CARE; + else + return UNDEFINED; + /* all other cases are undefined */ +#ifdef CONFIG_RSBAC_USER_CHOWN + case T_USER: + /* there must be a new owner specified */ + if (attr == A_process) + return DO_NOT_CARE; + else + return UNDEFINED; + /* all other cases are undefined */ +#endif + default: + return UNDEFINED; + } + +#ifdef CONFIG_RSBAC_DAC_OWNER + case R_CHANGE_DAC_EFF_OWNER: + case R_CHANGE_DAC_FS_OWNER: + switch (target) { + case T_PROCESS: + /* there must be a new owner specified */ + if (attr == A_owner) + return DO_NOT_CARE; + /* fall through */ + /* all other cases are undefined */ + default: + return UNDEFINED; + } +#endif + + case R_CHDIR: + switch (target) { + case T_DIR: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_CLONE: + if (target == T_PROCESS) + return DO_NOT_CARE; + else + return UNDEFINED; + + case R_CREATE: + switch (target) { + /* Creating dir or (pseudo) file IN target dir! */ + case T_DIR: + case T_IPC: +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETTEMP: + case T_NETOBJ: +#endif +#if defined(CONFIG_RSBAC_UM) + case T_USER: + case T_GROUP: +#endif + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_DELETE: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: +#if defined(CONFIG_RSBAC_UM) + case T_USER: + case T_GROUP: +#endif +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETTEMP: + case T_NETOBJ: +#endif + return DO_NOT_CARE; + default: + return UNDEFINED; + } + + case R_LINK_HARD: + switch (target) { + case T_FILE: + case T_UNIXSOCK: + case T_FIFO: + case T_SYMLINK: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_MODIFY_ACCESS_DATA: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_AUTHENTICATE: + switch (target) { + case T_USER: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_MODIFY_ATTRIBUTE: + return DO_NOT_CARE; + + case R_MODIFY_PERMISSIONS_DATA: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: + case T_SCD: + case T_DEV: + case T_NETOBJ: +#if defined(CONFIG_RSBAC_UM) + case T_USER: + case T_GROUP: +#endif + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_MODIFY_SYSTEM_DATA: + switch (target) { + case T_UNIXSOCK: + case T_IPC: + case T_SCD: + case T_DEV: + case T_NETDEV: + case T_PROCESS: +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETOBJ: +#endif + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_MOUNT: + switch (target) { + case T_FILE: + case T_DIR: + case T_DEV: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_READ_ATTRIBUTE: + return DO_NOT_CARE; + + case R_REMOVE_FROM_KERNEL: + switch (target) { + case T_FILE: + case T_DEV: + case T_NONE: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_RENAME: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: +#if defined(CONFIG_RSBAC_UM) + case T_USER: + case T_GROUP: +#endif + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_SEND_SIGNAL: + switch (target) { + case T_PROCESS: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_SHUTDOWN: + switch (target) { + case T_NONE: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + + case R_SWITCH_LOG: + switch (target) { + case T_NONE: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_SWITCH_MODULE: + switch (target) { + case T_NONE: + /* there must be a switch target specified */ + if (attr == A_switch_target) + return DO_NOT_CARE; + /* fall through */ + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + /* notify only, handled by adf-dispatcher */ + case R_TERMINATE: + if (target == T_PROCESS) + return DO_NOT_CARE; + else + return UNDEFINED; + + case R_TRACE: + switch (target) { + case T_PROCESS: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_TRUNCATE: + switch (target) { + case T_FILE: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_UMOUNT: + switch (target) { + case T_FILE: + case T_DIR: + case T_DEV: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + + case R_BIND: + switch (target) { + case T_IPC: + return DO_NOT_CARE; +#if defined(CONFIG_RSBAC_NET_DEV) + case T_NETDEV: + return DO_NOT_CARE; +#endif +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETOBJ: + return DO_NOT_CARE; +#endif + /* all other cases are undefined */ + default: + return UNDEFINED; + } + + case R_LOCK: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: + return DO_NOT_CARE; + /* all other cases are undefined */ + default: + return UNDEFINED; + } + +/*********************/ + default: + return UNDEFINED; + } + + return UNDEFINED; +} /* end of rsbac_adf_request_check() */ + + +/*****************************************************************************/ +/* If the request returned granted and the operation is performed, */ +/* the following function can be called by the AEF to get all aci set */ +/* correctly. For write accesses that are performed fully within the kernel, */ +/* this is usually not done to prevent extra calls, including R_CLOSE for */ +/* cleaning up. Because of this, the write boundary is not adjusted - there */ +/* is no user-level writing anyway... */ +/* The second instance of target specification is the new target, if one has */ +/* been created, otherwise its values are ignored. */ +/* On success, 0 is returned, and an error from rsbac/error.h otherwise. */ + +int rsbac_adf_set_attr_check(enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + switch (request) { + case R_CLOSE: /* only notifying for clean-up of opened-tables */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_UNIXSOCK: + case T_DEV: + case T_IPC: + case T_NETOBJ: + return 0; + default: + return -RSBAC_EINVALIDTARGET; + }; + + case R_APPEND_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + case T_DEV: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_CHANGE_OWNER: + switch (target) { + /* Changing process owner affects access decisions, */ + /* so attributes have to be adjusted. */ + case T_PROCESS: + /* there must be a new owner specified */ + if (attr != A_owner) + return -RSBAC_EINVALIDATTR; + /* fall through */ + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: + case T_NONE: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + +#ifdef CONFIG_RSBAC_DAC_OWNER + case R_CHANGE_DAC_EFF_OWNER: + case R_CHANGE_DAC_FS_OWNER: + switch (target) { + /* Changing process owner affects access decisions, */ + /* so attributes have to be adjusted. */ + case T_PROCESS: + /* there must be a new owner specified */ + if (attr != A_owner) + return -RSBAC_EINVALIDATTR; + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } +#endif + + case R_CHDIR: + switch (target) { + case T_DIR: + return 0; + default: + return -RSBAC_EINVALIDTARGET; + }; + + case R_CLONE: + if (target == T_PROCESS) + return 0; + else + return -RSBAC_EINVALIDTARGET; + + case R_CREATE: + switch (target) { + /* Creating dir or (pseudo) file IN target dir! */ + case T_DIR: + case T_IPC: +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETOBJ: +#endif +#if defined(CONFIG_RSBAC_UM) + case T_USER: + case T_GROUP: +#endif + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + /* removal of targets is done in main adf dispatcher! */ + case R_DELETE: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: +#if defined(CONFIG_RSBAC_UM) + case T_USER: + case T_GROUP: +#endif + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_EXECUTE: + switch (target) { + case T_FILE: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_SEND: + case R_RECEIVE: + switch (target) { + case T_UNIXSOCK: + case T_IPC: + case T_PROCESS: +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETOBJ: +#endif + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_BIND: + case R_LISTEN: + case R_ACCEPT: + case R_CONNECT: + case R_NET_SHUTDOWN: + switch (target) { + case T_UNIXSOCK: + case T_IPC: +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETOBJ: +#endif + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_MODIFY_SYSTEM_DATA: + switch (target) { + case T_SCD: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_MOUNT: + switch (target) { + case T_DIR: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_READ: + switch (target) { + case T_DIR: +#ifdef CONFIG_RSBAC_RW + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + case T_DEV: + case T_IPC: +#endif +#if defined(CONFIG_RSBAC_NET_OBJ_RW) || defined(CONFIG_RSBAC_MS_SOCK) + case T_NETOBJ: +#endif + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_READ_OPEN: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_IPC: + case T_DEV: + case T_UNIXSOCK: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_READ_WRITE_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_IPC: + case T_DEV: + case T_UNIXSOCK: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_RENAME: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_SEARCH: + switch (target) { + case T_DIR: + case T_FILE: + case T_SYMLINK: + case T_FIFO: + case T_UNIXSOCK: + case T_DEV: + case T_NETOBJ: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + +#if defined(CONFIG_RSBAC_NET_OBJ) + case R_SHUTDOWN: + switch (target) { + case T_NETOBJ: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } +#endif + + case R_TRACE: + switch (target) { + case T_PROCESS: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_TRUNCATE: + switch (target) { + case T_FILE: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + +#ifdef CONFIG_RSBAC_RW + case R_WRITE: + switch (target) { + case T_FILE: + case T_FIFO: + case T_DEV: + case T_UNIXSOCK: + case T_IPC: + case T_NETOBJ: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } +#endif + + case R_WRITE_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_DEV: + case T_UNIXSOCK: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + case R_MAP_EXEC: + switch (target) { + case T_FILE: + case T_NONE: + return 0; + /* all other cases are undefined */ + default: + return -RSBAC_EINVALIDTARGET; + } + + + default: + return -RSBAC_EINVALIDTARGET; + } + + return -RSBAC_EINVALIDTARGET; +} diff --git a/rsbac/adf/adf_main.c b/rsbac/adf/adf_main.c new file mode 100644 index 000000000000..6be0bb99cfae --- /dev/null +++ b/rsbac/adf/adf_main.c @@ -0,0 +1,3654 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - Main file main.c */ +/* */ +/* Author and (c) 1999-2017: Amon Ott */ +/* */ +/* Last modified: 11/Jul/2017 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_RSBAC_UM_EXCL) +#include +#endif + +#ifdef CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT +#include +#endif + +#ifdef CONFIG_RSBAC_SECDEL +#include +#include +#include +#include +#endif /* SECDEL */ + +#ifdef CONFIG_RSBAC_MPROTECT +#include +#endif + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +__u64 rsbac_adf_request_count[T_NONE+1] = {0,0,0,0,0,0,0,0}; +__u64 rsbac_adf_set_attr_count[T_NONE+1] = {0,0,0,0,0,0,0,0}; +#ifdef CONFIG_RSBAC_XSTATS +__u64 rsbac_adf_request_xcount[T_NONE+1][R_NONE]; +__u64 rsbac_adf_set_attr_xcount[T_NONE+1][R_NONE]; +#endif + +/******* MAC ********/ +#ifdef CONFIG_RSBAC_SWITCH_MAC +rsbac_boolean_t rsbac_switch_mac = TRUE; +#endif /* MAC */ + +/******* DAZ ********/ +#ifdef CONFIG_RSBAC_SWITCH_DAZ +rsbac_boolean_t rsbac_switch_daz = TRUE; +#endif /* DAZ */ + +/******* FF ********/ +#ifdef CONFIG_RSBAC_SWITCH_FF +rsbac_boolean_t rsbac_switch_ff = TRUE; +#endif /* FF */ + +/******* RC ********/ +#ifdef CONFIG_RSBAC_SWITCH_RC +rsbac_boolean_t rsbac_switch_rc = TRUE; +#endif /* RC */ + +/****** AUTH *******/ +#ifdef CONFIG_RSBAC_SWITCH_AUTH +rsbac_boolean_t rsbac_switch_auth = TRUE; +#endif /* AUTH */ + +/****** ACL *******/ +#ifdef CONFIG_RSBAC_SWITCH_ACL +rsbac_boolean_t rsbac_switch_acl = TRUE; +#endif /* ACL */ + +/****** CAP *******/ +#ifdef CONFIG_RSBAC_SWITCH_CAP +rsbac_boolean_t rsbac_switch_cap = TRUE; +#endif /* CAP */ + +/****** JAIL *******/ +#ifdef CONFIG_RSBAC_SWITCH_JAIL +rsbac_boolean_t rsbac_switch_jail = TRUE; +#endif /* JAIL */ + +/****** PAX ********/ +#ifdef CONFIG_RSBAC_SWITCH_PAX +rsbac_boolean_t rsbac_switch_pax = TRUE; +#endif /* PAX */ + +/****** RES *******/ +#ifdef CONFIG_RSBAC_SWITCH_RES +rsbac_boolean_t rsbac_switch_res = TRUE; +#endif /* RES */ + +/******* UDF ********/ +#ifdef CONFIG_RSBAC_SWITCH_UDF +rsbac_boolean_t rsbac_switch_udf = TRUE; +#endif /* UDF */ + +/******* MPROTECT ********/ +#ifdef CONFIG_RSBAC_SWITCH_MPROTECT +rsbac_boolean_t rsbac_switch_mprotect = TRUE; +#endif /* MPROTECT */ + + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +/* Init function, calls inits for all sub-modules */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +void rsbac_init_adf(void) +#else +void __init rsbac_init_adf(void) +#endif + { + #if defined(CONFIG_RSBAC_REG) + rsbac_reg_init(); + #endif + } + +enum rsbac_adf_req_ret_t + adf_and_plus(enum rsbac_adf_req_ret_t res1, + enum rsbac_adf_req_ret_t res2) + { + switch (res1) + { + case DO_NOT_CARE: return (res2); + case GRANTED: if (res2 == DO_NOT_CARE) + return (GRANTED); + else + return (res2); + case NOT_GRANTED: if (res2 == UNDEFINED) + return (UNDEFINED); + else + return (NOT_GRANTED); + default: return (UNDEFINED); + } + } + +/* + * rsbac_adf_request_int() + * This function is the main decision function, called though the + * rsbac_adf_request wrapper from the AEF. + */ + +EXPORT_SYMBOL(rsbac_adf_request_int); +enum rsbac_adf_req_ret_t + rsbac_adf_request_int(enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t * tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t * attr_val_p, + enum rsbac_switch_target_t ignore_module) + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val; + rsbac_uid_t owner=0; + int tmperr=0; + rsbac_request_vector_t request_vector; + enum rsbac_adf_req_ret_t result = DO_NOT_CARE; +#ifdef CONFIG_RSBAC_SOFTMODE_IND + enum rsbac_adf_req_ret_t ret_result = DO_NOT_CARE; +#endif + rsbac_enum_t mod_result[SW_NONE + 1] = { + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE, + DO_NOT_CARE + }; + rsbac_boolean_t do_log = FALSE; + rsbac_boolean_t log_on_request = TRUE; +/* only if individual logging is enabled */ +#if defined(CONFIG_RSBAC_IND_LOG) || defined(CONFIG_RSBAC_IND_NETDEV_LOG) || defined(CONFIG_RSBAC_IND_NETOBJ_LOG) + union rsbac_attribute_value_t i_attr_val2; + enum rsbac_log_level_t log_level; +#endif + struct vfsmount * mnt_p; +#ifdef CONFIG_RSBAC_SOFTMODE + rsbac_boolean_t rsbac_internal = FALSE; +#endif + +/* No decision possible before init (called at boot time) -> don't care */ + if (unlikely(!rsbac_is_initialized())) + return DO_NOT_CARE; + +/* Always granted for kernel (pid 0) and logging daemon */ + if ( !pid_nr(caller_pid) + #if defined(CONFIG_RSBAC_LOG_REMOTE) + || (pid_nr(caller_pid) == pid_nr(rsbaclogd_pid)) + #endif + ) + return GRANTED; + +/* Checking base values */ + if(unlikely( request >= R_NONE + || target > T_NONE + || attr > A_none) + ) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_request_int(): called with invalid request, target or attribute\n"); + return NOT_GRANTED; + } + request_vector = RSBAC_REQUEST_VECTOR(request); + + if (unlikely(in_interrupt())) + { + char * request_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(request_name) + { + get_request_name(request_name, request); + printk(KERN_WARNING "rsbac_adf_request_int(): called from interrupt: request %s, pid %u(%s), attr_val %u!\n", + request_name, pid_nr(caller_pid), current->comm, attr_val_p->dummy); + rsbac_kfree(request_name); + } + else + { + printk(KERN_WARNING "rsbac_adf_request_int(): called from interrupt: request %u, pid %u(%s)!\n", + request, pid_nr(caller_pid), current->comm); + } + dump_stack(); + return DO_NOT_CARE; + } + +/* Getting basic information about this request */ + + /* only useful for real process, not idle or init */ + if (pid_nr(caller_pid) > 1) + { + tmperr = rsbac_get_owner(&owner); + if(tmperr) + { + rsbac_printk(KERN_DEBUG + "rsbac_adf_request_int(): caller_pid %i, RSBAC not initialized, returning DO_NOT_CARE\n", + pid_nr(caller_pid)); + return DO_NOT_CARE; /* Startup-Sequence (see above) */ + } + } + else /* caller_pid = 1 -> init, always owned by root */ + { + owner = 0; + } + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if ((attr == A_owner) && (RSBAC_UID_SET(attr_val_p->owner) > RSBAC_UM_VIRTUAL_MAX)) + attr_val_p->owner = RSBAC_GEN_UID(RSBAC_UID_SET(owner), attr_val_p->owner); + else + if ((attr == A_group) && (RSBAC_GID_SET(attr_val_p->group) > RSBAC_UM_VIRTUAL_MAX)) + attr_val_p->group = RSBAC_GEN_GID(RSBAC_UID_SET(owner), attr_val_p->group); +#else + if (attr == A_owner) + attr_val_p->owner = RSBAC_UID_NUM(attr_val_p->owner); + else + if (attr == A_group) + attr_val_p->group = RSBAC_GID_NUM(attr_val_p->group); +#endif + +/******************************************************/ +/* General work for all modules - before module calls */ + /* test target on rsbac_internal */ + switch(target) + { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: +#ifdef CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT + if ( ((mnt_p = rsbac_get_vfsmount(tid_p->file.device))) + && ( (mnt_p->mnt_sb->s_magic == NFS_SUPER_MAGIC) + || (mnt_p->mnt_sb->s_magic == CODA_SUPER_MAGIC) + || (mnt_p->mnt_sb->s_magic == NCP_SUPER_MAGIC) + || (mnt_p->mnt_sb->s_magic == SMB_SUPER_MAGIC) + ) + ) + { + result = DO_NOT_CARE; + goto log; + } +#endif + /* No decision on pseudo pipefs */ + if( (target == T_FIFO) + && ((mnt_p = rsbac_get_vfsmount(tid_p->file.device))) + && (mnt_p->mnt_sb->s_magic == PIPEFS_MAGIC) + ) + return DO_NOT_CARE; + + switch(request) + { + case R_GET_STATUS_DATA: + case R_GET_PERMISSIONS_DATA: + case R_READ_ATTRIBUTE: +#ifdef CONFIG_RSBAC_DAT_VISIBLE + case R_SEARCH: + case R_READ: + case R_CLOSE: + case R_CHDIR: +#endif + break; + + default: + if ((tmperr = rsbac_get_attr(SW_GEN, + target, + *tid_p, + A_internal, + &i_attr_val, + TRUE) )) + { + if(tmperr == -RSBAC_EINVALIDDEV) + { +// rsbac_ds_get_error_num("rsbac_adf_request()", A_internal, tmperr); + return DO_NOT_CARE; /* last calls on shutdown */ + } + else + { + rsbac_ds_get_error_num("rsbac_adf_request()", A_internal, tmperr); + return NOT_GRANTED; /* something weird happened */ + } + } + /* no access to rsbac_internal objects is granted in any case */ + if (i_attr_val.internal) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_request(): trial to access object declared RSBAC-internal!\n"); + result = NOT_GRANTED; + mod_result[SW_NONE] = NOT_GRANTED; + #ifdef CONFIG_RSBAC_SOFTMODE + #ifdef CONFIG_RSBAC_SOFTMODE_IND + ret_result = NOT_GRANTED; + #endif + rsbac_internal = TRUE; + #endif + } + } + +#if defined(CONFIG_RSBAC_UM_VIRTUAL_ISOLATE) + if (attr == A_vset && (RSBAC_UID_SET(owner))) { + result = adf_and_plus(result, NOT_GRANTED); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + ret_result = adf_and_plus(ret_result, NOT_GRANTED); +#endif + } +#endif + + break; + +#if defined(CONFIG_RSBAC_UM_EXCL) || defined(CONFIG_RSBAC_UM_VIRTUAL_ISOLATE) + case T_PROCESS: +#if defined(CONFIG_RSBAC_UM_EXCL) + switch(request) + { + case R_CHANGE_OWNER: +#ifdef CONFIG_RSBAC_DAC_OWNER + case R_CHANGE_DAC_EFF_OWNER: + case R_CHANGE_DAC_FS_OWNER: +#endif + if( (attr == A_owner) + && !rsbac_um_no_excl + && !rsbac_um_user_exists(0, attr_val_p->owner) + ) + { + rsbac_printk(KERN_INFO + "rsbac_adf_request(): uid %u not known to RSBAC User Management!\n", + attr_val_p->owner); + result = adf_and_plus(result, NOT_GRANTED); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + ret_result = adf_and_plus(ret_result, NOT_GRANTED); +#endif + } + break; + + case R_CHANGE_GROUP: +#ifdef CONFIG_RSBAC_DAC_OWNER + case R_CHANGE_DAC_EFF_GROUP: + case R_CHANGE_DAC_FS_GROUP: +#endif + if( (attr == A_group) + && !rsbac_um_no_excl + && !rsbac_um_group_exists(0, attr_val_p->group) + ) + { + rsbac_printk(KERN_INFO + "rsbac_adf_request(): gid %u not known to RSBAC User Management!\n", + attr_val_p->group); + result = adf_and_plus(result, NOT_GRANTED); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + ret_result = adf_and_plus(ret_result, NOT_GRANTED); +#endif + } + break; + + default: + break; + } +#endif +#if defined(CONFIG_RSBAC_UM_VIRTUAL_ISOLATE) + if (attr == A_vset && (RSBAC_UID_SET(owner))) { + result = adf_and_plus(result, NOT_GRANTED); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + ret_result = adf_and_plus(ret_result, NOT_GRANTED); +#endif + } +#endif + break; +#endif /* UM_EXCL || UM_VIRTUAL_ISOLATE */ + +#if defined(CONFIG_RSBAC_UM_VIRTUAL_ISOLATE) + case T_USER: + if( RSBAC_UID_SET(owner) + && (RSBAC_UID_SET(owner) != RSBAC_UID_SET(tid_p->user)) + ) { + if (RSBAC_UID_SET(tid_p->user) == RSBAC_UM_VIRTUAL_ALL) + tid_p->user = RSBAC_GEN_UID(RSBAC_UID_SET(owner), tid_p->user); + else { + result = adf_and_plus(result, NOT_GRANTED); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + ret_result = adf_and_plus(ret_result, NOT_GRANTED); +#endif + } + } + break; + case T_GROUP: + if( RSBAC_UID_SET(owner) + && (RSBAC_UID_SET(owner) != RSBAC_GID_SET(tid_p->group)) + ) { + if (RSBAC_UID_SET(tid_p->user) == RSBAC_UM_VIRTUAL_ALL) + tid_p->user = RSBAC_GEN_UID(RSBAC_UID_SET(owner), tid_p->user); + else { + result = adf_and_plus(result, NOT_GRANTED); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + ret_result = adf_and_plus(ret_result, NOT_GRANTED); +#endif + } + } + break; +#endif + +#ifdef CONFIG_RSBAC_NET_OBJ +#if defined(CONFIG_RSBAC_IND_NETOBJ_LOG) || defined(CONFIG_RSBAC_MAC) || defined(CONFIG_RSBAC_RC) + case T_NETOBJ: + if(rsbac_net_remote_request(request)) { + tid_p->netobj.local_temp = 0; + rsbac_ta_net_lookup_templates(0, + &tid_p-> + netobj, NULL, + &tid_p->netobj.remote_temp); + } else { + tid_p->netobj.remote_temp = 0; + rsbac_ta_net_lookup_templates(0, + &tid_p-> + netobj, + &tid_p->netobj.local_temp, + NULL); + } +#endif +#endif + + default: + break; + } + +/**********************************************************/ +/* calling all decision modules, building a common result */ + +#ifdef CONFIG_RSBAC_DEBUG +/* first, check for valid request/target combination */ +/* (undefined should only happen in _check and means a real bug!) */ + result = adf_and_plus(result,rsbac_adf_request_check(request, + caller_pid, + target, + tid_p, + attr, + attr_val_p, + owner) ); +#endif + +/******* MAC ********/ +#if defined(CONFIG_RSBAC_MAC) +#ifdef CONFIG_RSBAC_SWITCH_MAC +if (rsbac_switch_mac) +#endif + /* no need to call module, if to be ignored */ + if(ignore_module != SW_MAC && (request_vector & RSBAC_MAC_REQUEST_VECTOR)) { + mod_result[SW_MAC] = rsbac_adf_request_mac(request, + caller_pid, + target, + *tid_p, + attr, + *attr_val_p, + owner); + result = adf_and_plus(result, mod_result[SW_MAC]); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(!rsbac_ind_softmode[SW_MAC]) + ret_result = adf_and_plus(ret_result, mod_result[SW_MAC]); +#endif + } +#endif /* MAC */ + +/******* DAZ ********/ +#if defined(CONFIG_RSBAC_DAZ) +#ifdef CONFIG_RSBAC_SWITCH_DAZ +if (rsbac_switch_daz) +#endif + /* no need to call module, if to be ignored */ + if(ignore_module != SW_DAZ && (request_vector & RSBAC_DAZ_REQUEST_VECTOR)) + { + mod_result[SW_DAZ] = rsbac_adf_request_daz (request, + caller_pid, + target, + *tid_p, + attr, + *attr_val_p, + owner); + result = adf_and_plus(result, mod_result[SW_DAZ]); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(!rsbac_ind_softmode[SW_DAZ]) + ret_result = adf_and_plus(ret_result, mod_result[SW_DAZ]); +#endif + } +#endif /* DAZ */ + +/******* FF ********/ +#if defined(CONFIG_RSBAC_FF) +#ifdef CONFIG_RSBAC_SWITCH_FF +if (rsbac_switch_ff) +#endif + /* no need to call module, if to be ignored */ + if(ignore_module != SW_FF && (request_vector & RSBAC_FF_REQUEST_VECTOR)) + { + mod_result[SW_FF] = rsbac_adf_request_ff (request, + caller_pid, + target, + *tid_p, + attr, + *attr_val_p, + owner); + result = adf_and_plus(result, mod_result[SW_FF]); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(!rsbac_ind_softmode[SW_FF]) + ret_result = adf_and_plus(ret_result, mod_result[SW_FF]); +#endif + } +#endif /* FF */ + +/******* RC ********/ +#if defined(CONFIG_RSBAC_RC) +#ifdef CONFIG_RSBAC_SWITCH_RC +if (rsbac_switch_rc) +#endif + /* no need to call module, if to be ignored */ + if(ignore_module != SW_RC) + { + mod_result[SW_RC] = rsbac_adf_request_rc (request, + caller_pid, + target, + *tid_p, + attr, + *attr_val_p, + owner); + result = adf_and_plus(result, mod_result[SW_RC]); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(!rsbac_ind_softmode[SW_RC]) + ret_result = adf_and_plus(ret_result, mod_result[SW_RC]); +#endif + } +#endif /* RC */ + +/****** AUTH *******/ +#if defined(CONFIG_RSBAC_AUTH) +#ifdef CONFIG_RSBAC_SWITCH_AUTH +if (rsbac_switch_auth) +#endif + /* no need to call module, if to be ignored */ + if(ignore_module != SW_AUTH && (request_vector & RSBAC_AUTH_REQUEST_VECTOR)) + { + mod_result[SW_AUTH]= rsbac_adf_request_auth(request, + caller_pid, + target, + *tid_p, + attr, + *attr_val_p, + owner); + result = adf_and_plus(result, mod_result[SW_AUTH]); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(!rsbac_ind_softmode[SW_AUTH]) + ret_result = adf_and_plus(ret_result, mod_result[SW_AUTH]); +#endif + } +#endif /* AUTH */ + +/****** ACL *******/ +#if defined(CONFIG_RSBAC_ACL) +#ifdef CONFIG_RSBAC_SWITCH_ACL +if (rsbac_switch_acl) +#endif + /* no need to call module, if to be ignored */ + if(ignore_module != SW_ACL) + { + mod_result[SW_ACL] = rsbac_adf_request_acl(request, + caller_pid, + target, + *tid_p, + attr, + *attr_val_p, + owner); + result = adf_and_plus(result, mod_result[SW_ACL]); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(!rsbac_ind_softmode[SW_ACL]) + ret_result = adf_and_plus(ret_result, mod_result[SW_ACL]); +#endif + } +#endif /* ACL */ + +/****** CAP *******/ +#if defined(CONFIG_RSBAC_CAP) +#ifdef CONFIG_RSBAC_SWITCH_CAP +if (rsbac_switch_cap) +#endif + /* no need to call module, if to be ignored */ + if(ignore_module != SW_CAP && (request_vector & RSBAC_CAP_REQUEST_VECTOR)) + { + mod_result[SW_CAP] = rsbac_adf_request_cap(request, + caller_pid, + target, + *tid_p, + attr, + *attr_val_p, + owner); + result = adf_and_plus(result, mod_result[SW_CAP]); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(!rsbac_ind_softmode[SW_CAP]) + ret_result = adf_and_plus(ret_result, mod_result[SW_CAP]); +#endif + } +#endif /* CAP */ + +/****** JAIL *******/ +#if defined(CONFIG_RSBAC_JAIL) +#ifdef CONFIG_RSBAC_SWITCH_JAIL +if (rsbac_switch_jail) +#endif + /* no need to call module, if to be ignored */ + if(ignore_module != SW_JAIL && (request_vector & RSBAC_JAIL_REQUEST_VECTOR)) + { + mod_result[SW_JAIL]= rsbac_adf_request_jail(request, + caller_pid, + target, + *tid_p, + attr, + *attr_val_p, + owner); + result = adf_and_plus(result, mod_result[SW_JAIL]); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(!rsbac_ind_softmode[SW_JAIL]) + ret_result = adf_and_plus(ret_result, mod_result[SW_JAIL]); +#endif + } +#endif /* JAIL */ + +/******* PAX ********/ +#if defined(CONFIG_RSBAC_PAX) +#ifdef CONFIG_RSBAC_SWITCH_PAX +if (rsbac_switch_pax) +#endif + /* no need to call module, if to be ignored */ + if(ignore_module != SW_PAX && (request_vector & RSBAC_PAX_REQUEST_VECTOR)) + { + mod_result[SW_PAX] = rsbac_adf_request_pax (request, + caller_pid, + target, + *tid_p, + attr, + *attr_val_p, + owner); + result = adf_and_plus(result, mod_result[SW_PAX]); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(!rsbac_ind_softmode[SW_PAX]) + ret_result = adf_and_plus(ret_result, mod_result[SW_PAX]); +#endif + } +#endif /* PAX */ + +/****** RES *******/ +#if defined(CONFIG_RSBAC_RES) +#ifdef CONFIG_RSBAC_SWITCH_RES +if (rsbac_switch_res) +#endif + /* no need to call module, if to be ignored */ + if(ignore_module != SW_RES && (request_vector & RSBAC_RES_REQUEST_VECTOR)) + { + mod_result[SW_RES] = rsbac_adf_request_res(request, + caller_pid, + target, + *tid_p, + attr, + *attr_val_p, + owner); + result = adf_and_plus(result, mod_result[SW_RES]); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(!rsbac_ind_softmode[SW_RES]) + ret_result = adf_and_plus(ret_result, mod_result[SW_RES]); +#endif + } +#endif /* RES */ + +/******* UDF ********/ +#if defined(CONFIG_RSBAC_UDF) +#ifdef CONFIG_RSBAC_SWITCH_UDF +if (rsbac_switch_udf) +#endif + /* no need to call module, if to be ignored */ + if(ignore_module != SW_UDF && (request_vector & RSBAC_UDF_REQUEST_VECTOR)) + { + mod_result[SW_UDF] = rsbac_adf_request_udf (request, + caller_pid, + target, + *tid_p, + attr, + *attr_val_p, + owner); + result = adf_and_plus(result, mod_result[SW_UDF]); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(!rsbac_ind_softmode[SW_UDF]) + ret_result = adf_and_plus(ret_result, mod_result[SW_UDF]); +#endif + } +#endif /* UDF */ + +/****** REG *******/ +#if defined(CONFIG_RSBAC_REG) +if(ignore_module != SW_REG) + { + mod_result[SW_REG]= rsbac_adf_request_reg (request, + caller_pid, + target, + *tid_p, + attr, + *attr_val_p, + owner); + result = adf_and_plus(result, mod_result[SW_REG]); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(!rsbac_ind_softmode[SW_REG]) + ret_result = adf_and_plus(ret_result, mod_result[SW_REG]); +#endif + } +#endif /* REG */ + +/****************************/ + +#if defined(CONFIG_RSBAC_DEBUG) && defined(CONFIG_RSBAC_NET) + if( rsbac_debug_adf_net + && ( (target == T_NETDEV) + || (target == T_NETTEMP) + || (target == T_NETOBJ) + ) + ) + do_log = TRUE; +#endif + +/* log based on process owner */ +#ifdef CONFIG_RSBAC_IND_USER_LOG + i_tid.user = owner; + if (rsbac_get_attr(SW_GEN, + T_USER, + i_tid, + A_log_user_based, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request()", A_log_user_based); + } + else + { + if(((rsbac_request_vector_t) 1 << request) & i_attr_val.log_user_based) + do_log = TRUE; + } +#endif /* CONFIG_RSBAC_IND_USER_LOG */ + +/* log based on program */ +#ifdef CONFIG_RSBAC_IND_PROG_LOG + if(!do_log) + { + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_GEN, + T_PROCESS, + i_tid, + A_log_program_based, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request()", A_log_program_based); + } + else + { + if(((rsbac_request_vector_t) 1 << request) & i_attr_val.log_program_based) + do_log = TRUE; + } + } +#endif /* CONFIG_RSBAC_IND_PROG_LOG */ + +/*****************************************************/ +/* General work for all modules - after module calls */ +/* Note: the process' individual logging attributes are needed above */ + switch(request) + { + case R_TERMINATE: + if (target == T_PROCESS) + rsbac_remove_target(T_PROCESS,*tid_p); + break; + +#ifdef CONFIG_RSBAC_USER_CHOWN + case R_CHANGE_OWNER: + if (target == T_PROCESS) { + i_tid.user = attr_val_p->owner; + i_attr_val.process = tid_p->process; + result = adf_and_plus(result, + rsbac_adf_request_int(request, + caller_pid, + T_USER, + &i_tid, + A_process, + &i_attr_val, + ignore_module)); + } + break; +#endif + + default: + break; + } + +/* logging request on info level, if requested by file/dir/dev attributes */ +/* log_array_low/high, or, if that is requested, if enabled for this request */ +/* type (attributes state level, or that request based level is to be taken) */ +/* loglevel 2: log everything */ +/* loglevel 1: log, if denied */ +/* loglevel 0: log nothing */ + +#ifdef CONFIG_RSBAC_IND_LOG /* only if individual logging is enabled */ + /* if file/dir/dev, depend log on log_arrays */ + /* (but not for file.device = 0) */ + /* log_on_request is TRUE */ + if( !do_log + && ( ( ( (target == T_FILE) + || (target == T_DIR) + || (target == T_FIFO) + || (target == T_SYMLINK) + || (target == T_UNIXSOCK) + ) + && RSBAC_MAJOR(tid_p->file.device) + && RSBAC_MINOR(tid_p->file.device) + ) + || (target == T_DEV) + ) + ) + { + if (rsbac_get_attr(SW_GEN, + target, + *tid_p, + A_log_array_low, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request()", A_log_array_low); + } + else + { + if (rsbac_get_attr(SW_GEN, + target, + *tid_p, + A_log_array_high, + &i_attr_val2, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request()", A_log_array_high); + } + else + { /* ll = low-bit for request | (high-bit for request as bit 1) */ + /* WARNING: we deal with u64 here, only logical operations and */ + /* shifts work correctly! */ + log_level = ((i_attr_val.log_array_low >> request) & 1) + | ( ((i_attr_val2.log_array_high >> request) & 1) << 1); + if ( log_level == LL_full + || ( log_level == LL_denied + && (result == NOT_GRANTED + || result == UNDEFINED)) ) + { + do_log = TRUE; + } + if(log_level != LL_request) + log_on_request = FALSE; + } + } + } +#endif /* CONFIG_RSBAC_IND_LOG */ + +#ifdef CONFIG_RSBAC_IND_NETDEV_LOG /* only if individual logging for netdev is enabled */ + /* if netdev, depend log on log_arrays */ + /* log_on_request is TRUE */ + if( !do_log + && (target == T_NETDEV) + ) + { + if (rsbac_get_attr(SW_GEN, + target, + *tid_p, + A_log_array_low, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request()", A_log_array_low); + } + else + { + if (rsbac_get_attr(SW_GEN, + target, + *tid_p, + A_log_array_high, + &i_attr_val2, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request()", A_log_array_high); + } + else + { /* ll = low-bit for request | (high-bit for request as bit 1) */ + /* WARNING: we deal with u64 here, only logical operations and */ + /* shifts work correctly! */ + log_level = ((i_attr_val.log_array_low >> request) & 1) + | ( ((i_attr_val2.log_array_high >> request) & 1) << 1); + if ( log_level == LL_full + || ( log_level == LL_denied + && (result == NOT_GRANTED + || result == UNDEFINED)) ) + { + do_log = TRUE; + } + if(log_level != LL_request) + log_on_request = FALSE; + } + } + } +#endif /* CONFIG_RSBAC_IND_NETDEV_LOG */ + +#ifdef CONFIG_RSBAC_IND_NETOBJ_LOG /* only if individual logging for net objects is enabled */ + /* if nettemp, netobj, depend log on log_arrays */ + /* (but not for file.device = 0) */ + /* log_on_request is TRUE */ + if( !do_log + && ( (target == T_NETTEMP) + || (target == T_NETOBJ) + ) + ) + { + enum rsbac_attribute_t i_attr1, i_attr2; + + if(target == T_NETOBJ) + { + if(rsbac_net_remote_request(request)) + { + i_attr1 = A_remote_log_array_low; + i_attr2 = A_remote_log_array_high; + } + else + { + i_attr1 = A_local_log_array_low; + i_attr2 = A_local_log_array_high; + } + } + else + { + i_attr1 = A_log_array_low; + i_attr2 = A_log_array_high; + } + if (rsbac_get_attr(SW_GEN, + target, + *tid_p, + i_attr1, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request()", i_attr1); + } + else + { + if (rsbac_get_attr(SW_GEN, + target, + *tid_p, + i_attr2, + &i_attr_val2, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request()", i_attr2); + } + else + { /* ll = low-bit for request | (high-bit for request as bit 1) */ + /* WARNING: we deal with u64 here, only logical operations and */ + /* shifts work correctly! */ + log_level = ((i_attr_val.log_array_low >> request) & 1) + | ( ((i_attr_val2.log_array_high >> request) & 1) << 1); + if ( log_level == LL_full + || ( log_level == LL_denied + && (result == NOT_GRANTED + || result == UNDEFINED)) ) + { + do_log = TRUE; + } + if(log_level != LL_request) + log_on_request = FALSE; + } + } + } +#endif /* CONFIG_RSBAC_IND_NETOBJ_LOG */ + +#ifdef CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT +log: +#endif + /* if enabled, try request based log level */ + if ( !do_log + && log_on_request + && ( rsbac_log_levels[request][target] == LL_full + || ( rsbac_log_levels[request][target] == LL_denied + && (result == NOT_GRANTED + || result == UNDEFINED)) ) ) + do_log = TRUE; + + if(do_log) + { + char * request_name; + char * res_name; + char * res_mods; + char * target_type_name; + char * target_id_name; + char * attr_name; + char * attr_val_name; +#ifdef CONFIG_RSBAC_NET_OBJ + char * remote_ip_name; +#else + char remote_ip_name[1]; +#endif + char * audit_uid_name; + char command[17]; + rsbac_pid_t parent_pid = NULL; + rsbac_uid_t audit_uid; +#ifdef CONFIG_RSBAC_LOG_PSEUDO + rsbac_pseudo_t pseudo = 0; +#endif +#ifdef CONFIG_RSBAC_LOG_PROGRAM_FILE + struct file *file_p; +#endif + char * program_path; + + /* parent pid */ + if(current->parent) + parent_pid = get_task_pid(current->parent, PIDTYPE_PID); + + /* rsbac_kmalloc all memory */ + request_name = rsbac_kmalloc(32); + res_name = rsbac_kmalloc(32); + res_mods = rsbac_kmalloc(RSBAC_MAXNAMELEN); + target_type_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + target_id_name = rsbac_kmalloc(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + #ifdef CONFIG_RSBAC_LOG_PROGRAM_FILE + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + program_path + = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + program_path = rsbac_kmalloc(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + #else + program_path = rsbac_kmalloc(2); + #endif + attr_name = rsbac_kmalloc(32); + attr_val_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); +#ifdef CONFIG_RSBAC_NET_OBJ + remote_ip_name = rsbac_kmalloc(32); +#endif + audit_uid_name = rsbac_kmalloc(32); + + request_name[0] = (char) 0; + target_type_name[0] = (char) 0; + target_id_name[0] = (char) 0; + program_path[0] = (char) 0; + attr_name[0] = (char) 0; + attr_val_name[0] = (char) 0; + remote_ip_name[0] = (char) 0; + audit_uid_name[0] = (char) 0; + res_name[0] = (char) 0; + res_mods[0] = (char) 0; + command[0] = (char) 0; + get_request_name(request_name, request); +/* + if(result == mod_result[SW_NONE]) + { + strcat(res_mods, " SW_GEN"); + } +*/ + #if defined(CONFIG_RSBAC_MAC) + if(result == mod_result[SW_MAC]) + { + #ifdef CONFIG_RSBAC_SOFTMODE_IND + if(rsbac_ind_softmode[SW_MAC]) + strcat(res_mods, " MAC(Softmode)"); + else + #endif + strcat(res_mods, " MAC"); + } + #endif + #if defined(CONFIG_RSBAC_DAZ) + if(result == mod_result[SW_DAZ]) + { + #ifdef CONFIG_RSBAC_SOFTMODE_IND + if(rsbac_ind_softmode[SW_DAZ]) + strcat(res_mods, " DAZ(Softmode)"); + else + #endif + strcat(res_mods, " DAZ"); + } + #endif + #ifdef CONFIG_RSBAC_FF + if(result == mod_result[SW_FF]) + { + #ifdef CONFIG_RSBAC_SOFTMODE_IND + if(rsbac_ind_softmode[SW_FF]) + strcat(res_mods, " FF(Softmode)"); + else + #endif + strcat(res_mods, " FF"); + } + #endif + #ifdef CONFIG_RSBAC_RC + if(result == mod_result[SW_RC]) + { + #ifdef CONFIG_RSBAC_SOFTMODE_IND + if(rsbac_ind_softmode[SW_RC]) + strcat(res_mods, " RC(Softmode)"); + else + #endif + strcat(res_mods, " RC"); + } + #endif + #ifdef CONFIG_RSBAC_AUTH + if(result == mod_result[SW_AUTH]) + { + #ifdef CONFIG_RSBAC_SOFTMODE_IND + if(rsbac_ind_softmode[SW_AUTH]) + strcat(res_mods, " AUTH(Softmode)"); + else + #endif + strcat(res_mods, " AUTH"); + } + #endif + #ifdef CONFIG_RSBAC_ACL + if(result == mod_result[SW_ACL]) + { + #ifdef CONFIG_RSBAC_SOFTMODE_IND + if(rsbac_ind_softmode[SW_ACL]) + strcat(res_mods, " ACL(Softmode)"); + else + #endif + strcat(res_mods, " ACL"); + } + #endif + #ifdef CONFIG_RSBAC_CAP + if(result == mod_result[SW_CAP]) + { + #ifdef CONFIG_RSBAC_SOFTMODE_IND + if(rsbac_ind_softmode[SW_CAP]) + strcat(res_mods, " CAP(Softmode)"); + else + #endif + strcat(res_mods, " CAP"); + } + #endif + #ifdef CONFIG_RSBAC_JAIL + if(result == mod_result[SW_JAIL]) + { + #ifdef CONFIG_RSBAC_SOFTMODE_IND + if(rsbac_ind_softmode[SW_JAIL]) + strcat(res_mods, " JAIL(Softmode)"); + else + #endif + strcat(res_mods, " JAIL"); + } + #endif + #ifdef CONFIG_RSBAC_RES + if(result == mod_result[SW_RES]) + { + #ifdef CONFIG_RSBAC_SOFTMODE_IND + if(rsbac_ind_softmode[SW_RES]) + strcat(res_mods, " RES(Softmode)"); + else + #endif + strcat(res_mods, " RES"); + } + #endif + #if defined(CONFIG_RSBAC_UDF) + if(result == mod_result[SW_UDF]) + { + #ifdef CONFIG_RSBAC_SOFTMODE_IND + if(rsbac_ind_softmode[SW_UDF]) + strcat(res_mods, " UDF(Softmode)"); + else + #endif + strcat(res_mods, " UDF"); + } + #endif + #ifdef CONFIG_RSBAC_REG + if(result == mod_result[SW_REG]) + { + #ifdef CONFIG_RSBAC_SOFTMODE_IND + if(rsbac_ind_softmode[SW_REG]) + strcat(res_mods, " REG(Softmode)"); + else + #endif + strcat(res_mods, " REG"); + } + #endif + if(!res_mods[0]) + strcat(res_mods, " ADF"); + + /* Get process audit_uid */ + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_GEN,T_PROCESS,i_tid,A_audit_uid,&i_attr_val,FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request()", A_audit_uid); + return NOT_GRANTED; /* something weird happened */ + } + audit_uid = i_attr_val.audit_uid; + if(audit_uid == RSBAC_NO_USER) + audit_uid = owner; + else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(audit_uid)) + sprintf(audit_uid_name, "audit uid %u/%u, ", + RSBAC_UID_SET(audit_uid), + RSBAC_UID_NUM(audit_uid)); + else +#endif + sprintf(audit_uid_name, "audit uid %u, ", RSBAC_UID_NUM(audit_uid)); + } +#ifdef CONFIG_RSBAC_LOG_PSEUDO + /* Get owner's logging pseudo */ + i_tid.user = audit_uid; + if (rsbac_get_attr(SW_GEN,T_USER,i_tid,A_pseudo,&i_attr_val,FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request()", A_pseudo); + return NOT_GRANTED; /* something weird happened */ + } + /* if pseudo is not registered, return attribute value is 0 (see later) */ + pseudo = i_attr_val.pseudo; +#endif + +#ifdef CONFIG_RSBAC_NET_OBJ + /* Get process remote_ip */ + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_GEN,T_PROCESS,i_tid,A_remote_ip,&i_attr_val,FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request()", A_remote_ip); + return NOT_GRANTED; /* something weird happened */ + } + if(i_attr_val.remote_ip) + sprintf(remote_ip_name, "remote ip %u.%u.%u.%u, ", NIPQUAD(i_attr_val.remote_ip)); +#endif + +#ifdef CONFIG_RSBAC_LOG_PROGRAM_FILE + file_p = get_task_exe_file(current); + if( file_p + && file_p->f_path.dentry + ) { + char * p = program_path; + + p += sprintf(program_path, ", prog_file "); +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + rsbac_get_full_path(file_p->f_path.dentry, p, CONFIG_RSBAC_MAX_PATH_LEN); +#else + if ( file_p->f_path.dentry->d_name.len + && file_p->f_path.dentry->d_name.name + ) { + int namelen = rsbac_min(file_p->f_path.dentry->d_name.len, RSBAC_MAXNAMELEN); + + strncpy(p, file_p->f_path.dentry->d_name.name, namelen); + p[namelen]=0; + } else { + sprintf(program_name, "%s", current->comm); + } +#endif + } +#endif + + get_target_name(target_type_name, target, target_id_name, *tid_p); + get_attribute_name(attr_name, attr); + get_attribute_value_name(attr_val_name, attr, attr_val_p); + get_result_name(res_name, result); + if ((current) && (current->comm)) + { + strncpy(command,current->comm,16); + command[16] = (char) 0; + } + +#ifdef CONFIG_RSBAC_LOG_PSEUDO + /* if pseudo is set, its value is != 0, else -> use id */ + if (pseudo) + { +#ifdef CONFIG_RSBAC_SOFTMODE + if(rsbac_softmode) + rsbac_printk(KERN_INFO "rsbac_adf_request(): request %s, pid %u, ppid %u, prog_name %s%s, pseudo %u, %starget_type %s, tid %s, attr %s, value %s, result %s (Softmode) by%s\n", + request_name, pid_nr(caller_pid), parent_pid, command, program_path, pseudo, remote_ip_name, target_type_name, target_id_name, attr_name, attr_val_name, res_name, res_mods); + else +#endif + rsbac_printk(KERN_INFO "rsbac_adf_request(): request %s, pid %u, ppid %u, prog_name %s%s, pseudo %u, %starget_type %s, tid %s, attr %s, value %s, result %s by%s\n", + request_name, pid_nr(caller_pid), parent_pid, command, program_path, pseudo, remote_ip_name, target_type_name, target_id_name, attr_name, attr_val_name, res_name, res_mods); + } + else +#endif + { + char * owner_name; + + owner_name = rsbac_kmalloc(32); +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(owner)) + sprintf(owner_name, "%u/%u", + RSBAC_UID_SET(owner), + RSBAC_UID_NUM(owner)); + else +#endif + sprintf(owner_name, "%u", RSBAC_UID_NUM(owner)); + #ifdef CONFIG_RSBAC_SOFTMODE + if(rsbac_softmode) + rsbac_printk(KERN_INFO "rsbac_adf_request(): request %s, pid %u, ppid %u, prog_name %s%s, uid %s, %s%starget_type %s, tid %s, attr %s, value %s, result %s (Softmode) by%s\n", + request_name, pid_nr(caller_pid), pid_nr(parent_pid), command, program_path, owner_name, audit_uid_name, remote_ip_name, target_type_name, target_id_name, attr_name, attr_val_name, res_name, res_mods); + else + #endif + rsbac_printk(KERN_INFO "rsbac_adf_request(): request %s, pid %u, ppid %u, prog_name %s%s, uid %s, %s%starget_type %s, tid %s, attr %s, value %s, result %s by%s\n", + request_name, pid_nr(caller_pid), pid_nr(parent_pid), command, program_path, owner_name, audit_uid_name, remote_ip_name, target_type_name, target_id_name, attr_name, attr_val_name, res_name, res_mods); + rsbac_kfree(owner_name); + } + if (parent_pid) + put_pid(parent_pid); + /* rsbac_kfree all helper mem */ + rsbac_kfree(request_name); + rsbac_kfree(res_name); + rsbac_kfree(res_mods); + rsbac_kfree(target_type_name); + rsbac_kfree(target_id_name); + rsbac_kfree(program_path); + rsbac_kfree(attr_name); + rsbac_kfree(attr_val_name); +#ifdef CONFIG_RSBAC_NET_OBJ + rsbac_kfree(remote_ip_name); +#endif + rsbac_kfree(audit_uid_name); + } + +/* UNDEFINED must never be returned -> change result */ + if(result == UNDEFINED) + result = NOT_GRANTED; + +/* count */ + rsbac_adf_request_count[target]++; +#ifdef CONFIG_RSBAC_XSTATS + rsbac_adf_request_xcount[target][request]++; +#endif + +/* return result */ + #ifdef CONFIG_RSBAC_SOFTMODE + if(rsbac_softmode && !rsbac_internal) + return DO_NOT_CARE; + else + #endif + #ifdef CONFIG_RSBAC_SOFTMODE_IND + return ret_result; + #else + return result; /* change for debugging! */ + #endif + } /* end of rsbac_adf_request_int() */ + + +/*****************************************************************************/ +/* If the request returned granted and the operation is performed, */ +/* the following function is called by the AEF to get all aci set correctly. */ +/* The second instance of target specification is the new target, if one has */ +/* been created, otherwise its values are ignored. */ +/* It returns 0 on success and an error from error.h otherwise. */ + +EXPORT_SYMBOL(rsbac_adf_set_attr); +int rsbac_adf_set_attr( + enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val) + { + union rsbac_target_id_t i_tid; + rsbac_uid_t owner; + int error = 0; + rsbac_request_vector_t request_vector; + rsbac_boolean_t do_log = FALSE; + rsbac_boolean_t log_on_request = TRUE; + union rsbac_attribute_value_t i_attr_val; +#ifdef CONFIG_RSBAC_IND_LOG + union rsbac_attribute_value_t i_attr_val2; + enum rsbac_log_level_t log_level; +#endif +#ifdef CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT + struct vfsmount * mnt_p; +#endif + +/* No attribute setting possible before init (called at boot time) */ + + if (unlikely(!rsbac_is_initialized())) + return 0; + +/* kernel (pid 0) is ignored */ + if ( !pid_nr(caller_pid) + #if defined(CONFIG_RSBAC_LOG_REMOTE) + || (caller_pid == rsbaclogd_pid) + #endif + ) + return 0; +/* Checking base values */ + if(unlikely( request >= R_NONE + || target > T_NONE + || new_target > T_NONE + || attr > A_none) + ) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr(): called with invalid request, target or attribute\n"); + return(-RSBAC_EINVALIDVALUE); + } + + if (unlikely(in_interrupt())) + { + char * request_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(request_name) + { + get_request_name(request_name, request); + printk(KERN_WARNING "rsbac_adf_set_attr(): called from interrupt: request %s, pid %u(%s), attr_val %u!\n", + request_name, pid_nr(caller_pid), current->comm, attr_val.dummy); + rsbac_kfree(request_name); + } + else + { + printk(KERN_WARNING "rsbac_adf_set_attr(): called from interrupt: request %u, pid %u(%s)!\n", + request, pid_nr(caller_pid), current->comm); + } + dump_stack(); + return -RSBAC_EFROMINTERRUPT; + } + + request_vector = RSBAC_REQUEST_VECTOR(request); + +/* Getting basic information about this adf_set_attr-call */ + + owner = RSBAC_NO_USER; + /* only useful for real process, not idle or init */ + if (pid_nr(caller_pid) > 1) + { + error = rsbac_get_owner(&owner); + if(error) + { + rsbac_printk(KERN_DEBUG + "rsbac_adf_set_attr(): caller_pid %i, RSBAC not initialized, returning 0", + pid_nr(caller_pid)); + return 0; /* Startup-Sequence (see above) */ + } + } + else /* caller_pid = 1 -> init -> owner = root */ + owner = 0; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if ((attr == A_owner) && (RSBAC_UID_SET(attr_val.owner) > RSBAC_UM_VIRTUAL_MAX)) + attr_val.owner = RSBAC_GEN_UID(RSBAC_UID_SET(owner), attr_val.owner); + else + if ((attr == A_group) && (RSBAC_GID_SET(attr_val.group) > RSBAC_UM_VIRTUAL_MAX)) + attr_val.group = RSBAC_GEN_GID(RSBAC_UID_SET(owner), attr_val.group); +#else + if (attr == A_owner) + attr_val.owner = RSBAC_UID_NUM(attr_val.owner); + else + if (attr == A_group) + attr_val.group = RSBAC_GID_NUM(attr_val.group); +#endif + +/*************************************************/ +/* General work for all modules - before modules */ +#if defined(CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT) || defined(CONFIG_RSBAC_FD_CACHE) + switch (target) { + case T_DIR: +#if defined(CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT) + if ((mnt_p = rsbac_get_vfsmount(tid.file.device)) + && ( (mnt_p->mnt_sb->s_magic == NFS_SUPER_MAGIC) + || (mnt_p->mnt_sb->s_magic == CODA_SUPER_MAGIC) + || (mnt_p->mnt_sb->s_magic == NCP_SUPER_MAGIC) + || (mnt_p->mnt_sb->s_magic == SMB_SUPER_MAGIC) + ) + ) { + error = 0; + goto log; + } +#endif + +/* Ensure that there are no leftover attributes */ + if (request == R_CREATE) { + rsbac_remove_target(new_target, new_tid); + } + +#if defined(CONFIG_RSBAC_FD_CACHE) + else if (request == R_RENAME && RSBAC_MAJOR(tid.file.device) > 1) { + /* invalidate FD cache for this device, if parent dir has changed */ + if ( attr == A_old_dir_inode_p + && attr_val.old_dir_inode_p + && tid.file.dentry_p + && tid.file.dentry_p->d_parent + && tid.file.dentry_p->d_parent->d_inode) { + if (attr_val.old_dir_inode_p->i_ino != tid.file.dentry_p->d_parent->d_inode->i_ino) { + rsbac_pr_debug(fdcache, "moved DIR item device %02u:%02u inode %lu from dir %u to dir %u, invalidate cache for device\n", + RSBAC_MAJOR(tid.file.device), RSBAC_MINOR(tid.file.device), + tid.file.inode, attr_val.old_dir_inode_p->i_ino, tid.file.dentry_p->d_parent->d_inode->i_ino); + rsbac_fd_cache_invalidate_device(tid.file.device); + } else { + rsbac_pr_debug(fdcache, "renamed DIR item device %02u:%02u inode %lu inside dir %u, do not invalidate cache for device\n", + RSBAC_MAJOR(tid.file.device), RSBAC_MINOR(tid.file.device), + tid.file.inode, attr_val.old_dir_inode_p->i_ino); + } + } else { + rsbac_pr_debug(fdcache, "moved DIR item device %02u:%02u inode %lu without parent dir info, invalidate cache for device\n", + RSBAC_MAJOR(tid.file.device), RSBAC_MINOR(tid.file.device), + tid.file.inode); + rsbac_fd_cache_invalidate_device(tid.file.device); + } + } +#endif + break; + + case T_FILE: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: +#if defined(CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT) + if ((mnt_p = rsbac_get_vfsmount(tid.file.device)) + && ( (mnt_p->mnt_sb->s_magic == NFS_SUPER_MAGIC) + || (mnt_p->mnt_sb->s_magic == CODA_SUPER_MAGIC) + || (mnt_p->mnt_sb->s_magic == NCP_SUPER_MAGIC) + || (mnt_p->mnt_sb->s_magic == SMB_SUPER_MAGIC) + ) + ) { + error = 0; + goto log; + } +#endif + +#if defined(CONFIG_RSBAC_FD_CACHE) + if (request == R_RENAME && RSBAC_MAJOR(tid.file.device) > 1) { + /* invalidate FD cache entry, if parent dir has changed */ + if ( attr == A_old_dir_inode_p + && attr_val.old_dir_inode_p + && tid.file.dentry_p + && tid.file.dentry_p->d_parent + && tid.file.dentry_p->d_parent->d_inode) { + if (attr_val.old_dir_inode_p->i_ino != tid.file.dentry_p->d_parent->d_inode->i_ino) { + rsbac_pr_debug(fdcache, "moved FD item device %02u:%02u inode %lu from dir %u to dir %u, invalidate cache item\n", + RSBAC_MAJOR(tid.file.device), RSBAC_MINOR(tid.file.device), + tid.file.inode, attr_val.old_dir_inode_p->i_ino, tid.file.dentry_p->d_parent->d_inode->i_ino); + rsbac_fd_cache_invalidate(&tid.file); + } else { + rsbac_pr_debug(fdcache, "renamed FD item device %02u:%02u inode %lu inside dir %u, do not invalidate cache item\n", + RSBAC_MAJOR(tid.file.device), RSBAC_MINOR(tid.file.device), + tid.file.inode, attr_val.old_dir_inode_p->i_ino); + } + } else { + rsbac_pr_debug(fdcache, "moved FD item device %02u:%02u inode %lu without parent dir info, invalidate cache item\n", + RSBAC_MAJOR(tid.file.device), RSBAC_MINOR(tid.file.device), + tid.file.inode); + rsbac_fd_cache_invalidate(&tid.file); + } + } +#endif + break; + + case T_PROCESS: + if ( (request == R_CLONE) + && !new_tid.process + ) { + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr(): tid for new process in CLONE is NULL!\n"); + return -RSBAC_EINVALIDTARGET; + } + break; + + default: + break; + } +#endif + +/**********************************************************/ +/* calling all decision modules, building a common result */ + + +#ifdef CONFIG_RSBAC_DEBUG +/* first, check for valid request/target combination */ +error |= rsbac_adf_set_attr_check(request, + caller_pid, + target, + tid, + new_target, + new_tid, + attr, + attr_val, + owner); +if(error) + goto general_work; +#endif + +/******* MAC ********/ +#if defined(CONFIG_RSBAC_MAC) +#ifdef CONFIG_RSBAC_SWITCH_MAC +if (rsbac_switch_mac) +#endif + if(request_vector & RSBAC_MAC_SET_ATTR_VECTOR) + error |= rsbac_adf_set_attr_mac(request, + caller_pid, + target, + tid, + new_target, + new_tid, + attr, + attr_val, + owner); +#endif /* MAC */ + +/******* DAZ ********/ +#ifdef CONFIG_RSBAC_DAZ +#ifdef CONFIG_RSBAC_SWITCH_DAZ +if (rsbac_switch_daz) +#endif + if(request_vector & RSBAC_DAZ_SET_ATTR_VECTOR) + error |= rsbac_adf_set_attr_daz (request, + caller_pid, + target, + tid, + new_target, + new_tid, + attr, + attr_val, + owner); +#endif /* DAZ */ + +/******* RC ********/ +#ifdef CONFIG_RSBAC_RC +#ifdef CONFIG_RSBAC_SWITCH_RC +if (rsbac_switch_rc) +#endif + error |= rsbac_adf_set_attr_rc (request, + caller_pid, + target, + tid, + new_target, + new_tid, + attr, + attr_val, + owner); +#endif /* RC */ + +/****** AUTH *******/ +#ifdef CONFIG_RSBAC_AUTH +#ifdef CONFIG_RSBAC_SWITCH_AUTH +if (rsbac_switch_auth) +#endif + if(request_vector & RSBAC_AUTH_SET_ATTR_VECTOR) + error |= rsbac_adf_set_attr_auth(request, + caller_pid, + target, + tid, + new_target, + new_tid, + attr, + attr_val, + owner); +#endif /* AUTH */ + +/****** CAP *******/ +#ifdef CONFIG_RSBAC_CAP +#ifdef CONFIG_RSBAC_SWITCH_CAP +if (rsbac_switch_cap) +#endif + if(request_vector & RSBAC_CAP_SET_ATTR_VECTOR) + error |= rsbac_adf_set_attr_cap (request, + caller_pid, + target, + tid, + new_target, + new_tid, + attr, + attr_val, + owner); +#endif /* CAP */ + +/****** JAIL *******/ +#ifdef CONFIG_RSBAC_JAIL +#ifdef CONFIG_RSBAC_SWITCH_JAIL +if (rsbac_switch_jail) +#endif + if(request_vector & RSBAC_JAIL_SET_ATTR_VECTOR) + error |= rsbac_adf_set_attr_jail(request, + caller_pid, + target, + tid, + new_target, + new_tid, + attr, + attr_val, + owner); +#endif /* JAIL */ + +/****** RES *******/ +#ifdef CONFIG_RSBAC_RES +#ifdef CONFIG_RSBAC_SWITCH_RES +if (rsbac_switch_res) +#endif + if(request_vector & RSBAC_RES_SET_ATTR_VECTOR) + error |= rsbac_adf_set_attr_res (request, + caller_pid, + target, + tid, + new_target, + new_tid, + attr, + attr_val, + owner); +#endif /* RES */ + +/******* UDF ********/ +#ifdef CONFIG_RSBAC_UDF +#ifdef CONFIG_RSBAC_SWITCH_UDF +if (rsbac_switch_udf) +#endif + if(request_vector & RSBAC_UDF_SET_ATTR_VECTOR) + error |= rsbac_adf_set_attr_udf (request, + caller_pid, + target, + tid, + new_target, + new_tid, + attr, + attr_val, + owner); +#endif /* UDF */ + +/****** REG *******/ +#ifdef CONFIG_RSBAC_REG + error |= rsbac_adf_set_attr_reg (request, + caller_pid, + target, + tid, + new_target, + new_tid, + attr, + attr_val, + owner); +#endif /* REG */ + +/* General work for all modules (after set_attr call) */ +#ifdef CONFIG_RSBAC_DEBUG +general_work: +#endif + switch(request) + { + /* remove deleted item from rsbac data */ + case R_DELETE : + switch (target) + { + case T_FILE: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + /* Only remove file/fifo target on deletion of last link */ + if ( (attr == A_nlink) + && (attr_val.nlink > 1) + ) + break; + /* fall through */ + case T_DIR: + rsbac_remove_target(target,tid); + break; + case T_IPC: + /* shm removal delayed and removed directly, when destroyed */ + if(tid.ipc.type != I_shm) + rsbac_remove_target(target,tid); + break; + default: + break; + } + break; + + case R_CLONE: + switch (target) + { + case T_PROCESS: + #if defined(CONFIG_RSBAC_IND_PROG_LOG) + /* get program based log from old process */ + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_log_program_based, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_log_program_based); + } + else + { /* only set, if not default value 0 */ + if(i_attr_val.log_program_based) + { + /* set program based log for new process */ + if (rsbac_set_attr(SW_GEN, new_target, + new_tid, + A_log_program_based, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_log_program_based); + } + } + } + #endif + #if defined(CONFIG_RSBAC_FAKE_ROOT_UID) + /* get fake_root_uid from old process */ + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_fake_root_uid, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_fake_root_uid); + } + else + { /* only set, of not default value 0 */ + if(i_attr_val.fake_root_uid) + { + /* set program based log for new process */ + if (rsbac_set_attr(SW_GEN, new_target, + new_tid, + A_fake_root_uid, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_fake_root_uid); + } + } + } + #endif + #if defined(CONFIG_RSBAC_MPROTECT) + /* get allow_write_exec from old process */ + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_allow_write_exec, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_allow_write_exec); + } + else + { /* only set, of not default value 0 */ + if(i_attr_val.allow_write_exec != AWX_relocate) + { + /* set program based log for new process */ + if (rsbac_set_attr(SW_GEN, new_target, + new_tid, + A_allow_write_exec, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_allow_write_exec); + } + } + } + #endif + #if defined(CONFIG_RSBAC_NET) + /* get remote_ip from old process */ + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_remote_ip, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_remote_ip); + } + else + { /* only set, of not default value 0 */ + if(i_attr_val.remote_ip) + { + /* set program based log for new process */ + if (rsbac_set_attr(SW_GEN, new_target, + new_tid, + A_remote_ip, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_remote_ip); + } + } + } + #endif + /* get kernel_thread from old process */ + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_kernel_thread, + &i_attr_val, FALSE)) { + rsbac_ds_get_error("rsbac_adf_set_attr()", + A_kernel_thread); + } else { + if (i_attr_val.kernel_thread) { + if (rsbac_set_attr(SW_GEN, new_target, + new_tid, + A_kernel_thread, + i_attr_val)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr()", + A_kernel_thread); + } + } + } + + /* get audit_uid from old process */ + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_audit_uid, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_audit_uid); + } + else + { /* only set, of not default value NO_USER */ + if(i_attr_val.audit_uid != RSBAC_NO_USER) + { + /* set audit uid for new process */ + if (rsbac_set_attr(SW_GEN, + new_target, + new_tid, + A_audit_uid, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_audit_uid); + } + } + } + /* get auid_exempt from old process */ + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_auid_exempt, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_auid_exempt); + } + else + { /* only set, of not default value NO_USER */ + if(i_attr_val.auid_exempt != RSBAC_NO_USER) + { + /* set program based log for new process */ + if (rsbac_set_attr(SW_GEN, + new_target, + new_tid, + A_auid_exempt, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_auid_exempt); + } + } + } + #ifdef CONFIG_RSBAC_UM_VIRTUAL + /* set vset of new process */ + i_attr_val.vset = RSBAC_UID_SET(owner); + if(i_attr_val.vset) + { + /* set vset for new process */ + if (rsbac_set_attr(SW_GEN, new_target, + new_tid, + A_vset, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_vset); + } + } + #endif + break; + + default: + break; + } + break; + + case R_CLOSE: + switch (target) { +#if 0 + case T_IPC: + if( (tid.ipc.type == I_anonunix) + && ( (attr != A_nlink) + || (attr_val.nlink <= 1) + ) + ) + rsbac_remove_target(target, tid); + break; +#endif +#ifdef CONFIG_RSBAC_NET_OBJ + case T_NETOBJ: + rsbac_remove_target(target, tid); + break; +#endif + default: + break; + } + break; + +#if 0 + case R_CREATE: + switch (target) { + case T_IPC: + if((tid.ipc.type != I_sem) && !tid.ipc.id.id_nr) + error |= -RSBAC_EINVALIDVALUE; + break; + default: + break; + } + break; +#endif + +#ifdef CONFIG_RSBAC_NET_OBJ + case R_ACCEPT: + switch (target) + { + case T_NETOBJ: + /* store remote IP */ + if( tid.netobj.sock_p + && tid.netobj.sock_p->ops + && tid.netobj.sock_p->sk + && (tid.netobj.sock_p->ops->family == AF_INET) + ) + { + i_tid.process = caller_pid; + i_attr_val.remote_ip = inet_sk(tid.netobj.sock_p->sk)->inet_daddr; + /* set program based log for new process */ + if (rsbac_set_attr(SW_GEN, + T_PROCESS, + i_tid, + A_remote_ip, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_remote_ip); + } + } + break; + + default: + break; + } + break; +#endif /* CONFIG_RSBAC_NET_OBJ */ + + case R_EXECUTE : + switch (target) + { + case T_FILE: + #if defined(CONFIG_RSBAC_IND_PROG_LOG) + /* get program based log from file */ + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_log_program_based, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_log_program_based); + } + else + { + /* set program based log for process */ + i_tid.process = caller_pid; + if (rsbac_set_attr(SW_GEN, T_PROCESS, + i_tid, + A_log_program_based, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_log_program_based); + } + } + #endif + #if defined(CONFIG_RSBAC_FAKE_ROOT_UID) + /* get fake_root_uid from file */ + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_fake_root_uid, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_fake_root_uid); + } + else + { + /* set fake_root_uid for process */ + i_tid.process = caller_pid; + if (rsbac_set_attr(SW_GEN, T_PROCESS, + i_tid, + A_fake_root_uid, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_fake_root_uid); + } + } + #endif + #if defined(CONFIG_RSBAC_MPROTECT) + /* get allow_write_exec from file */ + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_allow_write_exec, + &i_attr_val, + TRUE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_allow_write_exec); + } + else + { + /* set allow_write_exec for process */ + i_tid.process = caller_pid; + if (rsbac_set_attr(SW_GEN, T_PROCESS, + i_tid, + A_allow_write_exec, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_allow_write_exec); + } + } + #endif + #ifdef CONFIG_RSBAC_UM_VIRTUAL + /* get vset from file */ + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_vset, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_vset); + } + else + { + /* set vset for process */ + if(i_attr_val.vset != RSBAC_UM_VIRTUAL_KEEP) + { + i_tid.process = caller_pid; + if (rsbac_set_attr(SW_GEN, T_PROCESS, + i_tid, + A_vset, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_vset); + } + } + } + #endif + /* get auid_exempt from file */ + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_auid_exempt, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_auid_exempt); + } + else + { + if(i_attr_val.auid_exempt != RSBAC_NO_USER) + { + /* set auid_exempt for process */ + i_tid.process = caller_pid; + if (rsbac_set_attr(SW_GEN, T_PROCESS, + i_tid, + A_auid_exempt, + i_attr_val)) + { + rsbac_ds_set_error("rsbac_adf_set_attr()", A_auid_exempt); + } + } + } + break; + + default: + break; + } + break; + + default: + break; + } + +#if defined(CONFIG_RSBAC_DEBUG) && defined(CONFIG_RSBAC_NET) + if( rsbac_debug_adf_net + && ( (target == T_NETDEV) + || (target == T_NETTEMP) + || (target == T_NETOBJ) + ) + ) + do_log = TRUE; +#endif + +/* log based on process owner */ +#ifdef CONFIG_RSBAC_IND_USER_LOG + i_tid.user = owner; + if (rsbac_get_attr(SW_GEN, + T_USER, + i_tid, + A_log_user_based, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_log_user_based); + } + else + { + if(((rsbac_request_vector_t) 1 << request) & i_attr_val.log_user_based) + do_log = TRUE; + } +#endif /* CONFIG_RSBAC_IND_USER_LOG */ + +/* log based on program */ +#ifdef CONFIG_RSBAC_IND_PROG_LOG + if(!do_log) + { + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_GEN, + T_PROCESS, + i_tid, + A_log_program_based, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_log_program_based); + } + else + { + if(((rsbac_request_vector_t) 1 << request) & i_attr_val.log_program_based) + do_log = TRUE; + } + } +#endif /* CONFIG_RSBAC_IND_PROG_LOG */ + + +/* logging request on info level, if requested by file/dir/dev attributes */ +/* log_array_low/high, or, if that is requested, if enabled for this request */ +/* type (attributes state level, or that request based level is to be taken) */ +/* loglevel 2: log everything */ +/* loglevel 1: log, if denied */ +/* loglevel 0: log nothing */ + +#ifdef CONFIG_RSBAC_IND_LOG /* only if individual logging is enabled */ + /* if file/dir/dev, depend log on log_arrays */ + /* (but not for file.device = 0) */ + /* log_on_request is TRUE */ + if(!do_log) + { + if( ( ( (target == T_FILE) + || (target == T_DIR) + || (target == T_FIFO) + || (target == T_SYMLINK) + ) + && RSBAC_MAJOR(tid.file.device) + && RSBAC_MINOR(tid.file.device) + ) + || (target == T_DEV) + ) + { + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_log_array_low, + &i_attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_log_array_low); + } + else + { + if (rsbac_get_attr(SW_GEN, + target, + tid, + A_log_array_high, + &i_attr_val2, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_log_array_high); + } + else + { /* ll = low-bit for request | (high-bit for request as bit 1) */ + log_level = ((i_attr_val.log_array_low >> request) & 1) + | ( ((i_attr_val2.log_array_high >> request) & 1) << 1); + if ( log_level == LL_full + || ( log_level == LL_denied + && error) ) + { + do_log = TRUE; + } + if(log_level != LL_request) + log_on_request = FALSE; + } + } + } + } +#endif /* CONFIG_RSBAC_IND_LOG */ + +#ifdef CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT +log: +#endif + /* if enabled, try request based log level */ + if (log_on_request + && ( rsbac_log_levels[request][target] == LL_full + || ( rsbac_log_levels[request][target] == LL_denied + && error) ) ) + do_log = TRUE; + + if(do_log) + { + char * request_name; + char * target_type_name; + char * new_target_type_name; + char * target_id_name; + char * new_target_id_name; + char * attr_name; + rsbac_uid_t audit_uid; + char * audit_uid_name; +#ifdef CONFIG_RSBAC_LOG_PSEUDO + rsbac_pseudo_t pseudo = 0; +#endif + + /* Get process audit_uid */ + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_GEN,T_PROCESS,i_tid,A_audit_uid,&i_attr_val,FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_audit_uid); + return -RSBAC_EREADFAILED; /* something weird happened */ + } + audit_uid_name = rsbac_kmalloc(32); + audit_uid = i_attr_val.audit_uid; + if(audit_uid == RSBAC_NO_USER) { + audit_uid_name[0] = 0; + audit_uid = owner; + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(audit_uid)) + sprintf(audit_uid_name, "audit uid %u/%u, ", + RSBAC_UID_SET(audit_uid), + RSBAC_UID_NUM(audit_uid)); + else +#endif + sprintf(audit_uid_name, "audit uid %u, ", RSBAC_UID_NUM(audit_uid)); + } +#ifdef CONFIG_RSBAC_LOG_PSEUDO + /* Get owner's logging pseudo */ + i_tid.user = audit_uid; + if (rsbac_get_attr(SW_GEN,T_USER,i_tid,A_pseudo,&i_attr_val,FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr()", A_pseudo); + return -RSBAC_EREADFAILED; /* something weird happened */ + } + /* if pseudo is not registered, return attribute value is 0 (see later) */ + pseudo = i_attr_val.pseudo; +#endif + + /* rsbac_kmalloc all memory */ + request_name = rsbac_kmalloc(32); + target_type_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + new_target_type_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + #ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + new_target_id_name + = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ + #else + target_id_name = rsbac_kmalloc(2 * RSBAC_MAXNAMELEN); + new_target_id_name = rsbac_kmalloc(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ + #endif + attr_name = rsbac_kmalloc(32); + + /* Getting basic information about this request */ + request_name[0] = (char) 0; + target_type_name[0] = (char) 0; + target_id_name[0] = (char) 0; + new_target_type_name[0] = (char) 0; + new_target_id_name[0] = (char) 0; + attr_name[0] = (char) 0; + get_request_name(request_name, request); + get_target_name(target_type_name, target, target_id_name, tid); + get_target_name(new_target_type_name, new_target, + new_target_id_name, new_tid); + get_attribute_name(attr_name, attr); + +#ifdef CONFIG_RSBAC_LOG_PSEUDO + if(pseudo) + rsbac_printk(KERN_INFO + "rsbac_adf_set_attr(): request %s, pid %u, pseudo %u, target_type %s, tid %s, new_target_type %s, new_tid %s, attr %s, value %u, error %i\n", + request_name, pid_nr(caller_pid), pseudo, target_type_name, target_id_name, + new_target_type_name, new_target_id_name, attr_name, attr_val.dummy, error); + else +#endif + { + char * owner_name = rsbac_kmalloc(32); + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(owner)) + sprintf(owner_name, "%u/%u", + RSBAC_UID_SET(owner), + RSBAC_UID_NUM(owner)); + else +#endif + sprintf(owner_name, "%u", RSBAC_UID_NUM(owner)); + + rsbac_printk(KERN_INFO + "rsbac_adf_set_attr(): request %s, pid %u, uid %s, %starget_type %s, tid %s, new_target_type %s, new_tid %s, attr %s, value %u, error %i\n", + request_name, pid_nr(caller_pid), owner_name, audit_uid_name, target_type_name, target_id_name, + new_target_type_name, new_target_id_name, attr_name, attr_val.dummy, error); + rsbac_kfree(owner_name); + rsbac_kfree(audit_uid_name); + } + /* rsbac_kfree all helper mem */ + rsbac_kfree(request_name); + rsbac_kfree(target_type_name); + rsbac_kfree(new_target_type_name); + rsbac_kfree(target_id_name); + rsbac_kfree(new_target_id_name); + rsbac_kfree(attr_name); + } + +/* count */ + rsbac_adf_set_attr_count[target]++; +#ifdef CONFIG_RSBAC_XSTATS + rsbac_adf_set_attr_xcount[target][request]++; +#endif + + return(error); + } /* end of rsbac_adf_set_attr() */ + + +/**************** + * + * Secure Delete + * + ****************/ + +#ifdef CONFIG_RSBAC_SECDEL + +/* open_by_dentry */ +/* This is done by hand (copy from rsbac_read_open), because system calls */ +/* are currently blocked by rsbac */ + +static int open_by_dentry(struct dentry * file_dentry_p, struct file * file_p) + { + int tmperr; + + if ( !(S_ISREG(file_dentry_p->d_inode->i_mode)) ) + { /* this is not a file! -> error! */ + rsbac_printk(KERN_WARNING + "open_by_dentry(): expected file is not a file!\n"); + return -RSBAC_EWRITEFAILED; + } + /* Now we fill the file structure, and */ + /* if there is an open func, use it, otherwise ignore */ + if ((tmperr = init_private_file(file_p, file_dentry_p, O_WRONLY | O_SYNC))) + { + rsbac_printk(KERN_WARNING + "open_by_dentry(): could not open file!\n"); + return -RSBAC_EWRITEFAILED; + } + /* Without a write function we get into troubles -> error */ + if ((!file_p->f_op) || (!file_p->f_op->write_iter)) + { + rsbac_printk(KERN_WARNING + "open_by_dentry(): file write_iter function missing!\n"); + return -RSBAC_EWRITEFAILED; + } + return 0; + } + +/* + ********************** + * Secure File Truncation + */ +static int do_rsbac_sec_trunc(struct dentry * dentry_p, + loff_t new_len, + loff_t old_len, + u_int may_sync) + { + int err = 0; + rsbac_boolean_t need_overwrite = FALSE; + + if (unlikely(!rsbac_is_initialized())) + return 0; + /* security checks */ + if( !dentry_p + || !dentry_p->d_inode) + return -RSBAC_EINVALIDPOINTER; + if(!S_ISREG(dentry_p->d_inode->i_mode)) + return -RSBAC_EINVALIDTARGET; + if(dentry_p->d_sb->s_magic == PIPEFS_MAGIC) + return 0; + if(new_len >= old_len) + return 0; + + if (unlikely(in_interrupt())) + { + printk(KERN_WARNING "do_rsbac_sec_trunc(): called from interrupt: pid %u(%s)!\n", + current->pid, current->comm); + dump_stack(); + return -RSBAC_EFROMINTERRUPT; + } + + if(dentry_p->d_inode && !rsbac_writable(dentry_p->d_inode->i_sb)) + { +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_write) + { + rsbac_printk(KERN_DEBUG + "do_rsbac_sec_trunc(): ignoring file %lu on network device %02u:%02u!\n", + dentry_p->d_inode->i_ino, + MAJOR(dentry_p->d_inode->i_sb->s_dev), + MINOR(dentry_p->d_inode->i_sb->s_dev)); + } +#endif + return 0; + } + + /******* FF ********/ + #ifdef CONFIG_RSBAC_FF + #ifdef CONFIG_RSBAC_SWITCH_FF + if (rsbac_switch_ff) + #endif + /* no need to call module, if already need_overwrite */ + if(!need_overwrite) + need_overwrite = rsbac_need_overwrite_ff(dentry_p); + #endif /* FF */ + + /******* RC ********/ + #ifdef CONFIG_RSBAC_RC + #ifdef CONFIG_RSBAC_SWITCH_RC + if (rsbac_switch_rc) + #endif + /* no need to call module, if already need_overwrite */ + if(!need_overwrite) + need_overwrite = rsbac_need_overwrite_rc(dentry_p); + #endif /* RC */ + + /****** RES *******/ + #ifdef CONFIG_RSBAC_RES + #ifdef CONFIG_RSBAC_SWITCH_RES + if (rsbac_switch_res) + #endif + /* no need to call module, if already need_overwrite */ + if(!need_overwrite) + need_overwrite = rsbac_need_overwrite_res(dentry_p); + #endif /* RES */ + + /****** REG *******/ + #ifdef CONFIG_RSBAC_REG + if(!need_overwrite) + need_overwrite = rsbac_need_overwrite_reg(dentry_p); + #endif /* REG */ + + if(need_overwrite) + { + char * buffer; + struct file file; + int tmperr = 0; + mm_segment_t oldfs; + + buffer = rsbac_kmalloc(RSBAC_SEC_DEL_CHUNK_SIZE); + if(!buffer) + return -RSBAC_ENOMEM; + +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_write) + { + rsbac_printk(KERN_DEBUG + "rsbac_sec_trunc(): zeroing of file %lu on device %02u:%02u from byte %lu to %lu!\n", + dentry_p->d_inode->i_ino, + MAJOR(dentry_p->d_inode->i_sb->s_dev), + MINOR(dentry_p->d_inode->i_sb->s_dev), + (u_long) new_len, + (u_long) old_len-1); + } +#endif + /* open */ + err = open_by_dentry(dentry_p, &file); + if(err) + { + rsbac_kfree(buffer); + return err; + } + +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_write) + { + rsbac_printk(KERN_DEBUG + "rsbac_sec_trunc(): file %lu on device %02u:%02u is open, seeking to %lu!\n", + dentry_p->d_inode->i_ino, + MAJOR(dentry_p->d_inode->i_sb->s_dev), + MINOR(dentry_p->d_inode->i_sb->s_dev), + (u_long) new_len); + } +#endif + + /* OK, now we can start writing */ + + /* Set current user space to kernel space, because write() reads + * from user space + */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + + { /* taken from fs/read_write.c */ + file.f_pos = new_len; + file.f_version = 0; + } + memset(buffer,0,RSBAC_SEC_DEL_CHUNK_SIZE); + +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_write) + { + rsbac_printk(KERN_DEBUG + "rsbac_sec_trunc(): file %lu on device %02u:%02u is positioned, starting to write!\n", + dentry_p->d_inode->i_ino, + MAJOR(dentry_p->d_inode->i_sb->s_dev), + MINOR(dentry_p->d_inode->i_sb->s_dev)); + } +#endif + while (new_len < old_len) + { + struct iovec iov = { .iov_base = buffer, + .iov_len = rsbac_min(RSBAC_SEC_DEL_CHUNK_SIZE, old_len-new_len) }; + struct kiocb kiocb; + struct iov_iter iter; + + init_sync_kiocb(&kiocb, &file); + kiocb.ki_pos = file.f_pos; + iov_iter_init(&iter, WRITE, &iov, 1, iov.iov_len); + + tmperr = file.f_op->write_iter(&kiocb, &iter); + BUG_ON(tmperr == -EIOCBQUEUED); + file.f_pos = kiocb.ki_pos; + + if (tmperr < 0) { + err = tmperr; + break; + } + new_len += tmperr; + } + set_fs(oldfs); + +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_write) + { + rsbac_printk(KERN_DEBUG + "rsbac_sec_trunc(): syncing file %lu on device %02u:%02u!\n", + dentry_p->d_inode->i_ino, + MAJOR(dentry_p->d_inode->i_sb->s_dev), + MINOR(dentry_p->d_inode->i_sb->s_dev)); + } +#endif + + if(may_sync && (dentry_p->d_inode->i_size > 0)) + err = generic_file_fsync(&file, 0, dentry_p->d_inode->i_size - 1, 1); + + rsbac_kfree(buffer); + } + /* Ready. */ + return err; + } + +EXPORT_SYMBOL(rsbac_sec_trunc); +int rsbac_sec_trunc(struct dentry * dentry_p, + loff_t new_len, loff_t old_len) + { + return do_rsbac_sec_trunc(dentry_p, new_len, old_len, TRUE); + } + +EXPORT_SYMBOL(rsbac_sec_del); +int rsbac_sec_del(struct dentry * dentry_p, u_int may_sync) + { + return do_rsbac_sec_trunc(dentry_p, + 0, + dentry_p->d_inode->i_size, + may_sync); + } + +#else /* no SECDEL */ +EXPORT_SYMBOL(rsbac_sec_trunc); +int rsbac_sec_trunc(struct dentry * dentry_p, + loff_t new_len, loff_t old_len) + { + return 0; + } +EXPORT_SYMBOL(rsbac_sec_del); +int rsbac_sec_del(struct dentry * dentry_p, u_int may_sync) + { + return 0; + } +#endif /* SECDEL */ + +#ifdef CONFIG_RSBAC_SYM_REDIR +EXPORT_SYMBOL(rsbac_symlink_redirect); + +/* This function changes the symlink content by adding a suffix, if + * requested. It returns NULL, if unchanged, or a pointer to a + * kmalloc'd new char * otherwise, which has to be kfree'd after use. + */ +char * rsbac_symlink_redirect( + struct inode * inode_p, + const char * name, + u_int maxlen, + rsbac_boolean_t may_sleep) + { +#if defined(CONFIG_RSBAC_SYM_REDIR_REMOTE_IP) || defined(CONFIG_RSBAC_SYM_REDIR_MAC) || defined(CONFIG_RSBAC_SYM_REDIR_RC) || defined(CONFIG_RSBAC_SYM_REDIR_UID) + union rsbac_target_id_t i_tid; + int err; + union rsbac_attribute_value_t i_attr_val; + gfp_t kmalloc_gfp = may_sleep ? GFP_KERNEL : GFP_ATOMIC; +#endif + + if(unlikely(!name)) + return NULL; + if(unlikely(!inode_p)) + return NULL; + if(unlikely(!inode_p->i_sb)) + return NULL; + if(unlikely(!rsbac_is_initialized())) + return NULL; + + if(unlikely(!S_ISLNK(inode_p->i_mode))) + { + rsbac_printk(KERN_DEBUG + "rsbac_symlink_redirect(): called for non-symlink inode %lu on dev %02u:%02u!\n", + inode_p->i_ino, + RSBAC_MAJOR(inode_p->i_sb->s_dev), RSBAC_MINOR(inode_p->i_sb->s_dev) ); + return NULL; + } + + if (unlikely(in_interrupt())) + { + printk(KERN_WARNING "rsbac_symlink_redirect(): called from interrupt: pid %u(%s)!\n", + current->pid, current->comm); + dump_stack(); + return NULL; + } + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG + "rsbac_symlink_redirect(): called for symlink inode %lu on dev %02u:%02u!\n", + inode_p->i_ino, + RSBAC_MAJOR(inode_p->i_sb->s_dev), RSBAC_MINOR(inode_p->i_sb->s_dev) ); + } +#endif + +#if defined(CONFIG_RSBAC_SYM_REDIR_REMOTE_IP) || defined(CONFIG_RSBAC_SYM_REDIR_MAC) || defined(CONFIG_RSBAC_SYM_REDIR_RC) || defined(CONFIG_RSBAC_SYM_REDIR_UID) + i_tid.symlink.device = inode_p->i_sb->s_dev; + i_tid.symlink.inode = inode_p->i_ino; + i_tid.symlink.dentry_p = NULL; +#endif + +#ifdef CONFIG_RSBAC_SYM_REDIR_REMOTE_IP + if ((err = rsbac_get_attr(SW_GEN, + T_SYMLINK, + i_tid, + A_symlink_add_remote_ip, + &i_attr_val, + FALSE) )) + { + rsbac_ds_get_error_num("rsbac_symlink_redirect()", A_symlink_add_remote_ip, err); + return NULL; /* something weird happened */ + } + if(i_attr_val.symlink_add_remote_ip) + { + u_int len; + rsbac_enum_t add_remote_ip; + __u32 addr; + char * new_name; + + add_remote_ip = i_attr_val.symlink_add_remote_ip; + i_tid.process = task_pid(current); + err = rsbac_get_attr(SW_GEN, + T_PROCESS, + i_tid, + A_remote_ip, + &i_attr_val, + FALSE); + if (err) + { + rsbac_ds_get_error_num("rsbac_symlink_redirect()", A_remote_ip, err); + return NULL; /* something weird happened */ + } + addr = i_attr_val.remote_ip; + len = strlen(name); +#if 0 + while( len + && (name[len-1] >= '0') + && (name[len-1] <= '9') + ) + len--; + +#endif + if(len > (maxlen - 20)) + { + rsbac_printk(KERN_DEBUG + "rsbac_symlink_redirect(): not enough space for symlink inode %lu on dev %02u:%02u!\n", + inode_p->i_ino, + RSBAC_MAJOR(inode_p->i_sb->s_dev), RSBAC_MINOR(inode_p->i_sb->s_dev) ); + return NULL; + } + new_name = kmalloc(len + 20, kmalloc_gfp); + if(!new_name) + { + rsbac_printk(KERN_DEBUG + "rsbac_symlink_redirect(): not enough memory for symlink redir remote ip inode %lu on dev %02u:%02u!\n", + inode_p->i_ino, + RSBAC_MAJOR(inode_p->i_sb->s_dev), RSBAC_MINOR(inode_p->i_sb->s_dev) ); + return NULL; + } + strcpy(new_name, name); + switch(add_remote_ip) + { + case 1: + sprintf(new_name+len, "%u", + ((unsigned char *)&addr)[0]); + break; + case 2: + sprintf(new_name+len, "%u.%u", + ((unsigned char *)&addr)[0], + ((unsigned char *)&addr)[1]); + break; + case 3: + sprintf(new_name+len, "%u.%u.%u", + ((unsigned char *)&addr)[0], + ((unsigned char *)&addr)[1], + ((unsigned char *)&addr)[2]); + break; + default: + sprintf(new_name+len, "%u.%u.%u.%u", + ((unsigned char *)&addr)[0], + ((unsigned char *)&addr)[1], + ((unsigned char *)&addr)[2], + ((unsigned char *)&addr)[3]); + } + return new_name; + } +#endif + +#ifdef CONFIG_RSBAC_SYM_REDIR_UID + if ((err = rsbac_get_attr(SW_GEN, + T_SYMLINK, + i_tid, + A_symlink_add_uid, + &i_attr_val, + FALSE) )) + { + rsbac_ds_get_error_num("rsbac_symlink_redirect()", A_symlink_add_uid, err); + return NULL; /* something weird happened */ + } + if(i_attr_val.symlink_add_uid) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + u_int len; + u_int room = 20; + char * new_name; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(user)) + room = 40; +#endif + len = strlen(name); + while( len + && ( ( (name[len-1] >= '0') + && (name[len-1] <= '9') + ) +#ifdef CONFIG_RSBAC_UM_VIRTUAL + || (name[len-1] == '-') +#endif + ) + ) + len--; + if(len > (maxlen - room)) + { + rsbac_printk(KERN_DEBUG + "rsbac_symlink_redirect(): not enough space for symlink inode %lu on dev %02u:%02u!\n", + inode_p->i_ino, + RSBAC_MAJOR(inode_p->i_sb->s_dev), RSBAC_MINOR(inode_p->i_sb->s_dev) ); + return NULL; + } + new_name = kmalloc(len + room, kmalloc_gfp); + if(!new_name) + { + rsbac_printk(KERN_DEBUG + "rsbac_symlink_redirect(): not enough memory for symlink redir uid inode %lu on dev %02u:%02u!\n", + inode_p->i_ino, + RSBAC_MAJOR(inode_p->i_sb->s_dev), RSBAC_MINOR(inode_p->i_sb->s_dev) ); + return NULL; + } + strcpy(new_name, name); +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(user)) + sprintf(new_name+len, "%u-%u", + RSBAC_UID_SET(user), RSBAC_UID_NUM(user)); + else +#endif + sprintf(new_name+len, "%u", RSBAC_UID_NUM(user)); + return new_name; + } + else + return NULL; + } +#endif + +#ifdef CONFIG_RSBAC_SYM_REDIR_MAC + if ((err = rsbac_get_attr(SW_GEN, + T_SYMLINK, + i_tid, + A_symlink_add_mac_level, + &i_attr_val, + FALSE) )) + { + rsbac_ds_get_error_num("rsbac_symlink_redirect()", A_symlink_add_mac_level, err); + return NULL; /* something weird happened */ + } + if(i_attr_val.symlink_add_mac_level) + { + u_int len; + char * new_name; + + i_tid.process = task_pid(current); + if ((err = rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_current_sec_level, + &i_attr_val, + FALSE) )) + { + rsbac_ds_get_error_num("rsbac_symlink_redirect()", A_current_sec_level, err); + return NULL; /* something weird happened */ + } + + len = strlen(name); + while( len + && ( ( (name[len-1] >= '0') + && (name[len-1] <= '9') + ) +#ifdef CONFIG_RSBAC_SYM_REDIR_MAC_CAT + || (name[len-1] == ':') +#endif + ) + ) + len--; +#ifdef CONFIG_RSBAC_SYM_REDIR_MAC_CAT + if(len > (maxlen - 85)) +#else + if(len > (maxlen - 20)) +#endif + { + rsbac_printk(KERN_DEBUG + "rsbac_symlink_redirect(): not enough space for symlink inode %lu on dev %02u:%02u!\n", + inode_p->i_ino, + RSBAC_MAJOR(inode_p->i_sb->s_dev), RSBAC_MINOR(inode_p->i_sb->s_dev) ); + return NULL; + } + +#ifdef CONFIG_RSBAC_SYM_REDIR_MAC_CAT + new_name = kmalloc(len + 85, kmalloc_gfp); +#else + new_name = kmalloc(len + 20, kmalloc_gfp); +#endif + if(!new_name) + { + rsbac_printk(KERN_DEBUG + "rsbac_symlink_redirect(): not enough memory for symlink redir MAC level inode %lu on dev %02u:%02u!\n", + inode_p->i_ino, + RSBAC_MAJOR(inode_p->i_sb->s_dev), RSBAC_MINOR(inode_p->i_sb->s_dev) ); + return NULL; + } + strcpy(new_name, name); +#ifdef CONFIG_RSBAC_SYM_REDIR_MAC_CAT + len+=sprintf(new_name+len, "%u:", i_attr_val.current_sec_level); + if ((err = rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_mac_curr_categories, + &i_attr_val, + FALSE) )) + { + rsbac_ds_get_error_num("rsbac_symlink_redirect()", A_mac_curr_categories, err); + kfree(new_name); + return NULL; /* something weird happened */ + } + u64tostrmac(new_name+len, i_attr_val.mac_categories); +#else + len+=sprintf(new_name+len, "%u", i_attr_val.current_sec_level); +#endif + return new_name; + } +#endif + +#ifdef CONFIG_RSBAC_SYM_REDIR_RC + if ((err = rsbac_get_attr(SW_GEN, + T_SYMLINK, + i_tid, + A_symlink_add_rc_role, + &i_attr_val, + FALSE) )) + { + rsbac_ds_get_error_num("rsbac_symlink_redirect()", A_symlink_add_rc_role, err); + return NULL; /* something weird happened */ + } + if(i_attr_val.symlink_add_rc_role) + { + u_int len; + char * new_name; + + i_tid.process = task_pid(current); + err = rsbac_get_attr(SW_RC, + T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val, + FALSE); + if (err) + { + rsbac_ds_get_error_num("rsbac_symlink_redirect()", A_rc_role, err); + return NULL; /* something weird happened */ + } + + len = strlen(name); + while( len + && (name[len-1] >= '0') + && (name[len-1] <= '9') + ) + len--; + if(len > (maxlen - 20)) + { + rsbac_printk(KERN_DEBUG + "rsbac_symlink_redirect(): not enough space for symlink inode %lu on dev %02u:%02u!\n", + inode_p->i_ino, + RSBAC_MAJOR(inode_p->i_sb->s_dev), RSBAC_MINOR(inode_p->i_sb->s_dev) ); + return NULL; + } + + new_name = kmalloc(len + 20, kmalloc_gfp); + if(!new_name) + { + rsbac_printk(KERN_DEBUG + "rsbac_symlink_redirect(): not enough memory for symlink redir RC role inode %lu on dev %02u:%02u!\n", + inode_p->i_ino, + RSBAC_MAJOR(inode_p->i_sb->s_dev), RSBAC_MINOR(inode_p->i_sb->s_dev) ); + return NULL; + } + strcpy(new_name, name); + sprintf(new_name+len, "%u", i_attr_val.rc_role); + return new_name; + } +#endif + + return NULL; + } +#endif + +#ifdef CONFIG_RSBAC_FAKE_ROOT_UID +rsbac_uid_t rsbac_fake_uid(void) + { + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val; + + if(!__kuid_val(current_uid())) + return 0; + if (unlikely(!rsbac_is_initialized())) + return __kuid_val(current_uid()); + if (unlikely(in_interrupt())) + { + printk(KERN_WARNING "rsbac_fake_uid(): called from interrupt: pid %u(%s)!\n", + current->pid, current->comm); + dump_stack(); + return __kuid_val(current_uid()); + } + + i_tid.process = task_pid(current); + if ((err = rsbac_get_attr(SW_GEN, + T_PROCESS, + i_tid, + A_fake_root_uid, + &i_attr_val, + FALSE) )) + { + rsbac_ds_get_error("rsbac_fake_uid()", A_fake_root_uid); + return __kuid_val(current_uid()); + } + switch(i_attr_val.fake_root_uid) + { + case FR_both: + case FR_uid_only: + return 0; + default: + return __kuid_val(current_uid()); + } + } + +rsbac_uid_t rsbac_fake_euid(void) + { + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val; + + if(!__kuid_val(current_euid())) + return 0; + if (unlikely(!rsbac_is_initialized())) + return __kuid_val(current_euid()); + + if (unlikely(in_interrupt())) + { + printk(KERN_WARNING "rsbac_fake_euid(): called from interrupt: pid %u(%s)!\n", + current->pid, current->comm); + dump_stack(); + return __kuid_val(current_euid()); + } + + i_tid.process = task_pid(current); + if ((err = rsbac_get_attr(SW_GEN, + T_PROCESS, + i_tid, + A_fake_root_uid, + &i_attr_val, + FALSE) )) + { + rsbac_ds_get_error("rsbac_fake_euid()", A_fake_root_uid); + return __kuid_val(current_euid()); + } + switch(i_attr_val.fake_root_uid) + { + case FR_both: + case FR_euid_only: + return 0; + default: + return __kuid_val(current_euid()); + } + } + +int rsbac_uid_faked(void) + { + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val; + + if (unlikely(!rsbac_is_initialized())) + return 0; + + if (unlikely(in_interrupt())) + { + printk(KERN_WARNING "rsbac_uid_faked(): called from interrupt: pid %u(%s)!\n", + current->pid, current->comm); + dump_stack(); + return 0; + } + + i_tid.process = task_pid(current); + if ((err = rsbac_get_attr(SW_GEN, + T_PROCESS, + i_tid, + A_fake_root_uid, + &i_attr_val, + FALSE) )) + { + rsbac_ds_get_error("rsbac_uid_faked()", A_fake_root_uid); + return 0; /* something weird happened */ + } + switch(i_attr_val.fake_root_uid) + { + case FR_both: + case FR_uid_only: + return 1; + default: + return 0; + } + } +#endif + +#ifdef CONFIG_RSBAC_MPROTECT +int rsbac_write_exec_allowed(struct vm_area_struct *vma, unsigned int prot) + { + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val; + + if (unlikely(!rsbac_is_initialized())) + return 1; + if (unlikely(in_interrupt())) + { + printk(KERN_WARNING "rsbac_write_exec_allowed(): called from interrupt: pid %u(%s)!\n", + current->pid, current->comm); + dump_stack(); + return 1; + } +#ifdef CONFIG_RSBAC_SWITCH_MPROTECT + if (!rsbac_switch_mprotect) + return 1; +#endif + + i_tid.process = task_pid(current); + if ((err = rsbac_get_attr(SW_GEN, + T_PROCESS, + i_tid, + A_allow_write_exec, + &i_attr_val, + FALSE) )) + { + rsbac_ds_get_error("rsbac_write_exec_allowed()", A_allow_write_exec); + return 0; /* something weird happened */ + } + switch(i_attr_val.allow_write_exec) + { + case AWX_true: +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_mprotect) + { + char * program_name = rsbac_get_program_name(); + + if (vma && vma->vm_file && vma->vm_file->f_path.dentry && vma->vm_file->f_path.dentry->d_inode) { + char * help_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + help_name = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN); + if (help_name) { + if (!(rsbac_get_full_path(vma->vm_file->f_path.dentry, help_name, CONFIG_RSBAC_MAX_PATH_LEN - 1) > 0)) + strcpy(help_name, "(unknown)"); + } +#else + help_name = vma->vm_file->f_path.dentry->d_name.name; +#endif + rsbac_pr_debug(mprotect, "Process with %s has allow_write_exec true -> allow, pid %u(%s)\n", + help_name, current->pid, program_name); +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (help_name) + rsbac_kfree(help_name); +#endif + } else { + rsbac_pr_debug(mprotect, "Process has allow_write_exec true -> allow, pid %u(%s)\n", + current->pid, program_name); + } + if (program_name) + rsbac_kfree(program_name); + } +#endif + return 1; + + default: +#ifdef CONFIG_RSBAC_SOFTMODE + if( rsbac_softmode +#ifdef CONFIG_RSBAC_SOFTMODE_IND + || rsbac_ind_softmode[SW_MPROTECT] +#endif + ) { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_mprotect) + { + char * program_name = rsbac_get_program_name(); + + if (vma && vma->vm_file && vma->vm_file->f_path.dentry && vma->vm_file->f_path.dentry->d_inode) { + char * help_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + help_name = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN); + if (help_name) { + if (!(rsbac_get_full_path(vma->vm_file->f_path.dentry, help_name, CONFIG_RSBAC_MAX_PATH_LEN - 1) > 0)) + strcpy(help_name, "(unknown)"); + } +#else + help_name = vma->vm_file->f_path.dentry->d_name.name; +#endif + rsbac_pr_debug(mprotect, "softmode enabled, allow for %s, pid %u(%s)\n", + help_name, current->pid, program_name); +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (help_name) + rsbac_kfree(help_name); +#endif + } else { + rsbac_pr_debug(mprotect, "softmode enabled, allow, pid %u(%s)\n", + current->pid, program_name); + } + if (program_name) + rsbac_kfree(program_name); + } +#endif + return 1; + } +#else + break; +#endif + } + + if (vma && vma->vm_file) { + if (!vma->rsbac_mprotect_once) { + if (vma->vm_file->f_path.dentry && vma->vm_file->f_path.dentry->d_inode) { + i_tid.file.device = vma->vm_file->f_path.dentry->d_sb->s_dev; + i_tid.file.inode = vma->vm_file->f_path.dentry->d_inode->i_ino; + i_tid.file.dentry_p = vma->vm_file->f_path.dentry; + if ((err = rsbac_get_attr(SW_GEN, + T_FILE, + i_tid, + A_allow_write_exec, + &i_attr_val, + TRUE) )) + { + rsbac_ds_get_error("rsbac_write_exec_allowed()", A_allow_write_exec); + return 0; /* something weird happened */ + } + if (i_attr_val.allow_write_exec == AWX_true) { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_mprotect) + { + char * program_name = rsbac_get_program_name(); + char * help_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + help_name = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN); + if (help_name) { + if (!(rsbac_get_full_path(vma->vm_file->f_path.dentry, help_name, CONFIG_RSBAC_MAX_PATH_LEN - 1) > 0)) + strcpy(help_name, "(unknown)"); + } +#else + help_name = vma->vm_file->f_path.dentry->d_name.name; +#endif + rsbac_pr_debug(mprotect, "DYN ELF file %s has allow_write_exec true -> allow READ and WRITE, pid %u(%s)\n", + help_name, current->pid, program_name); +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (help_name) + rsbac_kfree(help_name); +#endif + if (program_name) + rsbac_kfree(program_name); + } +#endif + return 1; + } + if (prot == (PROT_READ | PROT_WRITE)) { + struct elfhdr elf_header; + + if (i_attr_val.allow_write_exec != AWX_relocate) { + i_tid.process = task_pid(current); + if ((err = rsbac_get_attr(SW_GEN, + T_PROCESS, + i_tid, + A_allow_write_exec, + &i_attr_val, + FALSE) )) + { + rsbac_ds_get_error("rsbac_write_exec_allowed()", A_allow_write_exec); + return 0; /* something weird happened */ + } + if (i_attr_val.allow_write_exec == AWX_true) { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_mprotect) + { + char * program_name = rsbac_get_program_name(); + char * help_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + help_name = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN); + if (help_name) { + if (!(rsbac_get_full_path(vma->vm_file->f_path.dentry, help_name, CONFIG_RSBAC_MAX_PATH_LEN - 1) > 0)) + strcpy(help_name, "(unknown)"); + } +#else + help_name = vma->vm_file->f_path.dentry->d_name.name; +#endif + rsbac_pr_debug(mprotect, "Process with %s has allow_write_exec true -> allow READ and WRITE, pid %u(%s)\n", + help_name, current->pid, program_name); +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (help_name) + rsbac_kfree(help_name); +#endif + if (program_name) + rsbac_kfree(program_name); + } +#endif + return 1; + } + } + if (i_attr_val.allow_write_exec == AWX_relocate) { + if (kernel_read(vma->vm_file, 0UL, (char *)&elf_header, sizeof(elf_header)) != sizeof(elf_header)) { + rsbac_pr_debug(mprotect, "ELF header read failed from %s, pid %u(%s)\n", + vma->vm_file->f_path.dentry->d_name.name, current->pid, current->comm); + } else if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG)) { + rsbac_pr_debug(mprotect, "ELF header invalid for %s, pid %u(%s)\n", + vma->vm_file->f_path.dentry->d_name.name, current->pid, current->comm); + } else if (elf_header.e_type != ET_DYN) { + rsbac_pr_debug(mprotect, "ELF file not DYN for %s, pid %u(%s)\n", + vma->vm_file->f_path.dentry->d_name.name, current->pid, current->comm); + } else { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_mprotect) + { + char * program_name = rsbac_get_program_name(); + char * help_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + help_name = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN); + if (help_name) { + if (!(rsbac_get_full_path(vma->vm_file->f_path.dentry, help_name, CONFIG_RSBAC_MAX_PATH_LEN - 1) > 0)) + strcpy(help_name, "(unknown)"); + } +#else + help_name = vma->vm_file->f_path.dentry->d_name.name; +#endif + rsbac_pr_debug(mprotect, "DYN ELF file %s -> allow READ and WRITE once for relocation, pid %u(%s)\n", + help_name, current->pid, program_name); +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (help_name) + rsbac_kfree(help_name); +#endif + if (program_name) + rsbac_kfree(program_name); + } +#endif + + vma->rsbac_mprotect_once = 1; + return 1; + } + } + } + } + } else if ((vma->rsbac_mprotect_once == 1) && (prot == (PROT_READ | PROT_EXEC))) { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_mprotect) + { + char * program_name = rsbac_get_program_name(); + + if (vma->vm_file->f_path.dentry) + { + char * help_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + help_name = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN); + if (help_name) { + if (!(rsbac_get_full_path(vma->vm_file->f_path.dentry, help_name, CONFIG_RSBAC_MAX_PATH_LEN - 1) > 0)) + strcpy(help_name, "(unknown)"); + } +#else + help_name = vma->vm_file->f_path.dentry->d_name.name; +#endif + +#ifdef CONFIG_RSBAC_SOFTMODE + if( rsbac_softmode +#ifdef CONFIG_RSBAC_SOFTMODE_IND + || rsbac_ind_softmode[SW_MPROTECT] +#endif + ) { + rsbac_pr_debug(mprotect, "DYN ELF file %s marked once -> allow to set back to READ and EXEC after relocation, softmode: do not disable future WRITE, pid %u(%s)\n", + help_name, current->pid, program_name); + } else { +#endif + rsbac_pr_debug(mprotect, "DYN ELF file %s marked once -> allow to set back to READ and EXEC after relocation and disable future WRITE, pid %u(%s)\n", + help_name, current->pid, program_name); +#ifdef CONFIG_RSBAC_SOFTMODE + } +#endif + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (help_name) + rsbac_kfree(help_name); +#endif + } + else + { +#ifdef CONFIG_RSBAC_SOFTMODE + if( rsbac_softmode +#ifdef CONFIG_RSBAC_SOFTMODE_IND + || rsbac_ind_softmode[SW_MPROTECT] +#endif + ) { + rsbac_pr_debug(mprotect, "DYN ELF file marked once -> allow to set back to READ and EXEC after relocation, softmode: do not disable future WRITE, pid %u(%s)\n", + current->pid, program_name); + } else { +#endif + rsbac_pr_debug(mprotect, "DYN ELF file marked once -> allow to set back to READ and EXEC after relocation and disable future WRITE, pid %u(%s)\n", + current->pid, program_name); +#ifdef CONFIG_RSBAC_SOFTMODE + } +#endif + } + if (program_name) + rsbac_kfree(program_name); + } +#endif + +#ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode +#ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MPROTECT] +#endif + ) { +#endif + vma->vm_flags &= ~VM_MAYWRITE; +#ifdef CONFIG_RSBAC_SOFTMODE + } +#endif + + vma->rsbac_mprotect_once = 2; + return 1; + } + } + return 0; + } +#endif + +int rsbac_set_audit_uid(rsbac_uid_t uid) + { + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val; + + if(!uid || (uid == __kuid_val(current_uid()))) + return 0; + + if (unlikely(in_interrupt())) + { + printk(KERN_WARNING "rsbac_set_audit_uid(): called from interrupt: pid %u(%s)!\n", + current->pid, current->comm); + dump_stack(); + return -RSBAC_EFROMINTERRUPT; + } + + tid.process = task_pid(current); + if (rsbac_get_attr(SW_GEN, + T_PROCESS, + tid, + A_audit_uid, + &attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_set_audit_uid()", A_audit_uid); + return -RSBAC_EREADFAILED; + } + if(attr_val.audit_uid != RSBAC_NO_USER) + return 0; + + if (rsbac_get_attr(SW_GEN, + T_PROCESS, + tid, + A_auid_exempt, + &attr_val, + FALSE)) + { + rsbac_ds_get_error("rsbac_set_audit_uid()", A_auid_exempt); + return -RSBAC_EREADFAILED; + } + if(attr_val.auid_exempt == uid) + return 0; + + attr_val.audit_uid = uid; + if (rsbac_set_attr(SW_GEN, + T_PROCESS, + tid, + A_audit_uid, + attr_val)) + { + rsbac_ds_set_error("rsbac_set_audit_uid()", A_audit_uid); + return -RSBAC_EWRITEFAILED; + } + return 0; + } + +#if defined(CONFIG_RSBAC_CAP_LOG_MISSING) || defined(CONFIG_RSBAC_JAIL_LOG_MISSING) +EXPORT_SYMBOL(rsbac_log_missing_cap); + +void rsbac_log_missing_cap(int cap) + { + #if defined(CONFIG_RSBAC_CAP_LOG_MISSING) || defined(CONFIG_RSBAC_CAP_LEARN) + #if defined(CONFIG_RSBAC_CAP_LOG_MISSING) && defined(CONFIG_RSBAC_CAP_LEARN) + if(rsbac_cap_log_missing || rsbac_cap_learn) + #elif defined(CONFIG_RSBAC_CAP_LEARN) + if(rsbac_cap_learn) + #else + if(rsbac_cap_log_missing) + #endif + rsbac_cap_log_missing_cap(cap); + #endif + #if defined(CONFIG_RSBAC_JAIL_LOG_MISSING) + if(rsbac_jail_log_missing) + rsbac_jail_log_missing_cap(cap); + #endif + } +#endif + +/* end of rsbac/adf/main.c */ diff --git a/rsbac/adf/auth/Makefile b/rsbac/adf/auth/Makefile new file mode 100644 index 000000000000..2d2f2b2c0df8 --- /dev/null +++ b/rsbac/adf/auth/Makefile @@ -0,0 +1,10 @@ +# +# File: rsbac/adf/auth/Makefile +# +# Makefile for the Linux rsbac auth decision module. +# +# Author and (c) 1999-2013 Amon Ott +# + +obj-y := auth_syscalls.o auth_main.o + diff --git a/rsbac/adf/auth/auth_main.c b/rsbac/adf/auth/auth_main.c new file mode 100644 index 000000000000..d39aa1c0ce82 --- /dev/null +++ b/rsbac/adf/auth/auth_main.c @@ -0,0 +1,1170 @@ +/**************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - Authorization module */ +/* File: rsbac/adf/auth/main.c */ +/* */ +/* Author and (c) 1999-2017: Amon Ott */ +/* */ +/* Last modified: 21/Mar/2017 */ +/**************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +static int rsbac_replace_auth_cap(rsbac_pid_t caller_pid, + enum rsbac_auth_cap_type_t cap_type, + rsbac_uid_t from, + rsbac_uid_t to) + { + if(rsbac_auth_p_capset_member(caller_pid, cap_type, from)) + { + struct rsbac_auth_cap_range_t cap_range; + + /* remove it and set cap for 'to' */ + cap_range.first = to; + cap_range.last = to; + if (rsbac_auth_add_to_p_capset(0, caller_pid, cap_type, cap_range, 0)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_auth(): rsbac_auth_add_to_p_capset() returned error!\n"); + return -RSBAC_EWRITEFAILED; + } + cap_range.first = from; + cap_range.last = from; + if (rsbac_auth_remove_from_p_capset(0, caller_pid, cap_type, cap_range)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_auth(): rsbac_auth_remove_from_p_capset() returned error!\n"); + return -RSBAC_EWRITEFAILED; + } + } + return 0; /* success */ + } + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +inline enum rsbac_adf_req_ret_t + rsbac_adf_request_auth (enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + enum rsbac_adf_req_ret_t result = DO_NOT_CARE; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_target_id_t i_tid; + + switch (request) + { +#if defined(CONFIG_RSBAC_AUTH_UM_PROT) || defined(CONFIG_RSBAC_AUTH_GROUP) + case R_CHANGE_GROUP: + switch(target) + { +#if defined(CONFIG_RSBAC_AUTH_UM_PROT) + case T_USER: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_AUTH, + T_USER, + i_tid, + A_auth_role, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_role); + return NOT_GRANTED; + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return GRANTED; + else + return NOT_GRANTED; +#endif /* AUTH_UM_PROT */ + +#if defined(CONFIG_RSBAC_AUTH_GROUP) + case T_PROCESS: + if(attr != A_group) + return NOT_GRANTED; +#if defined(CONFIG_RSBAC_AUTH_ALLOW_SAME) + if(attr_val.group == RSBAC_GEN_GID(RSBAC_UID_SET(owner),__kgid_val(current_gid()))) + return DO_NOT_CARE; +#endif + /* check auth_may_setuid of process */ + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_may_setuid, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_setuid); + return NOT_GRANTED; + } + /* if auth_may_setuid is full or and_gid, then grant */ + if( (i_attr_val1.auth_may_setuid == AMS_full) + || (i_attr_val1.auth_may_setuid == AMS_last_auth_and_gid) + ) + return GRANTED; + + /* check, if the target uid is in capset, grant, if yes, deny, if not. */ + if(rsbac_auth_p_capset_member(caller_pid, ACT_group_real, attr_val.group)) + return GRANTED; + else + return NOT_GRANTED; +#endif /* AUTH_GROUP */ + + /* We do not care about */ + /* all other cases */ + default: + return DO_NOT_CARE; + } +#endif /* AUTH_UM_PROT || AUTH_GROUP */ + +#if defined(CONFIG_RSBAC_AUTH_UM_PROT) + case R_CREATE: + case R_DELETE: + case R_GET_PERMISSIONS_DATA: + case R_RENAME: + case R_WRITE: + switch(target) + { + case T_USER: + case T_GROUP: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_AUTH, + T_USER, + i_tid, + A_auth_role, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_role); + return NOT_GRANTED; + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return GRANTED; + else + return NOT_GRANTED; + /* We do not care about */ + /* all other cases */ + default: return DO_NOT_CARE; + } +#endif + + case R_CHANGE_OWNER: + switch(target) + { + case T_PROCESS: + if(attr != A_owner) + return NOT_GRANTED; +#if defined(CONFIG_RSBAC_AUTH_ALLOW_SAME) + if(attr_val.owner == owner) + return DO_NOT_CARE; +#endif + /* check auth_may_setuid of process */ + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_may_setuid, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_setuid); + return NOT_GRANTED; + } + switch(i_attr_val1.auth_may_setuid) + { + case AMS_off: + break; + case AMS_full: + return GRANTED; + case AMS_last_auth_only: + case AMS_last_auth_and_gid: + if(attr_val.owner == RSBAC_NO_USER) + return NOT_GRANTED; + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_last_auth, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_last_auth); + return NOT_GRANTED; + } + if(i_attr_val1.auth_last_auth == attr_val.owner) + return GRANTED; + break; + + default: + rsbac_printk(KERN_INFO + "rsbac_adf_request_auth(): auth_may_setuid of process %u an invalid value %u!\n", + tid.process, i_attr_val1.auth_may_setuid); + return NOT_GRANTED; + } + /* check, if the target uid is in capset, grant, if yes, deny, if not. */ + if(rsbac_auth_p_capset_member(caller_pid, ACT_real, attr_val.owner)) + return GRANTED; + else + return NOT_GRANTED; + + /* all other cases are not checked */ + default: + return DO_NOT_CARE; + } + +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + case R_CHANGE_DAC_EFF_OWNER: + switch(target) + { + case T_PROCESS: + if(attr != A_owner) + return NOT_GRANTED; + if(attr_val.owner == owner) + return DO_NOT_CARE; +#if defined(CONFIG_RSBAC_AUTH_ALLOW_SAME) + if(attr_val.owner == __kuid_val(current_euid())) + return DO_NOT_CARE; +#endif + /* check auth_may_setuid of process */ + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_may_setuid, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_setuid); + return NOT_GRANTED; + } + switch(i_attr_val1.auth_may_setuid) + { + case AMS_off: + break; + case AMS_full: + return GRANTED; + case AMS_last_auth_only: + case AMS_last_auth_and_gid: + if(attr_val.owner == RSBAC_NO_USER) + return NOT_GRANTED; + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_last_auth, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_last_auth); + return NOT_GRANTED; + } + if(i_attr_val1.auth_last_auth == attr_val.owner) + return GRANTED; + break; + + default: + rsbac_printk(KERN_INFO + "rsbac_adf_request_auth(): auth_may_setuid of process %u has invalid value %u!\n", + tid.process, i_attr_val1.auth_may_setuid); + return NOT_GRANTED; + } + /* check, if the target uid is in capset, grant, if yes, deny, if not. */ + if(rsbac_auth_p_capset_member(caller_pid, ACT_eff, attr_val.owner)) + return GRANTED; + else + return NOT_GRANTED; + + /* all other cases are not checked */ + default: + return DO_NOT_CARE; + } + case R_CHANGE_DAC_FS_OWNER: + switch(target) + { + case T_PROCESS: + if(attr != A_owner) + return NOT_GRANTED; + if(attr_val.owner == owner) + return DO_NOT_CARE; +#if defined(CONFIG_RSBAC_AUTH_ALLOW_SAME) + if(attr_val.owner == __kuid_val(current_fsuid())) + return DO_NOT_CARE; +#endif + /* check auth_may_setuid of process */ + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_may_setuid, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_setuid); + return NOT_GRANTED; + } + switch(i_attr_val1.auth_may_setuid) + { + case AMS_off: + break; + case AMS_full: + return GRANTED; + case AMS_last_auth_only: + case AMS_last_auth_and_gid: + if(attr_val.owner == RSBAC_NO_USER) + return NOT_GRANTED; + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_last_auth, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_last_auth); + return NOT_GRANTED; + } + if(i_attr_val1.auth_last_auth == attr_val.owner) + return GRANTED; + break; + + default: + rsbac_printk(KERN_INFO + "rsbac_adf_request_auth(): auth_may_setuid of process %u has an invalid value!\n", + tid.process); + return NOT_GRANTED; + } + /* check, if the target uid is in capset, grant, if yes, deny, if not. */ + if(rsbac_auth_p_capset_member(caller_pid, ACT_fs, attr_val.owner)) + return GRANTED; + else + return NOT_GRANTED; + + /* all other cases are not checked */ + default: + return DO_NOT_CARE; + } +#endif + +#ifdef CONFIG_RSBAC_AUTH_GROUP +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case R_CHANGE_DAC_EFF_GROUP: + switch(target) + { + case T_PROCESS: + if(attr != A_group) + return NOT_GRANTED; + if(attr_val.group == RSBAC_GEN_GID(RSBAC_UID_SET(owner),__kgid_val(current_gid()))) + return DO_NOT_CARE; +#if defined(CONFIG_RSBAC_AUTH_ALLOW_SAME) + if(attr_val.group == RSBAC_GEN_GID(RSBAC_UID_SET(owner),__kgid_val(current_egid()))) + return DO_NOT_CARE; +#endif + /* check auth_may_setuid of process */ + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_may_setuid, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_setuid); + return NOT_GRANTED; + } + /* if auth_may_setuid is set, then grant */ + if( (i_attr_val1.auth_may_setuid == AMS_full) + || (i_attr_val1.auth_may_setuid == AMS_last_auth_and_gid) + ) + return GRANTED; + + /* check, if the target uid is in capset, grant, if yes, deny, if not. */ + if(rsbac_auth_p_capset_member(caller_pid, ACT_group_eff, attr_val.group)) + return GRANTED; + else + return NOT_GRANTED; + + /* all other cases are not checked */ + default: + return DO_NOT_CARE; + } + case R_CHANGE_DAC_FS_GROUP: + switch(target) + { + case T_PROCESS: + if(attr != A_group) + return NOT_GRANTED; + if(attr_val.group == RSBAC_GEN_GID(RSBAC_UID_SET(owner),__kgid_val(current_gid()))) + return DO_NOT_CARE; +#if defined(CONFIG_RSBAC_AUTH_ALLOW_SAME) + if(attr_val.group == RSBAC_GEN_GID(RSBAC_UID_SET(owner),__kgid_val(current_fsgid()))) + return DO_NOT_CARE; +#endif + /* check auth_may_setuid of process */ + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_may_setuid, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_setuid); + return NOT_GRANTED; + } + /* if auth_may_setuid is set, then grant */ + if( (i_attr_val1.auth_may_setuid == AMS_full) + || (i_attr_val1.auth_may_setuid == AMS_last_auth_and_gid) + ) + return GRANTED; + + /* check, if the target uid is in capset, grant, if yes, deny, if not. */ + if(rsbac_auth_p_capset_member(caller_pid, ACT_group_fs, attr_val.group)) + return GRANTED; + else + return NOT_GRANTED; + + /* all other cases are not checked */ + default: + return DO_NOT_CARE; + } +#endif +#endif /* AUTH_GROUP */ + + case R_MODIFY_ATTRIBUTE: + switch(attr) + { + /* Only protect itself, if asked to by configuration */ + #ifdef CONFIG_RSBAC_AUTH_AUTH_PROT + case A_system_role: + case A_auth_role: + case A_auth_may_setuid: + case A_auth_may_set_cap: + case A_auth_start_uid: + case A_auth_start_euid: + case A_auth_start_gid: + case A_auth_start_egid: + case A_auth_learn: + case A_auth_add_f_cap: + case A_auth_remove_f_cap: + /* All attributes (remove target!) */ + case A_none: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_AUTH, + T_USER, + i_tid, + A_auth_role, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_role); + return NOT_GRANTED; + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return GRANTED; + else + return NOT_GRANTED; + #endif + + case A_auth_last_auth: + if(target != T_PROCESS) + return DO_NOT_CARE; + /* check auth_may_set_cap of calling process */ + i_tid.process = task_pid(current); + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_may_set_cap, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_set_cap); + return -RSBAC_EREADFAILED; + } + /* if auth_may_set_cap is not set, then reject */ + if (!i_attr_val1.auth_may_set_cap) + { + rsbac_printk(KERN_INFO + "rsbac_adf_request_auth(): changing auth_last_auth of process %u to %u denied for process %u!\n", + tid.process, + attr_val.auth_last_auth, + task_pid(current)); + return NOT_GRANTED; + } + + default: + return DO_NOT_CARE; + } + +/* Only protect itself, if asked to by configuration */ +#ifdef CONFIG_RSBAC_AUTH_AUTH_PROT + case R_GET_STATUS_DATA: + switch(target) + { + case T_SCD: + /* target rsbac_log? only for secoff */ + if (tid.scd != ST_rsbac_log) + return GRANTED; + /* Secoff or Auditor? */ + i_tid.user = owner; + if ((rsbac_get_attr(SW_AUTH, + T_USER, + i_tid, + A_auth_role, + &i_attr_val1, + FALSE))) + { + rsbac_pr_get_error(A_auth_role); + return NOT_GRANTED; + } + /* grant only for secoff */ + if ( (i_attr_val1.system_role == SR_security_officer) + || (i_attr_val1.system_role == SR_auditor) + ) + return GRANTED; + else + return NOT_GRANTED; + + default: + return DO_NOT_CARE; + }; + + case R_MODIFY_PERMISSIONS_DATA: + switch(target) + { + case T_SCD: + #ifdef CONFIG_RSBAC_USER_MOD_IOPERM + if(tid.scd == ST_ioports) + return GRANTED; + #endif + /* fall through */ + #if defined(CONFIG_RSBAC_AUTH_UM_PROT) + case T_USER: + case T_GROUP: + #endif + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_AUTH, + T_USER, + i_tid, + A_auth_role, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_role); + return NOT_GRANTED; + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return GRANTED; + /* For booting: if administrator and ioports, then grant */ + if ( + #if defined(CONFIG_RSBAC_AUTH_UM_PROT) + (target == T_SCD) && + #endif + (i_attr_val1.system_role == SR_administrator) + && (tid.scd == ST_ioports) ) + return GRANTED; + else + return NOT_GRANTED; + + /* all other cases are not checked */ + default: return DO_NOT_CARE; + } + + case R_MODIFY_SYSTEM_DATA: + switch(target) + { + case T_SCD: + /* target not rsbac_log? no problem -> grant */ + switch(tid.scd) + { + case ST_rsbac_log: + case ST_rsbac_remote_log: + break; + case ST_kmem: + return NOT_GRANTED; + default: + return GRANTED; + } + /* Get role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_AUTH, + T_USER, + i_tid, + A_auth_role, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_role); + return NOT_GRANTED; + } + /* grant only for secoff and auditor */ + if ( (i_attr_val1.system_role == SR_security_officer) + || (i_attr_val1.system_role == SR_auditor) + ) + return GRANTED; + else + return NOT_GRANTED; + + /* all other cases are not checked */ + default: return DO_NOT_CARE; + } + + case R_SWITCH_LOG: + switch(target) + { + case T_NONE: + /* test owner's auth_role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_AUTH, + T_USER, + i_tid, + A_auth_role, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_role); + return NOT_GRANTED; + } + /* security officer? -> grant */ + if (i_attr_val1.system_role == SR_security_officer) + return GRANTED; + else + return NOT_GRANTED; + + /* all other cases are not checked */ + default: return DO_NOT_CARE; + } + + case R_SWITCH_MODULE: + switch(target) + { + case T_NONE: + /* we need the switch_target */ + if(attr != A_switch_target) + return NOT_GRANTED; +#ifndef CONFIG_RSBAC_AUTH_OTHER_PROT + /* do not care for other modules */ + if( (attr_val.switch_target != SW_AUTH) + #ifdef CONFIG_RSBAC_SOFTMODE + && (attr_val.switch_target != SW_SOFTMODE) + #endif + #ifdef CONFIG_RSBAC_FREEZE + && (attr_val.switch_target != SW_FREEZE) + #endif + #ifdef CONFIG_RSBAC_MPROTECT + && (attr_val.switch_target != SW_MPROTECT) + #endif + ) + return DO_NOT_CARE; +#endif + /* test owner's auth_role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_AUTH, + T_USER, + i_tid, + A_auth_role, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_role); + return NOT_GRANTED; + } + /* security officer? -> grant */ + if (i_attr_val1.system_role == SR_security_officer) + return GRANTED; + else + return NOT_GRANTED; + + /* all other cases are not checked */ + default: return DO_NOT_CARE; + } +#endif + +/*********************/ + default: return DO_NOT_CARE; + } + + return result; + } /* end of rsbac_adf_request_auth() */ + + +/*****************************************************************************/ +/* If the request returned granted and the operation is performed, */ +/* the following function can be called by the AEF to get all aci set */ +/* correctly. For write accesses that are performed fully within the kernel, */ +/* this is usually not done to prevent extra calls, including R_CLOSE for */ +/* cleaning up. */ +/* The second instance of target specification is the new target, if one has */ +/* been created, otherwise its values are ignored. */ +/* On success, 0 is returned, and an error from rsbac/error.h otherwise. */ + +inline int rsbac_adf_set_attr_auth( + enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + int error; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_attribute_value_t i_attr_val2; + #if defined(CONFIG_RSBAC_AUTH_LEARN) + union rsbac_attribute_value_t i_attr_val3; + union rsbac_attribute_value_t i_attr_val4; + #endif + + switch (request) + { + case R_CLONE: + if (target == T_PROCESS) + { + /* Get auth_may_setuid from first process */ + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_may_setuid, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_setuid); + return -RSBAC_EREADFAILED; + } + /* Get auth_may_set_cap from first process */ + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_may_set_cap, + &i_attr_val2, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_set_cap); + return -RSBAC_EREADFAILED; + } + #if defined(CONFIG_RSBAC_AUTH_LEARN) + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_start_uid, + &i_attr_val3, + FALSE)) + { + rsbac_pr_get_error(A_auth_start_uid); + return -RSBAC_EREADFAILED; + } + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_learn, + &i_attr_val4, + FALSE)) + { + rsbac_pr_get_error(A_auth_learn); + return -RSBAC_EREADFAILED; + } + #endif + /* Set auth_may_setuid for new process */ + if (i_attr_val1.auth_may_setuid && rsbac_set_attr(SW_AUTH, + T_PROCESS, + new_tid, + A_auth_may_setuid, + i_attr_val1)) + { + rsbac_pr_set_error(A_auth_may_setuid); + return -RSBAC_EWRITEFAILED; + } + /* Set auth_may_set_cap for new process */ + if (i_attr_val2.auth_may_set_cap && rsbac_set_attr(SW_AUTH, + T_PROCESS, + new_tid, + A_auth_may_set_cap, + i_attr_val2)) + { + rsbac_pr_set_error(A_auth_may_set_cap); + return -RSBAC_EWRITEFAILED; + } + #if defined(CONFIG_RSBAC_AUTH_LEARN) + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + new_tid, + A_auth_start_uid, + i_attr_val3)) + { + rsbac_pr_set_error(A_auth_start_uid); + return -RSBAC_EWRITEFAILED; + } + if (i_attr_val4.auth_learn && rsbac_set_attr(SW_AUTH, + T_PROCESS, + new_tid, + A_auth_learn, + i_attr_val4)) + { + rsbac_pr_set_error(A_auth_learn); + return -RSBAC_EWRITEFAILED; + } + #ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_start_euid, + &i_attr_val4, + FALSE)) + { + rsbac_pr_get_error(A_auth_start_uid); + return -RSBAC_EREADFAILED; + } + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + new_tid, + A_auth_start_euid, + i_attr_val4)) + { + rsbac_pr_set_error(A_auth_start_uid); + return -RSBAC_EWRITEFAILED; + } + #endif + #ifdef CONFIG_RSBAC_AUTH_GROUP + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_start_gid, + &i_attr_val4, + FALSE)) + { + rsbac_pr_get_error(A_auth_start_uid); + return -RSBAC_EREADFAILED; + } + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + new_tid, + A_auth_start_gid, + i_attr_val4)) + { + rsbac_pr_set_error(A_auth_start_uid); + return -RSBAC_EWRITEFAILED; + } + #ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_start_egid, + &i_attr_val4, + FALSE)) + { + rsbac_pr_get_error(A_auth_start_uid); + return -RSBAC_EREADFAILED; + } + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + new_tid, + A_auth_start_egid, + i_attr_val4)) + { + rsbac_pr_set_error(A_auth_start_uid); + return -RSBAC_EWRITEFAILED; + } + #endif + #endif + #endif + /* copy auth_last_auth */ + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + tid, + A_auth_last_auth, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_last_auth); + return -RSBAC_EREADFAILED; + } + if ((i_attr_val1.auth_last_auth != RSBAC_NO_USER) && rsbac_set_attr(SW_AUTH, + T_PROCESS, + new_tid, + A_auth_last_auth, + i_attr_val1)) + { + rsbac_pr_set_error(A_auth_last_auth); + return -RSBAC_EWRITEFAILED; + } + /* copy capability list */ + if(rsbac_auth_copy_pp_capset(tid.process,new_tid.process)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_auth(): rsbac_auth_copy_pp_capset() returned error!\n"); + return -RSBAC_EWRITEFAILED; + } + return 0; + } + else + return 0; + + case R_EXECUTE: + switch(target) + { + case T_FILE: + /* reset auth_may_setuid and auth_may_set_cap for process */ + i_tid.process = caller_pid; + /* First, set auth_may_setuid to program file's auth_may_setuid */ + if (rsbac_get_attr(SW_AUTH, + T_FILE, + tid, + A_auth_may_setuid, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_setuid); + return -RSBAC_EREADFAILED; + } + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_may_setuid, + i_attr_val1)) + { + rsbac_pr_set_error(A_auth_may_setuid); + return -RSBAC_EWRITEFAILED; + } + /* Next, set auth_may_set_cap to program file's auth_may_set_cap */ + if (rsbac_get_attr(SW_AUTH, + T_FILE, + tid, + A_auth_may_set_cap, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_set_cap); + return -RSBAC_EREADFAILED; + } + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_may_set_cap, + i_attr_val1)) + { + rsbac_pr_set_error(A_auth_may_set_cap); + return -RSBAC_EWRITEFAILED; + } + /* reset auth_last_auth for process */ + i_attr_val1.auth_last_auth = RSBAC_NO_USER; + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_last_auth, + i_attr_val1)) + { + rsbac_pr_set_error(A_auth_last_auth); + } + + /* copy file capability list from file to process */ + if (rsbac_auth_copy_fp_capset(tid.file, caller_pid)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_auth(): rsbac_auth_copy_fp_capset() returned error!\n"); + return -RSBAC_EWRITEFAILED; + } + /* replace RSBAC_AUTH_OWNER_F_CAP by current owner */ + error = rsbac_replace_auth_cap(caller_pid, + ACT_real, + RSBAC_AUTH_OWNER_F_CAP, + owner); + if(error) + return error; + #ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + error = rsbac_replace_auth_cap(caller_pid, + ACT_eff, + RSBAC_AUTH_OWNER_F_CAP, + owner); + if(error) + return error; + error = rsbac_replace_auth_cap(caller_pid, + ACT_eff, + RSBAC_AUTH_DAC_OWNER_F_CAP, + __kuid_val(current_euid())); + if(error) + return error; + error = rsbac_replace_auth_cap(caller_pid, + ACT_fs, + RSBAC_AUTH_OWNER_F_CAP, + owner); + if(error) + return error; + error = rsbac_replace_auth_cap(caller_pid, + ACT_fs, + RSBAC_AUTH_DAC_OWNER_F_CAP, + __kuid_val(current_fsuid())); + if(error) + return error; + #endif + #ifdef CONFIG_RSBAC_AUTH_GROUP + error = rsbac_replace_auth_cap(caller_pid, + ACT_group_real, + RSBAC_AUTH_GROUP_F_CAP, + __kgid_val(current_gid())); + if(error) + return error; + #ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + error = rsbac_replace_auth_cap(caller_pid, + ACT_group_eff, + RSBAC_AUTH_GROUP_F_CAP, + __kgid_val(current_gid())); + if(error) + return error; + error = rsbac_replace_auth_cap(caller_pid, + ACT_group_eff, + RSBAC_AUTH_DAC_GROUP_F_CAP, + __kgid_val(current_egid())); + if(error) + return error; + error = rsbac_replace_auth_cap(caller_pid, + ACT_group_fs, + RSBAC_AUTH_GROUP_F_CAP, + __kgid_val(current_gid())); + if(error) + return error; + error = rsbac_replace_auth_cap(caller_pid, + ACT_group_fs, + RSBAC_AUTH_DAC_GROUP_F_CAP, + __kgid_val(current_fsgid())); + if(error) + return error; + #endif + #endif + + #if defined(CONFIG_RSBAC_AUTH_LEARN) + /* Set auth_learn to program file's auth_learn */ + if (rsbac_get_attr(SW_AUTH, + T_FILE, + tid, + A_auth_learn, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_learn); + return -RSBAC_EREADFAILED; + } + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_learn, + i_attr_val1)) + { + rsbac_pr_set_error(A_auth_learn); + return -RSBAC_EWRITEFAILED; + } + /* remember caller */ + i_attr_val1.auth_start_uid = owner; + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_start_uid, + i_attr_val1)) + { + rsbac_pr_set_error(A_auth_start_uid); + return -RSBAC_EWRITEFAILED; + } + #ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + i_attr_val1.auth_start_euid = __kuid_val(current_euid()); + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_start_euid, + i_attr_val1)) + { + rsbac_pr_set_error(A_auth_start_euid); + return -RSBAC_EWRITEFAILED; + } + #endif + #ifdef CONFIG_RSBAC_AUTH_GROUP + i_attr_val1.auth_start_gid = __kgid_val(current_gid()); + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_start_gid, + i_attr_val1)) + { + rsbac_pr_set_error(A_auth_start_gid); + return -RSBAC_EWRITEFAILED; + } + #ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + i_attr_val1.auth_start_egid = __kgid_val(current_egid()); + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_start_egid, + i_attr_val1)) + { + rsbac_pr_set_error(A_auth_start_egid); + return -RSBAC_EWRITEFAILED; + } + #endif + #endif + #endif + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + +/* Only protect itself, if asked to by configuration */ +#ifdef CONFIG_RSBAC_AUTH_AUTH_PROT + /* remove all file capabilities on all changing requests to files */ + case R_APPEND_OPEN: + case R_CHANGE_GROUP: + case R_DELETE: + case R_LINK_HARD: + case R_MODIFY_ACCESS_DATA: + case R_READ_WRITE_OPEN: + case R_RENAME: + case R_TRUNCATE: + case R_WRITE_OPEN: + switch(target) + { + case T_FILE: + /* remove cap set */ + if(rsbac_auth_remove_f_capsets(tid.file)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_auth(): rsbac_auth_remove_f_capsets() returned error!\n"); + return -RSBAC_EWRITEFAILED; + } + return 0; + + /* all other cases are not handled */ + default: return 0; + } +#endif + +/*********************/ + default: return 0; + } + + return 0; + } /* end of rsbac_adf_set_attr_auth() */ + +/* end of rsbac/adf/auth/main.c */ diff --git a/rsbac/adf/auth/auth_syscalls.c b/rsbac/adf/auth/auth_syscalls.c new file mode 100644 index 000000000000..fc85d30e5638 --- /dev/null +++ b/rsbac/adf/auth/auth_syscalls.c @@ -0,0 +1,156 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - Authentification module */ +/* File: rsbac/adf/auth/syscalls.c */ +/* */ +/* Author and (c) 1999-2013: Amon Ott */ +/* */ +/* Last modified: 09/Aug/2013 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +int rsbac_auth_add_p_cap( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range, + rsbac_time_t ttl) + { +/* check only in non-maint mode */ +#ifdef CONFIG_RSBAC_SWITCH_AUTH + if(rsbac_switch_auth) +#endif + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + /* check auth_may_set_cap of calling process */ + i_tid.process = task_pid(current); + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_may_set_cap, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_set_cap); + return -RSBAC_EREADFAILED; + } + /* if auth_may_set_cap is not set, then reject */ + if (!i_attr_val1.auth_may_set_cap) + { + rsbac_printk(KERN_INFO + "rsbac_auth_add_p_cap(): adding AUTH cap %u:%u to process %u denied for process %u!\n", + cap_range.first, + cap_range.last, + pid, + task_pid(current)); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_AUTH] + #endif + ) + #endif + return(-EPERM); + } + } + + /* OK, check passed. Add the capability. */ + return rsbac_auth_add_to_p_capset(ta_number, pid, cap_type, cap_range, ttl); + } + +int rsbac_auth_remove_p_cap( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range) + { +#ifdef CONFIG_RSBAC_SWITCH_AUTH + if(rsbac_switch_auth) +#endif + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + /* check auth_may_set_cap of calling process */ + i_tid.process = task_pid(current); + if (rsbac_get_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_may_set_cap, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_auth_may_set_cap); + return -RSBAC_EREADFAILED; + } + /* if auth_may_set_cap is not set, then reject */ + if (!i_attr_val1.auth_may_set_cap) + { + rsbac_printk(KERN_INFO + "rsbac_auth_remove_p_cap(): removing AUTH cap %u:%u from process %u denied for process %u!\n", + cap_range.first, + cap_range.last, + pid, + task_pid(current)); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_AUTH] + #endif + ) + #endif + return(-EPERM); + } + } + + /* OK, check passed. Try to remove the capability. */ + return rsbac_auth_remove_from_p_capset(ta_number, pid, cap_type, cap_range); + } + +int rsbac_auth_add_f_cap( + rsbac_list_ta_number_t ta_number, + rsbac_auth_file_t file, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range, + rsbac_time_t ttl) + { + /* check has been done in help/syscalls.c: sys_rsbac_auth_add_f_cap */ + return rsbac_auth_add_to_f_capset(ta_number, file, cap_type, cap_range, ttl); + } + +int rsbac_auth_remove_f_cap( + rsbac_list_ta_number_t ta_number, + rsbac_auth_file_t file, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range) + { + /* check has been done in help/syscalls.c: sys_rsbac_auth_remove_f_cap */ + return rsbac_auth_remove_from_f_capset(ta_number, file, cap_type, cap_range); + } + +/* end of rsbac/adf/auth/syscalls.c */ diff --git a/rsbac/adf/cap/Makefile b/rsbac/adf/cap/Makefile new file mode 100644 index 000000000000..34117649fc98 --- /dev/null +++ b/rsbac/adf/cap/Makefile @@ -0,0 +1,10 @@ +# +# File: rsbac/adf/cap/Makefile +# +# Makefile for the Linux rsbac cap decision module. +# +# Author and (c) 1999-2012 Amon Ott +# + +obj-y := cap_main.o + diff --git a/rsbac/adf/cap/cap_main.c b/rsbac/adf/cap/cap_main.c new file mode 100644 index 000000000000..363eaba379bd --- /dev/null +++ b/rsbac/adf/cap/cap_main.c @@ -0,0 +1,946 @@ +/**************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - Linux Capabilities (CAP) */ +/* File: rsbac/adf/cap/main.c */ +/* */ +/* Author and (c) 1999-2016: Amon Ott */ +/* */ +/* Last modified: 01/Aug/2016 */ +/**************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +inline enum rsbac_adf_req_ret_t + rsbac_adf_request_cap (enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + switch (request) + { + case R_MODIFY_ATTRIBUTE: + switch(attr) + { + case A_system_role: + case A_cap_role: + case A_min_caps: + case A_max_caps: + case A_max_caps_user: + case A_max_caps_program: + case A_cap_process_hiding: + case A_cap_learn: + #ifdef CONFIG_RSBAC_CAP_AUTH_PROT + case A_auth_may_setuid: + case A_auth_may_set_cap: + case A_auth_start_uid: + case A_auth_start_euid: + case A_auth_start_gid: + case A_auth_start_egid: + case A_auth_learn: + case A_auth_add_f_cap: + case A_auth_remove_f_cap: + #endif + /* All attributes (remove target!) */ + case A_none: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_cap_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_cap()", A_cap_role); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + default: + return(DO_NOT_CARE); + } + + case R_READ_ATTRIBUTE: + switch(attr) + { + case A_system_role: + case A_cap_role: + case A_min_caps: + case A_max_caps: + case A_max_caps_user: + case A_max_caps_program: + case A_cap_process_hiding: + /* All attributes (remove target!) */ + case A_none: + /* Security Officer or Admin? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_cap_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_cap()", A_cap_role); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if( (i_attr_val1.system_role == SR_security_officer) + || (i_attr_val1.system_role == SR_administrator) + ) + return(GRANTED); + else + return(NOT_GRANTED); + + default: + return(DO_NOT_CARE); + } + + case R_SWITCH_LOG: + switch(target) + { + case T_NONE: + /* test owner's cap_role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_cap_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_cap()", A_cap_role); + return(NOT_GRANTED); + } + /* security officer? -> grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + /* all other cases are unknown */ + default: return(DO_NOT_CARE); + } + + case R_SWITCH_MODULE: + switch(target) + { + case T_NONE: + /* we need the switch_target */ + if(attr != A_switch_target) + return NOT_GRANTED; + /* do not care for other modules */ + if( (attr_val.switch_target != SW_CAP) + #ifdef CONFIG_RSBAC_CAP_AUTH_PROT + && (attr_val.switch_target != SW_AUTH) + #endif + #ifdef CONFIG_RSBAC_SOFTMODE + && (attr_val.switch_target != SW_SOFTMODE) + #endif + #ifdef CONFIG_RSBAC_FREEZE + && (attr_val.switch_target != SW_FREEZE) + #endif + #ifdef CONFIG_RSBAC_MPROTECT + && (attr_val.switch_target != SW_MPROTECT) + #endif + ) + return(DO_NOT_CARE); + /* test owner's cap_role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_cap_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_cap()", A_cap_role); + return(NOT_GRANTED); + } + /* security officer? -> grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + +#ifdef CONFIG_RSBAC_CAP_PROC_HIDE + case R_CHANGE_GROUP: + case R_GET_STATUS_DATA: + case R_MODIFY_SYSTEM_DATA: + case R_SEND_SIGNAL: + case R_TRACE: + switch(target) + { + case T_PROCESS: + if(caller_pid == tid.process) + return GRANTED; + if (rsbac_get_attr(SW_CAP, + target, + tid, + A_cap_process_hiding, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_cap()", A_cap_process_hiding); + return(NOT_GRANTED); /* something weird happened */ + } + switch(i_attr_val1.cap_process_hiding) + { + case PH_full: + /* Security Officer or Admin? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_cap_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_cap()", A_cap_role); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if(i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + case PH_from_other_users: + { + struct task_struct * task_p; + enum rsbac_adf_req_ret_t result; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (rsbac_get_attr(SW_GEN, + T_PROCESS, + tid, + A_vset, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_cap()", A_vset); + return(NOT_GRANTED); + } + if (i_attr_val1.vset == RSBAC_UID_SET(owner)) +#endif + { + task_p = get_pid_task(tid.process, PIDTYPE_PID); + if(task_p) { + if( pid_alive(task_p) + && (__kuid_val(task_uid(task_p)) != RSBAC_UID_NUM(owner)) + ) { + result = NOT_GRANTED; + } else { + result = GRANTED; + } + put_task_struct(task_p); + } else { + result = GRANTED; + } + if(result == GRANTED) + return GRANTED; + } + /* Security Officer or Admin? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_cap_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_cap()", A_cap_role); + return(NOT_GRANTED); + } + /* if sec_officer or admin, then grant */ + if( (i_attr_val1.system_role == SR_security_officer) + || (i_attr_val1.system_role == SR_administrator) + ) + return(GRANTED); + else + return(NOT_GRANTED); + } + default: + return DO_NOT_CARE; + } + + default: + return DO_NOT_CARE; + } +#endif + +/*********************/ + default: return DO_NOT_CARE; + } + + return DO_NOT_CARE; + } /* end of rsbac_adf_request_cap() */ + + +/*****************************************************************************/ +/* If the request returned granted and the operation is performed, */ +/* the following function can be called by the AEF to get all aci set */ +/* correctly. For write accesses that are performed fully within the kernel, */ +/* this is usually not done to prevent extra calls, including R_CLOSE for */ +/* cleaning up. */ +/* The second instance of target specification is the new target, if one has */ +/* been created, otherwise its values are ignored. */ +/* On success, 0 is returned, and an error from rsbac/error.h otherwise. */ + +inline int rsbac_adf_set_attr_cap( + enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + switch (request) + { + case R_CHANGE_OWNER: + switch(target) + { + case T_PROCESS: + if(attr != A_owner) + return(-RSBAC_EINVALIDATTR); + i_tid.user = attr_val.owner; + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_cap_ld_env, + &i_attr_val1, TRUE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_cap()", + A_max_caps); + } else { + if (i_attr_val1.cap_ld_env == LD_keep) { + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_CAP, + T_PROCESS, + i_tid, + A_cap_ld_env, + &i_attr_val1, FALSE)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_cap()", + A_cap_ld_env); + } else { + if (rsbac_set_attr(SW_CAP, + T_PROCESS, + tid, + A_cap_ld_env, + i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_cap()", + A_cap_ld_env); + } + } + } + } + /* Adjust Linux caps */ + i_tid.user = attr_val.owner; + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_max_caps, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_cap()", A_max_caps); + } + else + { + #ifdef CONFIG_RSBAC_SOFTMODE + if( rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + || rsbac_ind_softmode[SW_CAP] + #endif + ) + { /* Warn */ + if((i_attr_val1.max_caps.cap[0] != RSBAC_CAP_DEFAULT_MAX) || (i_attr_val1.max_caps.cap[1] != RSBAC_CAP_DEFAULT_MAX)) + { + rsbac_printk(KERN_NOTICE + "rsbac_adf_set_attr_cap(): running in softmode, max_caps of user %u not applied to process %u(%s)!\n", + owner, + pid_nr(caller_pid), + current->comm); + } + } + else + #endif + { + /* set caps for process */ + struct cred *override_cred; + override_cred = prepare_creds(); + if (!override_cred) + return -ENOMEM; + if ( ((override_cred->cap_permitted.cap[0] & i_attr_val1.max_caps.cap[0]) != override_cred->cap_permitted.cap[0]) + || ((override_cred->cap_effective.cap[0] & i_attr_val1.max_caps.cap[0]) != override_cred->cap_effective.cap[0]) + || ((override_cred->cap_inheritable.cap[0] & i_attr_val1.max_caps.cap[0]) != override_cred->cap_inheritable.cap[0]) + || ((override_cred->cap_permitted.cap[1] & i_attr_val1.max_caps.cap[1]) != override_cred->cap_permitted.cap[1]) + || ((override_cred->cap_effective.cap[1] & i_attr_val1.max_caps.cap[1]) != override_cred->cap_effective.cap[1]) + || ((override_cred->cap_inheritable.cap[1] & i_attr_val1.max_caps.cap[1]) != override_cred->cap_inheritable.cap[1]) + ) { + override_cred->cap_permitted.cap[0] &= i_attr_val1.max_caps.cap[0]; + override_cred->cap_effective.cap[0] &= i_attr_val1.max_caps.cap[0]; + override_cred->cap_inheritable.cap[0] &= i_attr_val1.max_caps.cap[0]; + override_cred->cap_permitted.cap[1] &= i_attr_val1.max_caps.cap[1]; + override_cred->cap_effective.cap[1] &= i_attr_val1.max_caps.cap[1]; + override_cred->cap_inheritable.cap[1] &= i_attr_val1.max_caps.cap[1]; + commit_creds(override_cred); + } else { + abort_creds(override_cred); + } + +#ifdef CONFIG_RSBAC_CAP_LOG_MISSING + /* set max_caps_user for process */ + if (rsbac_set_attr(SW_CAP, + target, + tid, + A_max_caps_user, + i_attr_val1)) + { + rsbac_ds_set_error("rsbac_adf_set_attr_cap()", A_max_caps_user); + } +#endif + } + } + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_min_caps, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_cap()", A_min_caps); + } + else + { + /* set caps for process */ + { + struct cred *override_cred; + override_cred = prepare_creds(); + if (!override_cred) + return -ENOMEM; + if ( ((override_cred->cap_permitted.cap[0] | i_attr_val1.min_caps.cap[0]) != override_cred->cap_permitted.cap[0]) + || ((override_cred->cap_effective.cap[0] | i_attr_val1.min_caps.cap[0]) != override_cred->cap_effective.cap[0]) + || ((override_cred->cap_inheritable.cap[0] | i_attr_val1.min_caps.cap[0]) != override_cred->cap_inheritable.cap[0]) + || ((override_cred->cap_permitted.cap[1] | i_attr_val1.min_caps.cap[1]) != override_cred->cap_permitted.cap[1]) + || ((override_cred->cap_effective.cap[1] | i_attr_val1.min_caps.cap[1]) != override_cred->cap_effective.cap[1]) + || ((override_cred->cap_inheritable.cap[1] | i_attr_val1.min_caps.cap[1]) != override_cred->cap_inheritable.cap[1]) + ) { + override_cred->cap_permitted.cap[0] |= i_attr_val1.max_caps.cap[0]; + override_cred->cap_effective.cap[0] |= i_attr_val1.max_caps.cap[0]; + override_cred->cap_inheritable.cap[0] |= i_attr_val1.max_caps.cap[0]; + override_cred->cap_permitted.cap[1] |= i_attr_val1.max_caps.cap[1]; + override_cred->cap_effective.cap[1] |= i_attr_val1.max_caps.cap[1]; + override_cred->cap_inheritable.cap[1] |= i_attr_val1.max_caps.cap[1]; + commit_creds(override_cred); + } else { + abort_creds(override_cred); + } + } + } + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + break; + +#if defined (CONFIG_RSBAC_CAP_PROC_HIDE) || defined(CONFIG_RSBAC_CAP_LOG_MISSING) + case R_CLONE: + switch(target) + { + case T_PROCESS: + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_CAP, + target, + i_tid, + A_cap_ld_env, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_cap()", + A_cap_ld_env); + } else { + if ((i_attr_val1.cap_ld_env != LD_allow) && rsbac_set_attr(SW_CAP, + new_target, + new_tid, + A_cap_ld_env, + i_attr_val1)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_cap()", + A_cap_ld_env); + } + } +#ifdef CONFIG_RSBAC_CAP_PROC_HIDE + /* get process hiding from old process */ + if (rsbac_get_attr(SW_CAP, + target, + tid, + A_cap_process_hiding, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_cap()", A_cap_process_hiding); + } + else + { /* only set, of not default value 0 */ + if(i_attr_val1.cap_process_hiding) + { + /* set program based log for new process */ + if (rsbac_set_attr(SW_CAP, + new_target, + new_tid, + A_cap_process_hiding, + i_attr_val1)) + { + rsbac_ds_set_error("rsbac_adf_set_attr_cap()", A_cap_process_hiding); + } + } + } +#endif +#ifdef CONFIG_RSBAC_CAP_LOG_MISSING + /* get max_caps_user from old process */ + if (rsbac_get_attr(SW_CAP, + target, + tid, + A_max_caps_user, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_cap():CLONE", A_max_caps_user); + } + else + { /* only set, of not default value */ + if((i_attr_val1.max_caps_user.cap[0] != RSBAC_CAP_DEFAULT_MAX) || (i_attr_val1.max_caps_user.cap[1] != RSBAC_CAP_DEFAULT_MAX)) + { + if (rsbac_set_attr(SW_CAP, + new_target, + new_tid, + A_max_caps_user, + i_attr_val1)) + { + rsbac_ds_set_error("rsbac_adf_set_attr_cap():CLONE", A_max_caps_user); + } + } + } + /* get max_caps_program from old process */ + if (rsbac_get_attr(SW_CAP, + target, + tid, + A_max_caps_program, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_cap():CLONE", A_max_caps_program); + } + else + { /* only set, of not default value */ + if((i_attr_val1.max_caps_program.cap[0] != RSBAC_CAP_DEFAULT_MAX) || (i_attr_val1.max_caps_program.cap[1] != RSBAC_CAP_DEFAULT_MAX)) + { + if (rsbac_set_attr(SW_CAP, + new_target, + new_tid, + A_max_caps_program, + i_attr_val1)) + { + rsbac_ds_set_error("rsbac_adf_set_attr_cap():CLONE", A_max_caps_program); + } + } + } +#endif + return 0; + + /* all other cases are unknown */ + default: + return 0; + } +#endif /* PROC_HIDE || LOG_MISSING */ + + case R_EXECUTE: + switch(target) + { + case T_FILE: + i_tid.user = owner; + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_cap_ld_env, + &i_attr_val1, TRUE)) { + rsbac_ds_get_error("rsbac_adf_set_attr_cap()",A_cap_ld_env); + } else { + if (i_attr_val1.cap_ld_env == LD_keep) { + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_CAP, + T_PROCESS, + i_tid, + A_cap_ld_env, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error("rsbac_adf_set_attr_cap()", + A_cap_ld_env); + } + i_tid.process = caller_pid; + if (rsbac_set_attr(SW_CAP, + T_PROCESS, + i_tid, + A_cap_ld_env, + i_attr_val1)) { + rsbac_ds_get_error("rsbac_adf_set_attr_cap()", + A_cap_ld_env); + } + } + } + /* Adjust Linux caps - first user, then program based */ + /* User must be redone, because caps are cleared by Linux kernel */ + i_tid.user = owner; + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_max_caps, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_cap()", A_max_caps); + } + else + { + #ifdef CONFIG_RSBAC_SOFTMODE + if( rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + || rsbac_ind_softmode[SW_CAP] + #endif + ) + { /* Warn */ + if((i_attr_val1.max_caps.cap[0] != RSBAC_CAP_DEFAULT_MAX) || (i_attr_val1.max_caps.cap[1] != RSBAC_CAP_DEFAULT_MAX)) + { + rsbac_printk(KERN_NOTICE + "rsbac_adf_set_attr_cap(): running in softmode, max_caps of user %u not applied to process %u(%s)!\n", + owner, + pid_nr(caller_pid), + current->comm); + } + } + else + #endif + { + struct cred *override_cred; + override_cred = prepare_creds(); + if (!override_cred) + return -ENOMEM; + if ( ((override_cred->cap_permitted.cap[0] & i_attr_val1.max_caps.cap[0]) != override_cred->cap_permitted.cap[0]) + || ((override_cred->cap_effective.cap[0] & i_attr_val1.max_caps.cap[0]) != override_cred->cap_effective.cap[0]) + || ((override_cred->cap_inheritable.cap[0] & i_attr_val1.max_caps.cap[0]) != override_cred->cap_inheritable.cap[0]) + || ((override_cred->cap_permitted.cap[1] & i_attr_val1.max_caps.cap[1]) != override_cred->cap_permitted.cap[1]) + || ((override_cred->cap_effective.cap[1] & i_attr_val1.max_caps.cap[1]) != override_cred->cap_effective.cap[1]) + || ((override_cred->cap_inheritable.cap[1] & i_attr_val1.max_caps.cap[1]) != override_cred->cap_inheritable.cap[1]) + ) { + override_cred->cap_permitted.cap[0] &= i_attr_val1.max_caps.cap[0]; + override_cred->cap_effective.cap[0] &= i_attr_val1.max_caps.cap[0]; + override_cred->cap_inheritable.cap[0] &= i_attr_val1.max_caps.cap[0]; + override_cred->cap_permitted.cap[1] &= i_attr_val1.max_caps.cap[1]; + override_cred->cap_effective.cap[1] &= i_attr_val1.max_caps.cap[1]; + override_cred->cap_inheritable.cap[1] &= i_attr_val1.max_caps.cap[1]; + commit_creds(override_cred); + } else { + abort_creds(override_cred); + } + } + } + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_min_caps, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_cap()", A_min_caps); + } + else + { + /* set caps for process */ + struct cred *override_cred; + override_cred = prepare_creds(); + if (!override_cred) + return -ENOMEM; + if ( ((override_cred->cap_permitted.cap[0] | i_attr_val1.min_caps.cap[0]) != override_cred->cap_permitted.cap[0]) + || ((override_cred->cap_effective.cap[0] | i_attr_val1.min_caps.cap[0]) != override_cred->cap_effective.cap[0]) + || ((override_cred->cap_inheritable.cap[0] | i_attr_val1.min_caps.cap[0]) != override_cred->cap_inheritable.cap[0]) + || ((override_cred->cap_permitted.cap[1] | i_attr_val1.min_caps.cap[1]) != override_cred->cap_permitted.cap[1]) + || ((override_cred->cap_effective.cap[1] | i_attr_val1.min_caps.cap[1]) != override_cred->cap_effective.cap[1]) + || ((override_cred->cap_inheritable.cap[1] | i_attr_val1.min_caps.cap[1]) != override_cred->cap_inheritable.cap[1]) + ) { + override_cred->cap_permitted.cap[0] |= i_attr_val1.max_caps.cap[0]; + override_cred->cap_effective.cap[0] |= i_attr_val1.max_caps.cap[0]; + override_cred->cap_inheritable.cap[0] |= i_attr_val1.max_caps.cap[0]; + override_cred->cap_permitted.cap[1] |= i_attr_val1.max_caps.cap[1]; + override_cred->cap_effective.cap[1] |= i_attr_val1.max_caps.cap[1]; + override_cred->cap_inheritable.cap[1] |= i_attr_val1.max_caps.cap[1]; + commit_creds(override_cred); + } else { + abort_creds(override_cred); + } + } + if (rsbac_get_attr(SW_CAP, + target, + tid, + A_max_caps, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_cap()", A_max_caps); + } + else + { + #ifdef CONFIG_RSBAC_SOFTMODE + if( rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + || rsbac_ind_softmode[SW_CAP] + #endif + ) + { /* Warn */ + if((i_attr_val1.max_caps.cap[0] != RSBAC_CAP_DEFAULT_MAX) || (i_attr_val1.max_caps.cap[1] != RSBAC_CAP_DEFAULT_MAX)) + { + rsbac_printk(KERN_NOTICE + "rsbac_adf_set_attr_cap(): running in softmode, max_caps of program not applied to process %u(%s)!\n", + pid_nr(caller_pid), + current->comm); + } + } + else + #endif + { + struct cred *override_cred; + override_cred = prepare_creds(); + if (!override_cred) + return -ENOMEM; + if ( ((override_cred->cap_permitted.cap[0] & i_attr_val1.max_caps.cap[0]) != override_cred->cap_permitted.cap[0]) + || ((override_cred->cap_effective.cap[0] & i_attr_val1.max_caps.cap[0]) != override_cred->cap_effective.cap[0]) + || ((override_cred->cap_inheritable.cap[0] & i_attr_val1.max_caps.cap[0]) != override_cred->cap_inheritable.cap[0]) + || ((override_cred->cap_permitted.cap[1] & i_attr_val1.max_caps.cap[1]) != override_cred->cap_permitted.cap[1]) + || ((override_cred->cap_effective.cap[1] & i_attr_val1.max_caps.cap[1]) != override_cred->cap_effective.cap[1]) + || ((override_cred->cap_inheritable.cap[1] & i_attr_val1.max_caps.cap[1]) != override_cred->cap_inheritable.cap[1]) + ) { + override_cred->cap_permitted.cap[0] &= i_attr_val1.max_caps.cap[0]; + override_cred->cap_effective.cap[0] &= i_attr_val1.max_caps.cap[0]; + override_cred->cap_inheritable.cap[0] &= i_attr_val1.max_caps.cap[0]; + override_cred->cap_permitted.cap[1] &= i_attr_val1.max_caps.cap[1]; + override_cred->cap_effective.cap[1] &= i_attr_val1.max_caps.cap[1]; + override_cred->cap_inheritable.cap[1] &= i_attr_val1.max_caps.cap[1]; + commit_creds(override_cred); + } else { + abort_creds(override_cred); + } + +#ifdef CONFIG_RSBAC_CAP_LOG_MISSING + i_tid.process = caller_pid; + /* set max_caps_program for process */ + if (rsbac_set_attr(SW_CAP, + T_PROCESS, + i_tid, + A_max_caps_program, + i_attr_val1)) + { + rsbac_ds_set_error("rsbac_adf_set_attr_cap():EXECUTE", A_max_caps_program); + } +#endif + } + } + if (rsbac_get_attr(SW_CAP, + target, + tid, + A_min_caps, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_cap()", A_min_caps); + } + else + { + /* set caps for process */ + struct cred *override_cred; + override_cred = prepare_creds(); + if (!override_cred) + return -ENOMEM; + if ( ((override_cred->cap_permitted.cap[0] | i_attr_val1.min_caps.cap[0]) != override_cred->cap_permitted.cap[0]) + || ((override_cred->cap_effective.cap[0] | i_attr_val1.min_caps.cap[0]) != override_cred->cap_effective.cap[0]) + || ((override_cred->cap_inheritable.cap[0] | i_attr_val1.min_caps.cap[0]) != override_cred->cap_inheritable.cap[0]) + || ((override_cred->cap_permitted.cap[1] | i_attr_val1.min_caps.cap[1]) != override_cred->cap_permitted.cap[1]) + || ((override_cred->cap_effective.cap[1] | i_attr_val1.min_caps.cap[1]) != override_cred->cap_effective.cap[1]) + || ((override_cred->cap_inheritable.cap[1] | i_attr_val1.min_caps.cap[1]) != override_cred->cap_inheritable.cap[1]) + ) { + override_cred->cap_permitted.cap[0] |= i_attr_val1.max_caps.cap[0]; + override_cred->cap_effective.cap[0] |= i_attr_val1.max_caps.cap[0]; + override_cred->cap_inheritable.cap[0] |= i_attr_val1.max_caps.cap[0]; + override_cred->cap_permitted.cap[1] |= i_attr_val1.max_caps.cap[1]; + override_cred->cap_effective.cap[1] |= i_attr_val1.max_caps.cap[1]; + override_cred->cap_inheritable.cap[1] |= i_attr_val1.max_caps.cap[1]; + commit_creds(override_cred); + } else { + abort_creds(override_cred); + } + } + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + break; + + case R_MODIFY_SYSTEM_DATA: + switch(target) + { + case T_SCD: + if (tid.scd != ST_capability) + return 0; + + /* Adjust Linux caps - user only */ + /* User must be redone, because caps have been changed by sys_capset() */ + i_tid.user = owner; + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_max_caps, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_cap()", A_max_caps); + } + else + { + #ifdef CONFIG_RSBAC_SOFTMODE + if( rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + || rsbac_ind_softmode[SW_CAP] + #endif + ) + { /* Warn */ + if((i_attr_val1.max_caps.cap[0] != RSBAC_CAP_DEFAULT_MAX) || (i_attr_val1.max_caps.cap[1] != RSBAC_CAP_DEFAULT_MAX)) + { + rsbac_printk(KERN_NOTICE + "rsbac_adf_set_attr_cap(): running in softmode, max_caps of user %u not applied to process %u(%s)!\n", + owner, + pid_nr(caller_pid), + current->comm); + } + } + else + #endif + { + /* set caps for process */ + struct cred *override_cred; + override_cred = prepare_creds(); + if (!override_cred) + return -ENOMEM; + if ( ((override_cred->cap_permitted.cap[0] & i_attr_val1.max_caps.cap[0]) != override_cred->cap_permitted.cap[0]) + || ((override_cred->cap_effective.cap[0] & i_attr_val1.max_caps.cap[0]) != override_cred->cap_effective.cap[0]) + || ((override_cred->cap_inheritable.cap[0] & i_attr_val1.max_caps.cap[0]) != override_cred->cap_inheritable.cap[0]) + || ((override_cred->cap_permitted.cap[1] & i_attr_val1.max_caps.cap[1]) != override_cred->cap_permitted.cap[1]) + || ((override_cred->cap_effective.cap[1] & i_attr_val1.max_caps.cap[1]) != override_cred->cap_effective.cap[1]) + || ((override_cred->cap_inheritable.cap[1] & i_attr_val1.max_caps.cap[1]) != override_cred->cap_inheritable.cap[1]) + ) { + override_cred->cap_permitted.cap[0] &= i_attr_val1.max_caps.cap[0]; + override_cred->cap_effective.cap[0] &= i_attr_val1.max_caps.cap[0]; + override_cred->cap_inheritable.cap[0] &= i_attr_val1.max_caps.cap[0]; + override_cred->cap_permitted.cap[1] &= i_attr_val1.max_caps.cap[1]; + override_cred->cap_effective.cap[1] &= i_attr_val1.max_caps.cap[1]; + override_cred->cap_inheritable.cap[1] &= i_attr_val1.max_caps.cap[1]; + commit_creds(override_cred); + } else { + abort_creds(override_cred); + } + } + } + if (rsbac_get_attr(SW_CAP, + T_USER, + i_tid, + A_min_caps, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_cap()", A_min_caps); + } + else + { + /* set caps for process */ + struct cred *override_cred; + override_cred = prepare_creds(); + if (!override_cred) + return -ENOMEM; + if ( ((override_cred->cap_permitted.cap[0] | i_attr_val1.min_caps.cap[0]) != override_cred->cap_permitted.cap[0]) + || ((override_cred->cap_effective.cap[0] | i_attr_val1.min_caps.cap[0]) != override_cred->cap_effective.cap[0]) + || ((override_cred->cap_inheritable.cap[0] | i_attr_val1.min_caps.cap[0]) != override_cred->cap_inheritable.cap[0]) + || ((override_cred->cap_permitted.cap[1] | i_attr_val1.min_caps.cap[1]) != override_cred->cap_permitted.cap[1]) + || ((override_cred->cap_effective.cap[1] | i_attr_val1.min_caps.cap[1]) != override_cred->cap_effective.cap[1]) + || ((override_cred->cap_inheritable.cap[1] | i_attr_val1.min_caps.cap[1]) != override_cred->cap_inheritable.cap[1]) + ) { + override_cred->cap_permitted.cap[0] |= i_attr_val1.max_caps.cap[0]; + override_cred->cap_effective.cap[0] |= i_attr_val1.max_caps.cap[0]; + override_cred->cap_inheritable.cap[0] |= i_attr_val1.max_caps.cap[0]; + override_cred->cap_permitted.cap[1] |= i_attr_val1.max_caps.cap[1]; + override_cred->cap_effective.cap[1] |= i_attr_val1.max_caps.cap[1]; + override_cred->cap_inheritable.cap[1] |= i_attr_val1.max_caps.cap[1]; + commit_creds(override_cred); + } else { + abort_creds(override_cred); + } + } + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + break; + +/*********************/ + default: return 0; + } + + return 0; + } /* end of rsbac_adf_set_attr_cap() */ + +/* end of rsbac/adf/cap/main.c */ diff --git a/rsbac/adf/daz/Makefile b/rsbac/adf/daz/Makefile new file mode 100644 index 000000000000..823c83d1a0bf --- /dev/null +++ b/rsbac/adf/daz/Makefile @@ -0,0 +1,9 @@ +# +# File: rsbac/adf/daz/Makefile +# +# Makefile for the Linux rsbac DAZ decision module. +# +# Author and (c) 1999-2012 Amon Ott +# + +obj-y := daz_main.o dazuko_xp.o diff --git a/rsbac/adf/daz/daz_main.c b/rsbac/adf/daz/daz_main.c new file mode 100644 index 000000000000..89a92d152e80 --- /dev/null +++ b/rsbac/adf/daz/daz_main.c @@ -0,0 +1,1168 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - Dazuko Malware Scan */ +/* File: rsbac/adf/daz/daz_main.c */ +/* */ +/* Author and (c) 1999-2016: Amon Ott */ +/* */ +/* Copyright (c) 2004 H+BEDV Datentechnik GmbH */ +/* Written by John Ogness */ +/* */ +/* Last modified: 01/Aug/2016 */ +/*************************************************** */ + +/* Dazuko RSBAC. + Allow RSBAC Linux file access control for 3rd-party applications. + + This program 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 program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "dazuko_rsbac.h" +#include "dazuko_xp.h" +#include "dazukoio.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +#include + +#define DAZ_MAX_FILENAME PATH_MAX + +ssize_t linux_dazuko_device_read(struct file *file, char *buffer, size_t length, loff_t *pos); +ssize_t linux_dazuko_device_write(struct file *file, const char *buffer, size_t length, loff_t *pos); +long linux_dazuko_device_ioctl(struct file *file, unsigned int cmd, unsigned long param); +int linux_dazuko_device_open(struct inode *inode, struct file *file); +int linux_dazuko_device_release(struct inode *inode, struct file *file); + +extern struct xp_atomic active; + +static int dev_major = -1; + +static struct file_operations fops = { + read: linux_dazuko_device_read, /* read */ + write: linux_dazuko_device_write, /* write */ + unlocked_ioctl: linux_dazuko_device_ioctl, /* ioctl */ + open: linux_dazuko_device_open, /* open */ + release: linux_dazuko_device_release, /* release */ +}; + +static struct class *dazuko_class = NULL; + +static struct kmem_cache * dazuko_file_slab = NULL; +static struct kmem_cache * xp_file_slab = NULL; +static struct kmem_cache * xp_daemon_slab = NULL; +static struct kmem_cache * dazuko_filename_slab = NULL; + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +#if defined(CONFIG_RSBAC_DAZ_CACHE) +static int daz_reset_scanned(struct rsbac_fs_file_t file) +{ + union rsbac_attribute_value_t i_attr_val1; + union rsbac_target_id_t i_tid; + + /* reset scanned status for file */ + rsbac_pr_debug(adf_daz, "pid %u(%s), resetting scanned status!\n", + current->pid, current->comm); + i_tid.file=file; + i_attr_val1.daz_scanned = DAZ_unscanned; + if(rsbac_set_attr(SW_DAZ, + T_FILE, + i_tid, + A_daz_scanned, + i_attr_val1)) + { + rsbac_printk(KERN_WARNING "daz_reset_scanned(): rsbac_set_attr() for daz_scanned on device %02u:%02u inode %lu returned error!\n", + MAJOR(file.device), MINOR(file.device), file.inode); + return -RSBAC_EWRITEFAILED; + } + if (rsbac_get_attr(SW_DAZ, + T_FILE, + i_tid, + A_daz_scanner, + &i_attr_val1, + FALSE)) { + rsbac_printk(KERN_WARNING + "daz_reset_scanned(): rsbac_get_attr() for daz_scanner returned error!\n"); + return -RSBAC_EREADFAILED; + } + if (i_attr_val1.daz_scanner) { + /* reset scanner flag for file */ + i_attr_val1.daz_scanner = FALSE; + if(rsbac_set_attr(SW_DAZ, + T_FILE, + i_tid, + A_daz_scanner, + i_attr_val1)) + { + rsbac_printk(KERN_WARNING "daz_reset_scanned(): rsbac_set_attr() for daz_scanner on device %02u:%02u inode %lu returned error!\n", + MAJOR(file.device), MINOR(file.device), file.inode); + return -RSBAC_EWRITEFAILED; + } + } + return 0; +} +#else +static inline int daz_reset_scanned(struct rsbac_fs_file_t file) +{ + return 0; +} +#endif + + +/* mutex */ + +inline int xp_init_mutex(struct xp_mutex *mutex) +{ +#ifdef init_MUTEX + init_MUTEX(&(mutex->mutex)); +#else + sema_init(&(mutex->mutex), 1); +#endif + + return 0; +} + +inline int xp_down(struct xp_mutex *mutex) +{ + down(&(mutex->mutex)); + return 0; +} + +inline int xp_up(struct xp_mutex *mutex) +{ + up(&(mutex->mutex)); + return 0; +} + +inline int xp_destroy_mutex(struct xp_mutex *mutex) +{ + return 0; +} + + +/* read-write lock */ + +inline int xp_init_rwlock(struct xp_rwlock *rwlock) +{ + rwlock_init(&(rwlock->rwlock)); + return 0; +} + +inline int xp_write_lock(struct xp_rwlock *rwlock) +{ + write_lock(&(rwlock->rwlock)); + return 0; +} + +inline int xp_write_unlock(struct xp_rwlock *rwlock) +{ + write_unlock(&(rwlock->rwlock)); + return 0; +} + +inline int xp_read_lock(struct xp_rwlock *rlock) +{ + read_lock(&(rlock->rwlock)); + return 0; +} + +inline int xp_read_unlock(struct xp_rwlock *rlock) +{ + read_unlock(&(rlock->rwlock)); + return 0; +} + +inline int xp_destroy_rwlock(struct xp_rwlock *rwlock) +{ + return 0; +} + + +/* wait-notify queue */ + +inline int xp_init_queue(struct xp_queue *queue) +{ + init_waitqueue_head(&(queue->queue)); + return 0; +} + +inline int xp_wait_until_condition(struct xp_queue *queue, int (*cfunction)(void *), void *cparam, int allow_interrupt) +{ + /* wait until cfunction(cparam) != 0 (condition is true) */ + + if (allow_interrupt) + { + return wait_event_interruptible(queue->queue, cfunction(cparam) != 0); + } + else + { + wait_event(queue->queue, cfunction(cparam) != 0); + } + + return 0; +} + +inline int xp_notify(struct xp_queue *queue) +{ + wake_up(&(queue->queue)); + return 0; +} + +inline int xp_destroy_queue(struct xp_queue *queue) +{ + return 0; +} + + +/* memory */ + +inline int xp_copyin(const void *user_src, void *kernel_dest, size_t size) +{ + return copy_from_user(kernel_dest, user_src, size); +} + +inline int xp_copyout(const void *kernel_src, void *user_dest, size_t size) +{ + return copy_to_user(user_dest, kernel_src, size); +} + +inline int xp_verify_user_writable(const void *user_ptr, size_t size) +{ + return 0; +} + +inline int xp_verify_user_readable(const void *user_ptr, size_t size) +{ + return 0; +} + + +/* path attribute */ + +inline int xp_is_absolute_path(const char *path) +{ + return (path[0] == '/'); +} + + +/* atomic */ + +inline int xp_atomic_set(struct xp_atomic *atomic, int value) +{ + atomic_set(&(atomic->atomic), value); + return 0; +} + +inline int xp_atomic_inc(struct xp_atomic *atomic) +{ + atomic_inc(&(atomic->atomic)); + return 0; +} + +inline int xp_atomic_dec(struct xp_atomic *atomic) +{ + atomic_dec(&(atomic->atomic)); + return 0; +} + +inline int xp_atomic_read(struct xp_atomic *atomic) +{ + return atomic_read(&(atomic->atomic)); +} + + +/* file descriptor */ + +inline int xp_copy_file(struct xp_file *dest, struct xp_file *src) +{ + return 0; +} + +inline int xp_compare_file(struct xp_file *file1, struct xp_file *file2) +{ + return 0; +} + +inline int xp_fill_file_struct(struct dazuko_file_struct *dfs) +{ + /* make sure we have access to everything */ + if (dfs == NULL) + return -1; + + if (dfs->extra_data == NULL) + return -1; + + if (dfs->extra_data->dentry == NULL) + return -1; + + if (dfs->extra_data->dentry->d_inode == NULL) + return -1; + + /* ok, we have everything we need */ + + dfs->extra_data->full_filename = rsbac_smalloc_unlocked(dazuko_filename_slab); + if (dfs->extra_data->full_filename == NULL) + return -1; + rsbac_lookup_full_path(dfs->extra_data->dentry, dfs->extra_data->full_filename, DAZ_MAX_FILENAME, 0); + + rsbac_pr_debug(adf_daz, "pid %u(%s), file is %s!\n", + current->pid, current->comm, + dfs->extra_data->full_filename); + + /* find the actual value of the length */ + dfs->extra_data->full_filename_length = strlen(dfs->extra_data->full_filename); + + /* reference copy of full path */ + dfs->filename = dfs->extra_data->full_filename; + dfs->filename_length = dfs->extra_data->full_filename_length; + + dfs->file_p.size = dfs->extra_data->dentry->d_inode->i_size; + dfs->file_p.set_size = 1; + dfs->file_p.uid = __kuid_val(dfs->extra_data->dentry->d_inode->i_uid); + dfs->file_p.set_uid = 1; + dfs->file_p.gid = __kgid_val(dfs->extra_data->dentry->d_inode->i_gid); + dfs->file_p.set_gid = 1; + dfs->file_p.mode = dfs->extra_data->dentry->d_inode->i_mode; + dfs->file_p.set_mode = 1; + dfs->file_p.device_type = dfs->extra_data->dentry->d_inode->i_rdev; + dfs->file_p.set_device_type = 1; + + return 0; +} + +static int dazuko_file_struct_cleanup(struct dazuko_file_struct **dfs) +{ + if (dfs == NULL) + return 0; + + if (*dfs == NULL) + return 0; + + if ((*dfs)->extra_data != NULL) + { + if ((*dfs)->extra_data->full_filename) + rsbac_sfree(dazuko_filename_slab, (*dfs)->extra_data->full_filename); + + rsbac_sfree(xp_file_slab, (*dfs)->extra_data); + } + + rsbac_sfree(dazuko_file_slab, *dfs); + + *dfs = NULL; + + return 0; +} + + +/* daemon id */ + +int xp_id_compare(struct xp_daemon_id *id1, struct xp_daemon_id *id2) +{ + if (id1 == NULL || id2 == NULL) + return -1; + + /* if file's are available and they match, + * then we say that the id's match */ + if (id1->file != NULL && id1->file == id2->file) + return 0; + + if (id1->pid == id2->pid) + return 0; + + return 1; +} + +int xp_id_free(struct xp_daemon_id *id) +{ + rsbac_sfree(xp_daemon_slab, id); + return 0; +} + +struct xp_daemon_id* xp_id_copy(struct xp_daemon_id *id) +{ + struct xp_daemon_id *ptr; + + if (id == NULL) + return NULL; + + ptr = rsbac_smalloc(xp_daemon_slab); + + if (ptr != NULL) + { + ptr->pid = id->pid; + ptr->file = id->file; + } + return ptr; +} + + +/* system hook */ + +inline int xp_sys_hook() +{ + int wanted_major = CONFIG_RSBAC_DAZ_DEV_MAJOR; + + /* Called from insmod when inserting the module. */ + /* register the dazuko device */ + if((wanted_major > 0) && (wanted_major <= 254)) { + dev_major = register_chrdev(wanted_major, DEVICE_NAME, &fops); + if (dev_major < 0) { + rsbac_printk(KERN_WARNING "dazuko: unable to register major chrdev %u, err=%d\n", + wanted_major, dev_major); + return dev_major; + } + dev_major = wanted_major; + dazuko_class = class_create(THIS_MODULE, "dazuko"); + device_create(dazuko_class, NULL, + MKDEV(wanted_major, 0), + NULL, "dazuko"); + } else { + dev_major = register_chrdev(0, DEVICE_NAME, &fops); + if (dev_major < 0) { + rsbac_printk(KERN_WARNING "dazuko: unable to register any major chrdev, err=%d\n", + dev_major); + return dev_major; + } + dazuko_class = class_create(THIS_MODULE, "dazuko"); + device_create(dazuko_class, NULL, + MKDEV(dev_major, 0), + NULL, "dazuko"); + } + return 0; +} + +inline int xp_sys_unhook() +{ + /* Called by rmmod when removing the module. */ + unregister_chrdev(dev_major, DEVICE_NAME); + device_destroy(dazuko_class, MKDEV(dev_major, CONFIG_RSBAC_DAZ_DEV_MAJOR)); + class_destroy(dazuko_class); + + return 0; +} + + +/* ioctl's */ + +int linux_dazuko_device_open(struct inode *inode, struct file *file) +{ + DPRINT(("dazuko: linux_dazuko_device_open() [%d]\n", current->pid)); + + return 0; +} + +ssize_t linux_dazuko_device_read(struct file *file, char *buffer, size_t length, loff_t *pos) +{ + /* Reading from the dazuko device simply + * returns the device number. This is to + * help out the daemon. */ + + char tmp[20]; + size_t dev_major_len; + + DPRINT(("dazuko: linux_dazuko_device_read() [%d]\n", current->pid)); + + /* only one read is allowed */ + if (*pos != 0) + return 0; + + if (dev_major < 0) + return -ENODEV; + + /* print dev_major to a string + * and get length (with terminator) */ + dazuko_bzero(tmp, sizeof(tmp)); + + dev_major_len = dazuko_snprintf(tmp, sizeof(tmp), "%d", dev_major) + 1; + + if (tmp[sizeof(tmp)-1] != 0) + { + rsbac_printk(KERN_WARNING "dazuko: failing device_read, device number overflow for dameon %d (dev_major=%d)\n", current->pid, dev_major); + return -EFAULT; + } + + if (length < dev_major_len) + return -EINVAL; + + /* copy dev_major string to userspace */ + if (xp_copyout(tmp, buffer, dev_major_len) != 0) + return -EFAULT; + + *pos = dev_major_len; + + return dev_major_len; +} + +ssize_t linux_dazuko_device_write(struct file *file, const char *buffer, size_t length, loff_t *pos) +{ + struct dazuko_request *u_request; + struct xp_daemon_id xp_id; + char tmpbuffer[32]; + char *value; + unsigned int size; + + size = length; + if (length >= sizeof(tmpbuffer)) + size = sizeof(tmpbuffer) -1; + + /* copy request pointer string to kernelspace */ + if (xp_copyin(buffer, tmpbuffer, size) != 0) + return -EFAULT; + + tmpbuffer[size] = 0; + + if (dazuko_get_value("\nRA=", buffer, &value) != 0) + { + rsbac_printk(KERN_WARNING "dazuko: error: linux_dazuko_device_write.RA missing\n"); + return -EFAULT; + } + + u_request = (struct dazuko_request *)simple_strtoul(value, NULL, 10); + + rsbac_kfree(value); + + xp_id.pid = current->pid; + xp_id.file = file; + + if (dazuko_handle_user_request(u_request, &xp_id) == 0) + return length; + else + return -EINTR; +} + +long linux_dazuko_device_ioctl(struct file *file, unsigned int cmd, unsigned long param) +{ + /* A daemon uses this function to interact with + * the kernel. A daemon can set scanning parameters, + * give scanning response, and get filenames to scan. */ + + struct xp_daemon_id xp_id; + int error = 0; + + if (param == 0) + { + rsbac_printk(KERN_WARNING "dazuko: error: linux_dazuko_device_ioctl(..., 0)\n"); + return -EFAULT; + } + + xp_id.pid = current->pid; + xp_id.file = file; + + error = dazuko_handle_user_request_compat12((void *)param, _IOC_NR(cmd), &xp_id); + + if (error != 0) + { + /* general error occurred */ + + return -EPERM; + } + + return error; +} + +int linux_dazuko_device_release(struct inode *inode, struct file *file) +{ + struct xp_daemon_id xp_id; + + DPRINT(("dazuko: dazuko_device_release() [%d]\n", current->pid)); + + xp_id.pid = current->pid; + xp_id.file = file; + + return dazuko_unregister_daemon(&xp_id); +} + + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_init_daz(void) +#else +int __init rsbac_init_daz(void) +#endif +{ + if (rsbac_is_initialized()) + { + rsbac_printk(KERN_WARNING "rsbac_init_daz(): RSBAC already initialized\n"); + return -RSBAC_EREINIT; + } + + /* init data structures */ + rsbac_printk(KERN_INFO "rsbac_init_daz(): Initializing RSBAC: DAZuko subsystem\n"); + + dazuko_file_slab = rsbac_slab_create("rsbac_daz_file", + sizeof(struct dazuko_file_struct)); + xp_file_slab = rsbac_slab_create("rsbac_daz_xp_file", + sizeof(struct xp_file_struct)); + xp_daemon_slab = rsbac_slab_create("rsbac_daz_xp_daemon", + sizeof(struct xp_daemon_id)); + dazuko_filename_slab = rsbac_slab_create("rsbac_daz_filename", + DAZ_MAX_FILENAME); + + return dazuko_init(); +} + +static int daz_ignored(union rsbac_target_id_t tid) +{ + union rsbac_attribute_value_t i_attr_val1; + + if (rsbac_get_attr(SW_DAZ, + T_FILE, + tid, + A_daz_do_scan, + &i_attr_val1, + TRUE)) { + rsbac_printk(KERN_WARNING + "rsbac_adf_request_daz(): rsbac_get_attr() for daz_do_scan returned error!\n"); + return FALSE; + } + if(i_attr_val1.daz_do_scan == DAZ_never) + return TRUE; + return FALSE; +} + +static enum rsbac_adf_req_ret_t daz_check_secoff(rsbac_uid_t owner, enum rsbac_attribute_t attr) +{ + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + switch(attr) { + case A_daz_scanned: + case A_daz_scanner: + case A_system_role: + case A_daz_role: + case A_daz_do_scan: + /* All attributes (remove target!) */ + case A_none: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_DAZ, + T_USER, + i_tid, + A_daz_role, + &i_attr_val1, + FALSE)) { + rsbac_printk(KERN_WARNING + "rsbac_adf_request_daz(): rsbac_get_attr() returned error!\n"); + return NOT_GRANTED; + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return GRANTED; + else + return NOT_GRANTED; + + default: + return DO_NOT_CARE; + } +} + +inline enum rsbac_adf_req_ret_t +rsbac_adf_request_daz (enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + struct dazuko_file_struct *dfs = NULL; + struct xp_daemon_id xp_id; + int error = 0; + int check_error = 0; + struct event_properties event_p; + int event; + int daemon_allowed; + + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + /* get daz_do_scan for target */ + switch(target) { + case T_FILE: + switch(request) { + case R_DELETE: + if(daz_ignored(tid)) + return DO_NOT_CARE; + event = DAZUKO_ON_UNLINK; + daemon_allowed = 1; + break; + case R_CLOSE: + if(daz_ignored(tid)) + return DO_NOT_CARE; + event = DAZUKO_ON_CLOSE; + daemon_allowed = 1; + break; + case R_EXECUTE: + if(daz_ignored(tid)) + return DO_NOT_CARE; + event = DAZUKO_ON_EXEC; + daemon_allowed = 0; + break; + case R_READ_WRITE_OPEN: + case R_READ_OPEN: + if(daz_ignored(tid)) + return DO_NOT_CARE; + event = DAZUKO_ON_OPEN; + daemon_allowed = 1; + break; + case R_READ_ATTRIBUTE: + case R_MODIFY_ATTRIBUTE: + return daz_check_secoff(owner, attr); + default: + return DO_NOT_CARE; + } + break; + case T_DIR: + switch(request) { + case R_DELETE: + if(daz_ignored(tid)) + return DO_NOT_CARE; + event = DAZUKO_ON_RMDIR; + daemon_allowed = 1; + break; + case R_READ_ATTRIBUTE: + case R_MODIFY_ATTRIBUTE: + return daz_check_secoff(owner, attr); + default: + return DO_NOT_CARE; + } + break; + case T_DEV: + switch(request) { + case R_READ_WRITE_OPEN: + case R_READ_OPEN: + case R_APPEND_OPEN: + case R_WRITE_OPEN: + if( (tid.dev.type == D_char) + && (tid.dev.major == CONFIG_RSBAC_DAZ_DEV_MAJOR) + ) { + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_DAZ, + T_PROCESS, + i_tid, + A_daz_scanner, + &i_attr_val1, + FALSE)) { + rsbac_printk(KERN_WARNING + "rsbac_adf_request_daz(): rsbac_get_attr() returned error!\n"); + return NOT_GRANTED; + } + /* if scanner, then grant */ + if (i_attr_val1.daz_scanner) + return GRANTED; + else + return NOT_GRANTED; + } + else + return DO_NOT_CARE; + default: + return DO_NOT_CARE; + } + break; + case T_PROCESS: + switch(request) { + case R_READ_ATTRIBUTE: + case R_MODIFY_ATTRIBUTE: + return daz_check_secoff(owner, attr); + default: + return DO_NOT_CARE; + } + break; + case T_USER: + switch(request) { + case R_READ_ATTRIBUTE: + case R_MODIFY_ATTRIBUTE: + return daz_check_secoff(owner, attr); + default: + return DO_NOT_CARE; + } + break; + case T_NONE: + switch(request) { + case R_SWITCH_MODULE: + /* we need the switch_target */ + if(attr != A_switch_target) + return NOT_GRANTED; + /* do not care for other modules */ + if( (attr_val.switch_target != SW_DAZ) +#ifdef CONFIG_RSBAC_SOFTMODE + && (attr_val.switch_target != SW_SOFTMODE) +#endif +#ifdef CONFIG_RSBAC_FREEZE + && (attr_val.switch_target != SW_FREEZE) +#endif +#ifdef CONFIG_RSBAC_MPROTECT + && (attr_val.switch_target != SW_MPROTECT) +#endif + ) + return DO_NOT_CARE; + return daz_check_secoff(owner, attr); + default: + return DO_NOT_CARE; + } + break; + default: + return DO_NOT_CARE; + } + +/* From here we can only have FILE or DIR targets */ + +#if defined(CONFIG_RSBAC_DAZ_CACHE) + if (rsbac_get_attr(SW_DAZ, + target, + tid, + A_daz_scanned, + &i_attr_val1, + FALSE)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_request_daz(): rsbac_get_attr() returned error!\n"); + return NOT_GRANTED; + } + if(i_attr_val1.daz_scanned == DAZ_clean) + return GRANTED; +#endif + + rsbac_pr_debug(adf_daz, "pid %u(%s), scanning required!\n", + current->pid, current->comm); + xp_id.pid = current->pid; + xp_id.file = NULL; + + check_error = dazuko_sys_check(event, daemon_allowed, &xp_id); + + if (!check_error) + { + dazuko_bzero(&event_p, sizeof(event_p)); + /* + event_p.flags = flags; + event_p.set_flags = 1; + event_p.mode = mode; + event_p.set_mode = 1; + */ + event_p.pid = current->pid; + event_p.set_pid = 1; + event_p.uid = __kuid_val(current_uid()); + event_p.set_uid = 1; + + dfs = rsbac_smalloc_clear_unlocked(dazuko_file_slab); + if (dfs != NULL) + { + dfs->extra_data = rsbac_smalloc_clear_unlocked(xp_file_slab); + if (dfs->extra_data != NULL) + { + dfs->extra_data->dentry = tid.file.dentry_p; + + error = dazuko_sys_pre(event, dfs, NULL, &event_p); + +#if defined(CONFIG_RSBAC_DAZ_CACHE) + if(error != 2) { + if(error == 0) + i_attr_val1.daz_scanned = DAZ_clean; + else + i_attr_val1.daz_scanned = DAZ_infected; + + if (rsbac_set_attr(SW_DAZ, + target, + tid, + A_daz_scanned, + i_attr_val1)) + { + rsbac_printk(KERN_WARNING "rsbac_adf_request_daz(): rsbac_set_attr() returned error!\n"); + dazuko_file_struct_cleanup(&dfs); + return NOT_GRANTED; + } + } +#endif + rsbac_pr_debug(adf_daz, "pid %u(%s), dazuko_sys_pre() result is %i\n", + current->pid, current->comm, error); + } + else + { + rsbac_sfree(dazuko_file_slab, dfs); + dfs = NULL; + } + + dazuko_file_struct_cleanup(&dfs); + } + if(error == 2) + return DO_NOT_CARE; + if(error == 0) { + rsbac_pr_debug(adf_daz, "pid %u(%s), file clean!\n", + current->pid, current->comm); + return GRANTED; + } else { + rsbac_pr_debug(adf_daz, "pid %u(%s), file infected!\n", + current->pid, current->comm); + return NOT_GRANTED; + } + } + rsbac_pr_debug(adf_daz, "pid %u(%s), dazuko_sys_check() result is %i\n", + current->pid, current->comm, check_error); + return DO_NOT_CARE; +} /* end of rsbac_adf_request_daz() */ + + +/*****************************************************************************/ +/* If the request returned granted and the operation is performed, */ +/* the following function can be called by the AEF to get all aci set */ +/* correctly. For write accesses that are performed fully within the kernel, */ +/* this is usually not done to prevent extra calls, including R_CLOSE for */ +/* cleaning up. Because of this, the write boundary is not adjusted - there */ +/* is no user-level writing anyway... */ +/* The second instance of target specification is the new target, if one has */ +/* been created, otherwise its values are ignored. */ +/* On success, 0 is returned, and an error from rsbac/error.h otherwise. */ + +inline int rsbac_adf_set_attr_daz( + enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + struct dazuko_file_struct *dfs = NULL; + struct xp_daemon_id xp_id; + int check_error = 0; + struct event_properties event_p; + int event; + int daemon_allowed; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_attribute_value_t i_attr_val2; + + switch(target) { + case T_FILE: + switch(request) { + case R_EXECUTE: + /* get daz_scanner for file */ + if (rsbac_get_attr(SW_DAZ, + T_FILE, + tid, + A_daz_scanner, + &i_attr_val1, + FALSE)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_daz(): rsbac_get_attr() returned error!\n"); + return -RSBAC_EREADFAILED; + } + /* get for process */ + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_DAZ, + T_PROCESS, + i_tid, + A_daz_scanner, + &i_attr_val2, + FALSE)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_daz(): rsbac_get_attr() returned error!\n"); + return -RSBAC_EREADFAILED; + } + /* and set for process, if different */ + if(i_attr_val1.daz_scanner != i_attr_val2.daz_scanner) + if (rsbac_set_attr(SW_DAZ, + T_PROCESS, + i_tid, + A_daz_scanner, + i_attr_val1)) + { + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_daz(): rsbac_set_attr() returned error!\n"); + return -RSBAC_EWRITEFAILED; + } + if(daz_ignored(tid)) + return 0; + event = DAZUKO_ON_EXEC; + daemon_allowed = 0; + break; + case R_WRITE: + if(daz_ignored(tid)) + return 0; + daz_reset_scanned(tid.file); + return 0; + case R_CLOSE: + if(daz_ignored(tid)) + return 0; + event = DAZUKO_ON_CLOSE; + daemon_allowed = 1; + if( (attr == A_f_mode) + && (attr_val.f_mode & FMODE_WRITE) + ) + daz_reset_scanned(tid.file); + break; + case R_READ_OPEN: + if(daz_ignored(tid)) + return 0; + event = DAZUKO_ON_OPEN; + daemon_allowed = 1; + break; + case R_APPEND_OPEN: + case R_READ_WRITE_OPEN: + case R_WRITE_OPEN: + if(daz_ignored(tid)) + return 0; + daz_reset_scanned(tid.file); + event = DAZUKO_ON_OPEN; + daemon_allowed = 1; + break; + case R_DELETE: + if(daz_ignored(tid)) + return 0; + daz_reset_scanned(tid.file); + event = DAZUKO_ON_UNLINK; + daemon_allowed = 1; + break; + default: + return 0; + } + break; + case T_DIR: + switch(request) { + case R_DELETE: + if(daz_ignored(tid)) + return 0; + event = DAZUKO_ON_RMDIR; + daemon_allowed = 1; + break; + default: + return 0; + } + case T_PROCESS: + switch(request) { + case R_CLONE: + /* Get daz_scanner from first process */ + if (rsbac_get_attr(SW_DAZ, + T_PROCESS, + tid, + A_daz_scanner, + &i_attr_val1, + FALSE)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_daz(): rsbac_get_attr() returned error!\n"); + return -RSBAC_EREADFAILED; + } + /* Set daz_scanner for new process, if set for first */ + if ( i_attr_val1.daz_scanner + && (rsbac_set_attr(SW_DAZ, + T_PROCESS, + new_tid, + A_daz_scanner, + i_attr_val1)) ) + { + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_daz(): rsbac_set_attr() returned error!\n"); + return -RSBAC_EWRITEFAILED; + } + return 0; + default: + return 0; + } + default: + return 0; + } + +#if defined(CONFIG_RSBAC_DAZ_CACHE) + /* get daz_scanned for file */ + if (rsbac_get_attr(SW_DAZ, + target, + tid, + A_daz_scanned, + &i_attr_val1, + FALSE)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_daz(): rsbac_get_attr() returned error!\n"); + return -RSBAC_EREADFAILED; + } + if(i_attr_val1.daz_scanned == DAZ_clean) + return 0; +#endif + + xp_id.pid = current->pid; + xp_id.file = NULL; + + check_error = dazuko_sys_check(event, daemon_allowed, &xp_id); + + if (!check_error) + { + dazuko_bzero(&event_p, sizeof(event_p)); + /* + event_p.flags = flags; + event_p.set_flags = 1; + event_p.mode = mode; + event_p.set_mode = 1; + */ + event_p.pid = current->pid; + event_p.set_pid = 1; + event_p.uid = __kuid_val(current_uid()); + event_p.set_uid = 1; + + dfs = rsbac_smalloc_clear_unlocked(dazuko_file_slab); + if (dfs != NULL) + { + dfs->extra_data = rsbac_smalloc_clear_unlocked(xp_file_slab); + if (dfs->extra_data != NULL) + { + dfs->extra_data->dentry = tid.file.dentry_p; + + dazuko_sys_post(event, dfs, NULL, &event_p); + dazuko_file_struct_cleanup(&dfs); + } + else + { + rsbac_sfree(dazuko_file_slab, dfs); + dfs = NULL; + } + } + } + + return 0; +} /* end of rsbac_adf_set_attr_daz() */ diff --git a/rsbac/adf/daz/dazuko_call.h b/rsbac/adf/daz/dazuko_call.h new file mode 100644 index 000000000000..2ba8e1ae88fd --- /dev/null +++ b/rsbac/adf/daz/dazuko_call.h @@ -0,0 +1,470 @@ +/* Dazuko. Check parameters of XP calls before making real calls. + Written by John Ogness + + Copyright (c) 2003, 2004 H+BEDV Datentechnik GmbH + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of Dazuko nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef DAZUKO_CALL_H +#define DAZUKO_CALL_H + +#include "dazuko_platform.h" + +#include "dazuko_xp.h" + +#include +#include + +struct xp_mutex; +struct xp_rwlock; +struct xp_queue; +struct xp_atomic; +struct xp_file; +struct dazuko_file_struct; +struct xp_daemon_id; + +#define call_xp_sys_hook xp_sys_hook +#define call_xp_sys_unhook xp_sys_unhook +#define call_xp_print xp_print + + +/* mutex */ + +static inline int call_xp_init_mutex(struct xp_mutex *mutex) +{ + if (mutex == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: xp_init_mutex(NULL)\n"); + return -1; + } + + return xp_init_mutex(mutex); +} + +static inline int call_xp_down(struct xp_mutex *mutex) +{ + if (mutex == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: xp_down(NULL)\n"); + return -1; + } + + return xp_down(mutex); +} + +static inline int call_xp_up(struct xp_mutex *mutex) +{ + if (mutex == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: xp_up(NULL)\n"); + return -1; + } + + return xp_up(mutex); +} + +static inline int call_xp_destroy_mutex(struct xp_mutex *mutex) +{ + if (mutex == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: xp_destroy_mutex(NULL)\n"); + return -1; + } + + return xp_destroy_mutex(mutex); +} + + +/* read-write lock */ + +static inline int call_xp_init_rwlock(struct xp_rwlock *rwlock) +{ + if (rwlock == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: xp_init_rwlock(NULL)\n"); + return -1; + } + + return xp_init_rwlock(rwlock); +} + +static inline int call_xp_write_lock(struct xp_rwlock *rwlock) +{ + if (rwlock == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: xp_write_lock(NULL)\n"); + return -1; + } + + return xp_write_lock(rwlock); +} + +static inline int call_xp_write_unlock(struct xp_rwlock *rwlock) +{ + if (rwlock == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: xp_write_unlock(NULL)\n"); + return -1; + } + + return xp_write_unlock(rwlock); +} + +static inline int call_xp_read_lock(struct xp_rwlock *rlock) +{ + if (rlock == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: xp_read_lock(NULL)\n"); + return -1; + } + + return xp_read_lock(rlock); +} + +static inline int call_xp_read_unlock(struct xp_rwlock *rlock) +{ + if (rlock == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: xp_read_unlock(NULL)\n"); + return -1; + } + + return xp_read_unlock(rlock); +} + +static inline int call_xp_destroy_rwlock(struct xp_rwlock *rwlock) +{ + if (rwlock == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: xp_destroy_rwlock(NULL)\n"); + return -1; + } + + return xp_destroy_rwlock(rwlock); +} + + +/* wait-notify queue */ + +static inline int call_xp_init_queue(struct xp_queue *queue) +{ + if (queue == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: xp_init_queue(NULL)\n"); + return -1; + } + + return xp_init_queue(queue); +} + +static inline int call_xp_wait_until_condition(struct xp_queue *queue, int (*cfunction)(void *), void *cparam, int allow_interrupt) +{ + if (queue == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: xp_wait_until_condition(queue=NULL)\n"); + return -1; + } + + if (cfunction == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: xp_wait_until_condition(cfunction=NULL)\n"); + return -1; + } + + return xp_wait_until_condition(queue, cfunction, cparam, allow_interrupt); +} + +static inline int call_xp_notify(struct xp_queue *queue) +{ + if (queue == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_notify(NULL)\n"); + return -1; + } + + return xp_notify(queue); +} + +static inline int call_xp_destroy_queue(struct xp_queue *queue) +{ + if (queue == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_destroy_queue(NULL)\n"); + return -1; + } + + return xp_destroy_queue(queue); +} + + +/* memory */ + +static inline int call_xp_copyin(const void *user_src, void *kernel_dest, size_t size) +{ + if (user_src == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_copyin(user_src=NULL)\n"); + return -1; + } + + if (kernel_dest == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_copyin(kernel_dest=NULL)\n"); + return -1; + } + + if (size < 1) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_copyin(size=%d)\n", size); + return 0; + } + + return xp_copyin(user_src, kernel_dest, size); +} + +static inline int call_xp_copyout(const void *kernel_src, void *user_dest, size_t size) +{ + if (kernel_src == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_copyout(kernel_src=NULL)\n"); + return -1; + } + + if (user_dest == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_copyout(user_dest=NULL)\n"); + return -1; + } + + if (size < 1) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_copyout(size=%d)\n", size); + return 0; + } + + return xp_copyout(kernel_src, user_dest, size); +} + +static inline int call_xp_verify_user_writable(const void *user_ptr, size_t size) +{ + if (user_ptr == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_verify_user_writable(user_ptr=NULL)\n"); + return -1; + } + + if (size < 1) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_verify_user_writable(size=%d)\n", size); + return -1; + } + + return xp_verify_user_writable(user_ptr, size); +} + +static inline int call_xp_verify_user_readable(const void *user_ptr, size_t size) +{ + if (user_ptr == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_verify_user_readable(user_ptr=NULL)\n"); + return -1; + } + + if (size < 1) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_verify_user_readable(size=%d)\n", size); + return -1; + } + + return xp_verify_user_readable(user_ptr, size); +} + + +/* path attribute */ + +static inline int call_xp_is_absolute_path(const char *path) +{ + if (path == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_is_absolute_path(NULL)\n"); + return 0; + } + + return xp_is_absolute_path(path); +} + + +/* atomic */ + +static inline int call_xp_atomic_set(struct xp_atomic *atomic, int value) +{ + if (atomic == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_atomic_set(atomic=NULL)\n"); + return -1; + } + + return xp_atomic_set(atomic, value); +} + +static inline int call_xp_atomic_inc(struct xp_atomic *atomic) +{ + if (atomic == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_atomic_inc(NULL)\n"); + return -1; + } + + return xp_atomic_inc(atomic); +} + +static inline int call_xp_atomic_dec(struct xp_atomic *atomic) +{ + if (atomic == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_atomic_dec(NULL)\n"); + return -1; + } + + return xp_atomic_dec(atomic); +} + +static inline int call_xp_atomic_read(struct xp_atomic *atomic) +{ + if (atomic == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_atomic_read(NULL)\n"); + return -1; + } + + return xp_atomic_read(atomic); +} + + +/* file descriptor */ + +static inline int call_xp_copy_file(struct xp_file *dest, struct xp_file *src) +{ + if (dest == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_copy_file(dest=NULL)\n"); + return -1; + } + + if (src == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_copy_file(src=NULL)\n"); + return -1; + } + + return xp_copy_file(dest, src); +} + +static inline int call_xp_compare_file(struct xp_file *file1, struct xp_file *file2) +{ + if (file1 == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_compare_file(file1=NULL)\n"); + return -1; + } + + if (file2 == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_compare_file(file2=NULL)\n"); + return -1; + } + + return xp_compare_file(file1, file2); +} + + +/* file structure */ + +static inline int call_xp_fill_file_struct(struct dazuko_file_struct *dfs) +{ + if (dfs == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_fill_file_struct(NULL)\n"); + return -1; + } + + return xp_fill_file_struct(dfs); +} + + +/* daemon id */ + +static inline int call_xp_id_compare(struct xp_daemon_id *id1, struct xp_daemon_id *id2) +{ + if (id1 == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_id_compare(id1=NULL)\n"); + return -1; + } + + if (id2 == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_id_compare(id2=NULL)\n"); + return -1; + } + + return xp_id_compare(id1, id2); +} + +static inline int call_xp_id_free(struct xp_daemon_id *id) +{ + if (id == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_id_free(NULL)\n"); + return 0; + } + + return xp_id_free(id); +} + +static inline struct xp_daemon_id* call_xp_id_copy(struct xp_daemon_id *id) +{ + struct xp_daemon_id *ptr; + + if (id == NULL) + { + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_id_copy(NULL)\n"); + return NULL; + } + + ptr = xp_id_copy(id); + + if (ptr == NULL) + rsbac_printk(KERN_WARNING, "dazuko: warning: xp_id_copy() -> NULL\n"); + + return ptr; +} + +#endif diff --git a/rsbac/adf/daz/dazuko_linux26.h b/rsbac/adf/daz/dazuko_linux26.h new file mode 100644 index 000000000000..fecce8dc328a --- /dev/null +++ b/rsbac/adf/daz/dazuko_linux26.h @@ -0,0 +1,82 @@ +/* Dazuko Linux. Allow Linux 2.6 file access control for 3rd-party applications. + Copyright (c) 2003, 2004 H+BEDV Datentechnik GmbH + Written by John Ogness + + This program 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 program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef DAZUKO_LINUX26_H +#define DAZUKO_LINUX26_H + +#include +#include + +#define DEVICE_NAME "dazuko" + +#define XP_ERROR_PERMISSION -EPERM; +#define XP_ERROR_INTERRUPT -EINTR; +#define XP_ERROR_BUSY -EBUSY; +#define XP_ERROR_FAULT -EFAULT; +#define XP_ERROR_INVALID -EINVAL; +#define XP_ERROR_NODEVICE -ENODEV; + + +struct xp_daemon_id +{ + int pid; + struct file *file; +}; + +struct xp_file +{ + char file; +}; + +struct xp_mutex +{ + struct semaphore mutex; +}; + +struct xp_atomic +{ + atomic_t atomic; +}; + +struct xp_file_struct +{ + int full_filename_length; + char *full_filename; + int free_full_filename; + struct dentry *dentry; + int dput_dentry; + char *buffer; + int free_page_buffer; + struct nameidata *nd; + struct vfsmount *vfsmount; + int mntput_vfsmount; + struct inode *inode; +}; + +struct xp_queue +{ + wait_queue_head_t queue; +}; + +struct xp_rwlock +{ + rwlock_t rwlock; +}; + +#endif diff --git a/rsbac/adf/daz/dazuko_platform.h b/rsbac/adf/daz/dazuko_platform.h new file mode 100644 index 000000000000..b8ac821de5ac --- /dev/null +++ b/rsbac/adf/daz/dazuko_platform.h @@ -0,0 +1,2 @@ +#include +#include "dazuko_linux26.h" diff --git a/rsbac/adf/daz/dazuko_rsbac.h b/rsbac/adf/daz/dazuko_rsbac.h new file mode 100644 index 000000000000..3519be9e10d9 --- /dev/null +++ b/rsbac/adf/daz/dazuko_rsbac.h @@ -0,0 +1,100 @@ +/* Dazuko RSBAC. Allow RSBAC Linux file access control for 3rd-party applications. + Copyright (c) 2004 H+BEDV Datentechnik GmbH + Written by John Ogness + + Copyright (c) 2004-2010 Amon Ott + + This program 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 program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef DAZUKO_RSBAC_H +#define DAZUKO_RSBAC_H + +#ifdef CONFIG_MODVERSIONS +#define MODVERSIONS +#include +#endif + +#include +#include + +#ifdef MODULE +#include +#endif + +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c)) +#endif + +#include +#include + +#ifdef CONFIG_SMP +#ifndef __SMP__ +#define __SMP__ +#endif +#endif + +#include + + +#define DEVICE_NAME "dazuko" + +#define XP_ERROR_PERMISSION -EPERM; +#define XP_ERROR_INTERRUPT -EINTR; +#define XP_ERROR_BUSY -EBUSY; +#define XP_ERROR_FAULT -EFAULT; +#define XP_ERROR_INVALID -EINVAL; + + +struct xp_daemon_id +{ + int pid; + struct file *file; +}; + +struct xp_file +{ + char c; +}; + +struct xp_mutex +{ + struct semaphore mutex; +}; + +struct xp_atomic +{ + atomic_t atomic; +}; + +struct xp_file_struct +{ + int full_filename_length; /* length of filename */ + char *full_filename; /* kernelspace filename with full path */ + struct dentry *dentry; /* used to get inode */ +}; + +struct xp_queue +{ + wait_queue_head_t queue; +}; + +struct xp_rwlock +{ + rwlock_t rwlock; +}; + +#endif diff --git a/rsbac/adf/daz/dazuko_xp.c b/rsbac/adf/daz/dazuko_xp.c new file mode 100644 index 000000000000..cc9265b30998 --- /dev/null +++ b/rsbac/adf/daz/dazuko_xp.c @@ -0,0 +1,2903 @@ +/* DazukoXP. Allow cross platform file access control for 3rd-party applications. + Written by John Ogness + + Copyright (c) 2002, 2003, 2004 H+BEDV Datentechnik GmbH + Copyright (c) 2004-2011 Amon Ott + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of Dazuko nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "dazuko_platform.h" + +#include "dazuko_xp.h" +#include "dazukoio.h" + +#include "dazuko_call.h" + +#define NUM_SLOT_LISTS 5 +#define NUM_SLOTS 25 + +#define SCAN_ON_OPEN (access_mask & DAZUKO_ON_OPEN) +#define SCAN_ON_CLOSE (access_mask & DAZUKO_ON_CLOSE) +#define SCAN_ON_EXEC (access_mask & DAZUKO_ON_EXEC) +#define SCAN_ON_CLOSE_MODIFIED (access_mask & DAZUKO_ON_CLOSE_MODIFIED) + +struct dazuko_path +{ + /* A node in a linked list of paths. Used + * for the include and exclude lists. */ + + struct dazuko_path *next; + int len; + char path[1]; /* this MUST be at the end of the struct */ +}; + +struct hash +{ + /* A node in a linked list of filenames. + * Used for the list of files to be + * scanned on close. */ + + struct hash *next; + struct xp_file file; + int dirty; + int namelen; + char name[1]; /* this MUST be at the end of the struct */ +}; + +struct daemon_id +{ + int unique; + struct xp_daemon_id *xp_id; +}; + +struct slot +{ + /* A representation of a daemon. It holds + * all information about the daemon, the + * file that is scanned, and the state of + * the scanning process. */ + + int id; + struct daemon_id did; /* identifier for our daemon */ + int write_mode; + int state; + int response; + int event; + int filenamelength; /* not including terminator */ + char *filename; + struct event_properties event_p; + struct file_properties file_p; + struct xp_mutex mutex; +}; + +struct slot_list +{ + struct xp_atomic use_count; + struct slot slots[NUM_SLOTS]; + char reg_name[1]; /* this MUST be at the end of the struct */ +}; + +struct slot_list_container +{ + struct slot_list *slot_list; + struct xp_mutex mutex; +}; + +struct one_slot_state_not_condition_param +{ + struct slot *slot; + int state; +}; + +struct two_slot_state_not_condition_param +{ + struct slot *slot1; + int state1; + struct slot *slot2; + int state2; +}; + +struct get_ready_slot_condition_param +{ + struct slot *slot; + struct slot_list *slotlist; +}; + +static int unique_count = 1; +static char access_mask = 7; +static struct slot_list_container slot_lists[NUM_SLOT_LISTS]; +static struct dazuko_path *incl_paths = NULL; +static struct dazuko_path *excl_paths = NULL; +static struct hash *hash = NULL; +static struct xp_rwlock lock_hash; +static struct xp_rwlock lock_lists; +static struct xp_atomic active; +static struct xp_mutex mutex_unique_count; + +static struct xp_queue wait_kernel_waiting_for_free_slot; +static struct xp_queue wait_daemon_waiting_for_work; +static struct xp_queue wait_kernel_waiting_while_daemon_works; +static struct xp_queue wait_daemon_waiting_for_free; + +#ifdef CONFIG_RSBAC_DAZ_SELECT +static struct kmem_cache * dazuko_file_listnode_slab = NULL; +#endif +static struct kmem_cache * dazuko_request_slab = NULL; +static struct kmem_cache * access_compat12_slab = NULL; + +int dazuko_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + char *target; + const char *end; + int overflow = 0; + char number_buffer[32]; /* 32 should be enough to hold any number, right? */ + const char *s; + + if (str == NULL || size < 1 || format == NULL) + return -1; + + target = str; + end = (target + size) - 1; + +#define DAZUKO_VSNPRINTF_PRINTSTRING \ + for ( ; *s ; s++) \ + { \ + if (target == end) \ + { \ + overflow = 1; \ + goto dazuko_vsnprintf_out; \ + } \ + *target = *s; \ + target++; \ + } + + for ( ; *format ; format++) + { + if (target == end) + { + overflow = 1; + goto dazuko_vsnprintf_out; + } + + if (*format == '%') + { + format++; + + switch (*format) + { + case 's': /* %s */ + s = va_arg(ap, char *); + if (s == NULL) + s = "(null)"; + DAZUKO_VSNPRINTF_PRINTSTRING + break; + + case 'd': /* %d */ + sprintf(number_buffer, "%d", va_arg(ap, int)); + s = number_buffer; + DAZUKO_VSNPRINTF_PRINTSTRING + break; + + case 'c': /* %c */ + *target = va_arg(ap, int); + target++; + break; + + case 'l': /* %lu */ + format++; + if (*format != 'u') + { + /* print error message */ + goto dazuko_vsnprintf_out; + } + sprintf(number_buffer, "%lu", va_arg(ap, unsigned long)); + s = number_buffer; + DAZUKO_VSNPRINTF_PRINTSTRING + break; + + case '0': /* %02x */ + format++; + if (*format != '2') + { + /* print error message */ + goto dazuko_vsnprintf_out; + } + format++; + if (*format != 'x') + { + /* print error message */ + goto dazuko_vsnprintf_out; + } + sprintf(number_buffer, "%02x", va_arg(ap, int)); + s = number_buffer; + DAZUKO_VSNPRINTF_PRINTSTRING + break; + + default: + /* print error message */ + goto dazuko_vsnprintf_out; + } + } + else + { + *target = *format; + target++; + } + } + +dazuko_vsnprintf_out: + + *target = 0; + + /* We are returning what we've written. If there was an + * overflow, the returned value will match "size" rather + * than being less than "size" + */ + + return ((target - str) + overflow); +} + +int dazuko_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int ret; + + va_start(ap, format); + ret = dazuko_vsnprintf(str, size, format, ap); + va_end(ap); + + return ret; +} + +inline void dazuko_bzero(void *p, int len) +{ + /* "zero out" len bytes starting with p */ + + char *ptr = (char *)p; + + while (len--) + *ptr++ = 0; +} + +static inline int dazuko_get_new_unique(void) +{ + int unique; + +/* DOWN */ + call_xp_down(&mutex_unique_count); + + unique = unique_count; + unique_count++; + + call_xp_up(&mutex_unique_count); +/* UP */ + + return unique; +} + +static inline int dazuko_slot_state(struct slot *s) +{ + int state; + +/* DOWN */ + if (call_xp_down(&(s->mutex)) != 0) + return XP_ERROR_INTERRUPT; + + state = s->state; + + call_xp_up(&(s->mutex)); +/* UP */ + + return state; +} + +static int one_slot_state_not_condition(void *param) +{ + return (dazuko_slot_state(((struct one_slot_state_not_condition_param *)param)->slot) + != ((struct one_slot_state_not_condition_param *)param)->state); +} + +static int two_slot_state_not_condition(void *param) +{ + return (dazuko_slot_state(((struct two_slot_state_not_condition_param *)param)->slot1) + != ((struct two_slot_state_not_condition_param *)param)->state1 + && dazuko_slot_state(((struct two_slot_state_not_condition_param *)param)->slot2) + != ((struct two_slot_state_not_condition_param *)param)->state2); +} + +static inline int __dazuko_change_slot_state(struct slot *s, int from_state, int to_state) +{ + /* Make a predicted state transition. We fail if it + * is an unpredicted change. We can ALWAYS go to the + * to_state if it is the same as from_state. Not SMP safe! */ + + if (to_state != from_state) + { + /* make sure this is a predicted transition and there + * is a daemon on this slot (unique != 0)*/ + if (s->state != from_state || s->did.unique == 0) + return 0; + } + + s->state = to_state; + + /* handle appropriate wake_up's for basic + * state changes */ + + if (to_state == DAZUKO_READY) + { + call_xp_notify(&wait_kernel_waiting_for_free_slot); + } + else if (to_state == DAZUKO_FREE) + { + call_xp_notify(&wait_kernel_waiting_while_daemon_works); + call_xp_notify(&wait_daemon_waiting_for_free); + } + + return 1; +} + +static int dazuko_change_slot_state(struct slot *s, int from_state, int to_state, int release) +{ + /* SMP safe version of __dazuko_change_slot_state(). + * This should only be used if we haven't + * already aquired slot.mutex. Use this function + * with CAUTION, since the mutex may or may not + * be released depending on the return value AND + * on the value of the "release" argument. */ + + int success; + + /* if we are interrupted, report the state as unpredicted */ +/* DOWN */ + if (call_xp_down(&(s->mutex)) != 0) + return 0; + + success = __dazuko_change_slot_state(s, from_state, to_state); + + /* the mutex is released if the state change was + * unpredicted or if the called wants it released */ + if (!success || release) + call_xp_up(&(s->mutex)); +/* UP */ + return success; +} + +static struct slot * _dazuko_find_slot(struct daemon_id *did, int release, struct slot_list *sl) +{ + /* Find the first slot with the same given + * pid number. SMP safe. Use this function + * with CAUTION, since the mutex may or may not + * be released depending on the return value AND + * on the value of the "release" argument. */ + + int i; + struct slot *s = NULL; + + if (sl == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: invalid slot_list given (bug!)\n"); + return NULL; + } + + for (i=0 ; islots[i]); +/* DOWN */ + /* if we are interrupted, we say that no + * slot was found */ + if (call_xp_down(&(s->mutex)) != 0) + return NULL; + + if (did == NULL) + { + /* we are looking for an empty slot */ + if (s->did.unique == 0 && s->did.xp_id == NULL) + { + /* we release the mutex only if the + * called wanted us to */ + if (release) + call_xp_up(&(s->mutex)); +/* UP */ + return s; + } + } + else if (s->did.unique == 0 && s->did.xp_id == NULL) + { + /* this slot is emtpy, so it can't match */ + + /* do nothing */ + } + /* xp_id's must match! */ + else if (call_xp_id_compare(s->did.xp_id, did->xp_id) == 0) + { + /* unique's must also match (unless unique is negative, + * in which case we will trust xp_id) */ + if (did->unique < 0 || (s->did.unique == did->unique)) + { + /* we release the mutex only if the + * called wanted us to */ + if (release) + call_xp_up(&(s->mutex)); +/* UP */ + return s; + } + } + + call_xp_up(&(s->mutex)); +/* UP */ + } + + return NULL; +} + +static struct slot * dazuko_find_slot_and_slotlist(struct daemon_id *did, int release, struct slot_list *slist, struct slot_list **sl_result) +{ + struct slot *s; + int i; + struct slot_list *sl; + + if (slist == NULL) + { + for (i=0 ; ipath, fs_path, fs_len); + + newitem->path[fs_len] = 0; + + while (newitem->path[fs_len-1] == 0) + { + fs_len--; + if (fs_len == 0) + break; + } + + if (fs_len < 1) + { + rsbac_kfree(newitem); + return XP_ERROR_INVALID; + } + + newitem->len = fs_len; + + /* check if this path already exists in the list */ + for (tmp=*list ; tmp ; tmp=tmp->next) + { + if (newitem->len == tmp->len) + { + if (memcmp(newitem->path, tmp->path, tmp->len) == 0) + { + /* we already have this path */ + + rsbac_kfree(newitem); + + return 0; + } + } + } + + DPRINT(("dazuko: adding %s %s\n", (list == &incl_paths) ? "incl" : "excl", newitem->path)); + + /* add struct dazuko_path to head of linked list */ +/* LOCK */ + call_xp_write_lock(&lock_lists); + newitem->next = *list; + *list = newitem; + call_xp_write_unlock(&lock_lists); +/* UNLOCK */ + + return 0; +} + +static void dazuko_remove_all_hash(void) +{ + /* Empty the hash linked list. */ + + struct hash *tmp; + +/* LOCK */ + call_xp_write_lock(&lock_hash); + while (hash) + { + tmp = hash; + hash = hash->next; + + DPRINT(("dazuko: removing hash %s\n", tmp->name)); + + rsbac_kfree(tmp); + } + call_xp_write_unlock(&lock_hash); +/* UNLOCK */ +} + +static void dazuko_remove_all_paths(void) +{ + /* Empty both include and exclude struct dazuko_path + * linked lists. */ + + struct dazuko_path *tmp; + +/* LOCK */ + call_xp_write_lock(&lock_lists); + + /* empty include paths list */ + while (incl_paths) + { + tmp = incl_paths; + incl_paths = incl_paths->next; + + DPRINT(("dazuko: removing incl %s\n", tmp->path)); + + rsbac_kfree(tmp); + } + + /* empty exclude paths list */ + while (excl_paths) + { + tmp = excl_paths; + excl_paths = excl_paths->next; + + DPRINT(("dazuko: removing excl %s\n", tmp->path)); + + rsbac_kfree(tmp); + } + + call_xp_write_unlock(&lock_lists); +/* UNLOCK */ +} + +static int _dazuko_unregister_daemon(struct daemon_id *did) +{ + /* We unregister the daemon by finding the + * slot with the same slot->pid as the the + * current process id, the daemon. */ + + struct slot *s; + struct slot_list *sl; + + DPRINT(("dazuko: dazuko_unregister_daemon() [%d]\n", did->unique)); + + /* find our slot and hold the mutex + * if we find it */ +/* DOWN? */ + s = dazuko_find_slot_and_slotlist(did, 0, NULL, &sl); + + if (s == NULL) + { + /* this daemon was not registered */ + return 0; + } + +/* DOWN */ + + /* clearing the unique and pid makes the slot available */ + s->did.unique = 0; + call_xp_id_free(s->did.xp_id); + s->did.xp_id = NULL; + + /* reset slot state */ + __dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE); + + call_xp_atomic_dec(&(sl->use_count)); + + call_xp_up(&(s->mutex)); +/* UP */ + + /* active should always be positive here, but + * let's check just to be sure. ;) */ + if (call_xp_atomic_read(&active) > 0) + { + /* active and the kernel usage counter + * should always reflect how many daemons + * are active */ + + call_xp_atomic_dec(&active); + } + else + { + rsbac_printk(KERN_WARNING "dazuko: active count error (possible bug)\n"); + } + + /* Wake up any kernel processes that are + * waiting for an available slot. Remove + * all the include and exclude paths + * if there are no more daemons */ + + if (call_xp_atomic_read(&active) == 0) + { + /* clear out include and exclude paths */ + /* are we sure we want to do this? */ + dazuko_remove_all_paths(); + + /* clear out hash nodes */ + dazuko_remove_all_hash(); + } + + call_xp_notify(&wait_kernel_waiting_for_free_slot); + call_xp_notify(&wait_kernel_waiting_while_daemon_works); + + return 0; +} + +int dazuko_unregister_daemon(struct xp_daemon_id *xp_id) +{ + struct daemon_id did; + int ret; + + if (xp_id == NULL) + return 0; + + did.unique = -1; + did.xp_id = call_xp_id_copy(xp_id); + + ret = _dazuko_unregister_daemon(&did); + + call_xp_id_free(did.xp_id); + + return ret; +} + +static inline int dazuko_state_error(struct slot *s, int current_state) +{ + if (dazuko_change_slot_state(s, current_state, DAZUKO_BROKEN, 1)) + { + call_xp_notify(&wait_kernel_waiting_for_free_slot); + call_xp_notify(&wait_kernel_waiting_while_daemon_works); + } + + return 0; +} + +static int dazuko_register_daemon(struct daemon_id *did, const char *reg_name, int string_length, int write_mode) +{ + const char *p1; + char *p2; + struct slot *s; + struct slot_list *sl; + int i; + + rsbac_pr_debug(adf_daz, "Registering daemon %s [%d]\n", reg_name, did->unique); + + if (did == NULL || reg_name == NULL) + return XP_ERROR_PERMISSION; + + s = dazuko_find_slot(did, 1, NULL); + + if (s != NULL) + { + /* We are already registered! */ + + rsbac_printk(KERN_INFO "dazuko: daemon %d already assigned to slot[%d]\n", did->unique, s->id); + + return XP_ERROR_PERMISSION; + } + + /* Find the slot_list with the matching name. */ + + for (i=0 ; ireg_name; + + while (*p1 == *p2) + { + if (*p1 == 0) + break; + + p1++; + p2++; + } + + if (*p1 == *p2) + break; + } + } + + if (i == NUM_SLOT_LISTS) + { + /* There is no slot_list with this name. We + * need to make one. */ + + sl = rsbac_kmalloc_clear_unlocked(sizeof(struct slot_list) + string_length + 1); + if (sl == NULL) + return XP_ERROR_FAULT; + + call_xp_atomic_set(&(sl->use_count), 0); + + p1 = reg_name; + p2 = sl->reg_name; + + while (*p1) + { + *p2 = *p1; + + p1++; + p2++; + } + *p2 = 0; + + /* give each slot a unique id */ + for (i=0 ; islots[i].id = i; + call_xp_init_mutex(&(sl->slots[i].mutex)); + } + + /* we need to find an empty slot */ + for (i=0 ; iunique = dazuko_get_new_unique(); + + s->did.unique = did->unique; + s->did.xp_id = call_xp_id_copy(did->xp_id); + s->write_mode = write_mode; + + call_xp_atomic_inc(&(sl->use_count)); + + /* the daemon is registered, but not yet + * ready to receive files */ + __dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE); + rsbac_pr_debug(adf_daz, "slot[%d] assigned to daemon %s [%d]", s->id, reg_name, did->unique); + call_xp_up(&(s->mutex)); +/* UP */ + + return 0; +} + +static struct slot* dazuko_get_an_access(struct daemon_id *did) +{ + /* The daemon is requesting a filename of a file + * to scan. This code will wait until a filename + * is available, or until we should be killed. + * (killing is done if any errors occur as well + * as when the user kills us) */ + + /* If a slot is returned, it will be already locked! */ + + int i; + struct slot *s; + struct one_slot_state_not_condition_param cond_p; + +tryagain: + /* find our slot */ + s = dazuko_find_slot(did, 1, NULL); + + if (s == NULL) + { + i = dazuko_register_daemon(did, "_COMPAT", 7, 1); + if (i != 0) + { + rsbac_printk(KERN_INFO "dazuko: unregistered daemon %d attempted to get access\n", did->unique); + return NULL; + } + + s = dazuko_find_slot(did, 1, NULL); + if (s == NULL) + { + rsbac_printk(KERN_INFO "dazuko: unregistered daemon %d attempted to get access\n", did->unique); + return NULL; + } + + rsbac_printk(KERN_INFO "dazuko: warning: daemon %d is using a deprecated protocol\n", did->unique); + } + + /* the daemon is now ready to receive a file */ + dazuko_change_slot_state(s, DAZUKO_READY, DAZUKO_READY, 1); + + cond_p.slot = s; + cond_p.state = DAZUKO_READY; + if (call_xp_wait_until_condition(&wait_daemon_waiting_for_work, one_slot_state_not_condition, &cond_p, 1) != 0) + { + /* The user has issued an interrupt. + * Return an error. The daemon should + * unregister itself. */ + + DPRINT(("dazuko: daemon %d killed while waiting for work\n", did->unique)); + + if (dazuko_change_slot_state(s, DAZUKO_READY, DAZUKO_BROKEN, 1) || dazuko_change_slot_state(s, DAZUKO_WAITING, DAZUKO_BROKEN, 1)) + { + call_xp_notify(&wait_kernel_waiting_for_free_slot); + call_xp_notify(&wait_kernel_waiting_while_daemon_works); + } + + return NULL; + } + + /* slot SHOULD now be in DAZUKO_WAITING state */ + + /* we will be working with the slot, so + * we need to lock it */ + +/* DOWN? */ + if (!dazuko_change_slot_state(s, DAZUKO_WAITING, DAZUKO_WORKING, 0)) + { + /* State transition error. Try again., */ + + goto tryagain; + } + +/* DOWN */ + + /* Slot IS in DAZUKO_WORKING state. Copy all the + * necessary information to userspace structure. */ + + /* IMPORTANT: slot is still locked! */ + + return s; /* access is available */ +} + +static int dazuko_return_access(struct daemon_id *did, int response, struct slot *s) +{ + /* The daemon has finished scanning a file + * and has the response to give. The daemon's + * slot should be in the DAZUKO_WORKING state. */ + + struct one_slot_state_not_condition_param cond_p; + + /* do we already have a slot? */ + if (s == NULL) + { + /* find our slot */ + s = dazuko_find_slot(did, 1, NULL); + + if (s == NULL) + { + /* It appears the kernel isn't interested + * in us or our response. It gave our slot away! */ + + DPRINT(("dazuko: daemon %d unexpectedly lost slot\n", did->unique)); + + return XP_ERROR_PERMISSION; + } + } + + /* we will be writing into the slot, so we + * need to lock it */ + +/* DOWN? */ + if (!dazuko_change_slot_state(s, DAZUKO_WORKING, DAZUKO_DONE, 0)) + { + /* The slot is in the wrong state. We will + * assume the kernel has cancelled the file + * access. */ + + DPRINT(("dazuko: response from daemon %d on slot[%d] not needed\n", did->unique, s->id)); + + return 0; + } + +/* DOWN */ + + s->response = response; + + call_xp_up(&(s->mutex)); +/* UP */ + + /* wake up any kernel processes that are + * waiting for responses */ + call_xp_notify(&wait_kernel_waiting_while_daemon_works); + + cond_p.slot = s; + cond_p.state = DAZUKO_DONE; + if (call_xp_wait_until_condition(&wait_daemon_waiting_for_free, one_slot_state_not_condition, &cond_p, 1) != 0) + { + /* The user has issued an interrupt. + * Return an error. The daemon should + * unregister itself. */ + + DPRINT(("dazuko: daemon %d killed while waiting for response acknowledgement\n", did->unique)); + + return XP_ERROR_INTERRUPT; + } + + return 0; +} + +static inline int dazuko_isdigit(const char c) +{ + return (c >= '0' && c <= '9'); +} + +static inline long dazuko_strtol(const char *string) +{ + long num = 1; + const char *p = string; + + if (string == NULL) + return 0; + + switch (*p) + { + case '-': + num = -1; + p++; + break; + + case '+': + p++; + break; + } + + if (dazuko_isdigit(*p)) + { + num *= *p - '0'; + p++; + } + else + { + return 0; + } + + while (dazuko_isdigit(*p)) + { + num *= 10; + num += *p - '0'; + p++; + } + + return num; +} + +static inline int dazuko_strlen(const char *string) +{ + const char *p; + + if (string == NULL) + return -1; + + for (p=string ; *p ; p++) + continue; + + return (p - string); +} + +static inline const char* dazuko_strchr(const char *haystack, char needle) +{ + const char *p; + + if (haystack == NULL) + return NULL; + + for (p=haystack ; *p ; p++) + { + if (*p == needle) + return p; + } + + return NULL; +} + +static inline const char* dazuko_strstr(const char *haystack, const char *needle) +{ + const char *p1; + const char *p2; + const char *p3; + + if (haystack == NULL || needle == NULL) + return NULL; + + for (p1=haystack ; *p1 ; p1++) + { + for (p2=needle,p3=p1 ; *p2&&*p3 ; p2++,p3++) + { + if (*p2 != *p3) + break; + } + + if (*p2 == 0) + return p1; + } + + return NULL; +} + +int dazuko_get_value(const char *key, const char *string, char **value) +{ + const char *p1; + const char *p2; + int size; + + if (value == NULL) + return -1; + + *value = NULL; + + if (key == NULL || string == NULL) + return -1; + + p1 = dazuko_strstr(string, key); + if (p1 == NULL) + return -1; + + p1 += dazuko_strlen(key); + + for (p2=p1 ; *p2 && *p2!='\n' ; p2++) + continue; + + size = (p2 - p1) + 1; + *value = rsbac_kmalloc_unlocked(size); + if (*value == NULL) + return -1; + + memcpy(*value, p1, size - 1); + (*value)[size - 1] = 0; + + return 0; +} + +static inline void dazuko_clear_replybuffer(struct dazuko_request *request) +{ + dazuko_bzero(request->reply_buffer, request->reply_buffer_size); + request->reply_buffer_size_used = 0; +} + +static inline void dazuko_close_replybuffer(struct dazuko_request *request) +{ + request->reply_buffer[request->reply_buffer_size_used] = 0; + request->reply_buffer_size_used++; +} + +static inline void dazuko_add_keyvalue_to_replybuffer(struct dazuko_request *request, const char *key, void *value, char vtype) +{ + +#define DAZUKO_VSNPRINT(type, name) dazuko_snprintf(request->reply_buffer + request->reply_buffer_size_used, (request->reply_buffer_size - request->reply_buffer_size_used) - 1, "%s%" #type , key, *((name *)value)) + + switch (vtype) + { + case 'd': + DAZUKO_VSNPRINT(d, const int); + break; + + case 's': + DAZUKO_VSNPRINT(s, const char *); + break; + + case 'l': + DAZUKO_VSNPRINT(lu, const unsigned long); + break; + + default: + /* all other types treated as chars */ + DAZUKO_VSNPRINT(c, const char); + break; + } + + /* update how much buffer we have used */ + request->reply_buffer_size_used += strlen(request->reply_buffer + request->reply_buffer_size_used); +} + +static inline int dazuko_printable(char c) +{ + /* hopefully this counts for all operating systems! */ + + return ((c >= ' ') && (c <= '~') && (c != '\\')); +} + +static inline void dazuko_add_esc_to_replybuffer(struct dazuko_request *request, const char *key, char **filename) +{ + int found = 0; + char *p_rq; + const char *limit; + const char *p_fn; + unsigned char c; + + /* check for escape characters in filename */ + for (p_fn=*filename ; *p_fn ; p_fn++) + { + if (!dazuko_printable(*p_fn)) + { + found = 1; + break; + } + } + + if (found) + { + /* this is expensive, but it will also almost never occur */ + + p_rq = request->reply_buffer + request->reply_buffer_size_used; + limit = request->reply_buffer + request->reply_buffer_size - 1; + + dazuko_snprintf(p_rq, limit - p_rq, "%s", key); + p_rq += strlen(p_rq); + + for (p_fn=*filename ; *p_fn && (p_rqreply_buffer_size_used += strlen(request->reply_buffer + request->reply_buffer_size_used); + } + else + { + /* no escape characters found */ + + dazuko_add_keyvalue_to_replybuffer(request, key, filename, 's'); + } +} + +static int dazuko_set_option(struct daemon_id *did, int opt, void *param, int len) +{ + /* The daemon wants to set a configuration + * option in the kernel. */ + + struct slot *s; + int error; + + /* sanity check */ + if (len < 0 || len > 8192) + return XP_ERROR_PERMISSION; + + /* make sure we are already registered + * (or that we don't register twice) */ + + /* find our slot */ + s = dazuko_find_slot(did, 1, NULL); + + switch (opt) + { + case REGISTER: + rsbac_printk(KERN_INFO "dazuko: dazuko_set_option does not support REGISTER (bug!)\n"); + return XP_ERROR_PERMISSION; + + case UNREGISTER: + if (s == NULL) + { + /* We are not registered! */ + + return 0; + } + break; + + default: + if (s == NULL) + { + error = dazuko_register_daemon(did, "_COMPAT", 7, 1); + if (error) + { + rsbac_printk(KERN_INFO "dazuko: unregistered daemon %d attempted access\n", did->unique); + return XP_ERROR_PERMISSION; + } + + s = dazuko_find_slot(did, 1, NULL); + if (s == NULL) + { + rsbac_printk(KERN_INFO "dazuko: unregistered daemon %d attempted access\n", did->unique); + return XP_ERROR_PERMISSION; + } + + rsbac_printk(KERN_INFO "dazuko: warning: daemon %d is using a deprecated protocol\n", did->unique); + } + break; + } + + /* check option type and take the appropriate action */ + switch (opt) + { + case UNREGISTER: + error = _dazuko_unregister_daemon(did); + if (error) + return error; + break; + + case SET_ACCESS_MASK: + memcpy(&access_mask, (char *)param, sizeof(char)); + break; + + case ADD_INCLUDE_PATH: + error = dazuko_insert_path_fs(&incl_paths, (char *)param, len); + if (error) + return error; + break; + + case ADD_EXCLUDE_PATH: + error = dazuko_insert_path_fs(&excl_paths, (char *)param, len); + if (error) + return error; + break; + + case REMOVE_ALL_PATHS: + dazuko_remove_all_paths(); + break; + + default: + rsbac_printk(KERN_INFO "dazuko: daemon %d requested unknown set %d (possible bug)\n", did->unique, opt); + break; + } + + return 0; +} + +static int dazuko_handle_request(struct dazuko_request *request, struct xp_daemon_id *xp_id) +{ + char *value1; + char *value2; + int error = 0; + int type; + struct slot *s; + struct daemon_id did; + + if (request == NULL || xp_id == NULL) + return -1; + + type = request->type[0] + (256 * request->type[1]); + + switch (type) + { + case REGISTER: + /* read "\nRM=regmode\nGN=group" */ + /* send "\nID=id" */ + + if (request->buffer_size <= 0) + return -1; + + if (request->reply_buffer_size <= 0) + return -1; + + if (dazuko_get_value("\nGN=", request->buffer, &value1) != 0) + return -1; + + if (dazuko_get_value("\nRM=", request->buffer, &value2) != 0) + { + rsbac_kfree(value1); + return -1; + } + + did.xp_id = call_xp_id_copy(xp_id); + did.unique = 0; /* a unique is not yet assigned */ + + error = dazuko_register_daemon(&did, value1, dazuko_strlen(value1), dazuko_strchr(value2, 'W') != NULL); + + dazuko_clear_replybuffer(request); + dazuko_add_keyvalue_to_replybuffer(request, "\nID=", &(did.unique), 'd'); + dazuko_close_replybuffer(request); + + rsbac_kfree(value1); + rsbac_kfree(value2); + call_xp_id_free(did.xp_id); + + break; + + case UNREGISTER: + /* read "\nID=id" */ + + if (request->buffer_size <= 0) + return -1; + + if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) + return -1; + + did.xp_id = call_xp_id_copy(xp_id); + did.unique = dazuko_strtol(value1); + + error = dazuko_set_option(&did, UNREGISTER, NULL, 0); + + rsbac_kfree(value1); + call_xp_id_free(did.xp_id); + + break; + + case SET_ACCESS_MASK: + /* read "\nID=id\nAM=mask" */ + + if (request->buffer_size <= 0) + return -1; + + if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) + return -1; + + if (dazuko_get_value("\nAM=", request->buffer, &value2) != 0) + { + rsbac_kfree(value1); + return -1; + } + + access_mask = (char)dazuko_strtol(value2); + + rsbac_kfree(value1); + rsbac_kfree(value2); + + break; + + case ADD_INCLUDE_PATH: + /* read "\nID=id\nPT=path" */ + + if (request->buffer_size <= 0) + return -1; + + if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) + return -1; + + if (dazuko_get_value("\nPT=", request->buffer, &value2) != 0) + { + rsbac_kfree(value1); + return -1; + } + + did.xp_id = call_xp_id_copy(xp_id); + did.unique = dazuko_strtol(value1); + + error = dazuko_set_option(&did, ADD_INCLUDE_PATH, value2, dazuko_strlen(value2)); + + rsbac_kfree(value1); + rsbac_kfree(value2); + call_xp_id_free(did.xp_id); + + break; + + case ADD_EXCLUDE_PATH: + /* read "\nID=id\nPT=path" */ + + if (request->buffer_size <= 0) + return -1; + + if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) + return -1; + + if (dazuko_get_value("\nPT=", request->buffer, &value2) != 0) + { + rsbac_kfree(value1); + return -1; + } + + did.xp_id = call_xp_id_copy(xp_id); + did.unique = dazuko_strtol(value1); + + error = dazuko_set_option(&did, ADD_EXCLUDE_PATH, value2, dazuko_strlen(value2)); + + rsbac_kfree(value1); + rsbac_kfree(value2); + call_xp_id_free(did.xp_id); + + break; + + case REMOVE_ALL_PATHS: + /* read "\nID=id" */ + + if (request->buffer_size <= 0) + return -1; + + if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) + return -1; + + did.xp_id = call_xp_id_copy(xp_id); + did.unique = dazuko_strtol(value1); + + error = dazuko_set_option(&did, REMOVE_ALL_PATHS, NULL, 0); + + rsbac_kfree(value1); + call_xp_id_free(did.xp_id); + + break; + + case GET_AN_ACCESS: + /* read "\nID=id" */ + /* send "\nFN=file\nFL=flags\nMD=mode\nUI=uid\nPI=pid" */ + + if (request->buffer_size <= 0) + return -1; + + if (request->reply_buffer_size <= 0) + return -1; + + if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) + return -1; + + did.xp_id = call_xp_id_copy(xp_id); + did.unique = dazuko_strtol(value1); + + rsbac_kfree(value1); + +/* DOWN? */ + s = dazuko_get_an_access(&did); + + if (s == NULL) + { + call_xp_id_free(did.xp_id); + return XP_ERROR_INTERRUPT; + } +/* DOWN */ + + /* Slot IS in DAZUKO_WORKING state. Copy all the + * necessary information to userspace structure. */ + + dazuko_clear_replybuffer(request); + dazuko_add_keyvalue_to_replybuffer(request, "\nEV=", &(s->event), 'd'); + dazuko_add_esc_to_replybuffer(request, "\nFN=", &(s->filename)); + + if (s->event_p.set_uid) + dazuko_add_keyvalue_to_replybuffer(request, "\nUI=", &(s->event_p.uid), 'd'); + + if (s->event_p.set_pid) + dazuko_add_keyvalue_to_replybuffer(request, "\nPI=", &(s->event_p.pid), 'd'); + + if (s->event_p.set_flags) + dazuko_add_keyvalue_to_replybuffer(request, "\nFL=", &(s->event_p.flags), 'd'); + + if (s->event_p.set_mode) + dazuko_add_keyvalue_to_replybuffer(request, "\nMD=", &(s->event_p.mode), 'd'); + + if (s->file_p.set_size) + dazuko_add_keyvalue_to_replybuffer(request, "\nFS=", &(s->file_p.size), 'l'); + + if (s->file_p.set_uid) + dazuko_add_keyvalue_to_replybuffer(request, "\nFU=", &(s->file_p.uid), 'd'); + + if (s->file_p.set_gid) + dazuko_add_keyvalue_to_replybuffer(request, "\nFG=", &(s->file_p.gid), 'd'); + + if (s->file_p.set_mode) + dazuko_add_keyvalue_to_replybuffer(request, "\nFM=", &(s->file_p.mode), 'd'); + + if (s->file_p.set_device_type) + dazuko_add_keyvalue_to_replybuffer(request, "\nDT=", &(s->file_p.device_type), 'd'); + + dazuko_close_replybuffer(request); + +/* XXX: What do we do if there is a problem copying back to userspace?! */ +/* dazuko_state_error(s, DAZUKO_WORKING); */ + + /* are we in read_only mode? */ + if (!(s->write_mode)) + { + /* the access is immediately (and at the kernel level) + * returned */ + + call_xp_up(&(s->mutex)); +/* UP */ + + dazuko_return_access(&did, 0, s); + } + else + { + call_xp_up(&(s->mutex)); +/* UP */ + } + + call_xp_id_free(did.xp_id); + + break; + + case RETURN_AN_ACCESS: + /* read "\nID=id\nDN=deny" */ + + if (request->buffer_size <= 0) + return -1; + + if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) + return -1; + + if (dazuko_get_value("\nDN=", request->buffer, &value2) != 0) + { + rsbac_kfree(value1); + return -1; + } + + did.xp_id = call_xp_id_copy(xp_id); + did.unique = dazuko_strtol(value1); + + error = dazuko_return_access(&did, dazuko_strtol(value2), NULL); + + rsbac_kfree(value1); + rsbac_kfree(value2); + call_xp_id_free(did.xp_id); + + break; + + default: + rsbac_printk(KERN_INFO "dazuko: daemon made unknown request %d (possible bug)\n", type); + + break; + } + + return error; +} + +int dazuko_handle_user_request(struct dazuko_request *user_request, struct xp_daemon_id *xp_id) +{ + int error = 0; + struct dazuko_request *request; + struct dazuko_request *temp_request; + + if (user_request == NULL || xp_id == NULL) + return XP_ERROR_FAULT; + + /* allocate kernel request */ + request = rsbac_smalloc_unlocked(dazuko_request_slab); + if (request == NULL) + return XP_ERROR_FAULT; + +/* use out0 now */ + + /* allocate temp kernel request */ + temp_request = rsbac_smalloc_unlocked(dazuko_request_slab); + if (temp_request == NULL) + { + error = XP_ERROR_FAULT; + goto dazuko_handle_user_request_out0; + } + +/* use out1 now */ + + /* copy in the request */ + if (call_xp_copyin(user_request, temp_request, sizeof(struct dazuko_request)) != 0) + { + error = XP_ERROR_FAULT; + goto dazuko_handle_user_request_out1; + } + + memcpy(request->type, temp_request->type, sizeof(char[2])); + request->buffer_size = temp_request->buffer_size; + + /* sanity check */ + if (request->buffer_size < 0 || request->buffer_size > 8192) + { + error = XP_ERROR_FAULT; + goto dazuko_handle_user_request_out1; + } + + request->reply_buffer_size = temp_request->reply_buffer_size; + + /* sanity check */ + if (request->reply_buffer_size < 0 || request->reply_buffer_size > 8192) + { + error = XP_ERROR_PERMISSION; + goto dazuko_handle_user_request_out1; + } + + /* allocate buffer */ + request->buffer = rsbac_kmalloc_unlocked(request->buffer_size + 1); + if (request->buffer == NULL) + { + error = XP_ERROR_FAULT; + goto dazuko_handle_user_request_out1; + } + +/* use out2 now */ + + if (request->reply_buffer_size > 0) + { + /* allocate reply buffer */ + request->reply_buffer = rsbac_kmalloc_unlocked(request->reply_buffer_size + 1); + if (request->reply_buffer == NULL) + { + error = XP_ERROR_FAULT; + goto dazuko_handle_user_request_out2; + } + +/* use out3 now */ + + request->reply_buffer_size_used = 0; + } + + /* copy the buffer from userspace to kernelspace */ + if (call_xp_copyin(temp_request->buffer, request->buffer, request->buffer_size) != 0) + { + error = XP_ERROR_FAULT; + goto dazuko_handle_user_request_out3; + } + + request->buffer[request->buffer_size] = 0; + + error = dazuko_handle_request(request, xp_id); + + if (error == 0 && request->reply_buffer_size > 0) + { + request->reply_buffer[request->reply_buffer_size] = 0; + + temp_request->reply_buffer_size_used = request->reply_buffer_size_used; + + if (call_xp_copyout(temp_request, user_request, sizeof(struct dazuko_request)) != 0) + { + error = XP_ERROR_FAULT; + goto dazuko_handle_user_request_out3; + } + + if (request->reply_buffer_size_used > 0) + { + if (call_xp_copyout(request->reply_buffer, temp_request->reply_buffer, request->reply_buffer_size_used) != 0) + { + error = XP_ERROR_FAULT; + goto dazuko_handle_user_request_out3; + } + } + } + +dazuko_handle_user_request_out3: + if (request->reply_buffer_size > 0) + rsbac_kfree(request->reply_buffer); +dazuko_handle_user_request_out2: + rsbac_kfree(request->buffer); +dazuko_handle_user_request_out1: + rsbac_sfree(dazuko_request_slab, temp_request); +dazuko_handle_user_request_out0: + rsbac_sfree(dazuko_request_slab, request); + + return error; +} + +int dazuko_handle_user_request_compat12(void *ptr, int cmd, struct xp_daemon_id *xp_id) +{ + struct access_compat12 *user_request12; + struct access_compat12 *temp_request12; + int error = 0; + struct slot *s; + char *k_param; + struct daemon_id did; + int temp_length; + int temp_int; + + if (ptr == NULL || xp_id == NULL) + return XP_ERROR_FAULT; + + did.xp_id = call_xp_id_copy(xp_id); + did.unique = -1; + + switch (cmd) + { + case IOCTL_GET_AN_ACCESS: + /* The daemon is requesting a filename of a file + * to scan. This code will wait until a filename + * is available, or until we should be killed. + * (killing is done if any errors occur as well + * as when the user kills us) */ + + user_request12 = (struct access_compat12 *)ptr; + + error = call_xp_verify_user_writable(user_request12, sizeof(struct access_compat12)); + if (error) + { + error = XP_ERROR_FAULT; + break; + } + +/* DOWN? */ + s = dazuko_get_an_access(&did); + + if (s == NULL) + { + error = XP_ERROR_INTERRUPT; + break; + } + +/* DOWN */ + + /* Slot IS in WORKING state. Copy all the + * necessary information to userspace structure. */ + + if (s->filenamelength >= DAZUKO_FILENAME_MAX_LENGTH_COMPAT12) + { + /* filename length overflow :( */ + + s->filename[DAZUKO_FILENAME_MAX_LENGTH_COMPAT12 - 1] = 0; + temp_length = DAZUKO_FILENAME_MAX_LENGTH_COMPAT12; + } + else + { + temp_length = s->filenamelength + 1; + } + + temp_request12 = rsbac_smalloc_unlocked(access_compat12_slab); + if (temp_request12 == NULL) + { + error = XP_ERROR_FAULT; + } + else if (call_xp_copyin(user_request12, temp_request12, sizeof(struct access_compat12)) != 0) + { + error = XP_ERROR_FAULT; + } + + if (error == 0) + { + temp_request12->event = s->event; + temp_request12->o_flags = s->event_p.flags; + temp_request12->o_mode = s->event_p.mode; + temp_request12->uid = s->event_p.uid; + temp_request12->pid = s->event_p.pid; + memcpy(temp_request12->filename, s->filename, temp_length); + + if (call_xp_copyout(temp_request12, user_request12, sizeof(struct access_compat12)) != 0) + { + error = XP_ERROR_FAULT; + } + } + + call_xp_up(&(s->mutex)); +/* UP */ + + if (error) + { + dazuko_state_error(s, DAZUKO_WORKING); + } + + if (temp_request12 != NULL) + { + rsbac_sfree(access_compat12_slab, temp_request12); + } + + break; + + case IOCTL_RETURN_ACCESS: + /* The daemon has finished scanning a file + * and has the response to give. The daemon's + * slot should be in the WORKING state. */ + + user_request12 = (struct access_compat12 *)ptr; + + error = call_xp_verify_user_readable(user_request12, sizeof(struct access_compat12)); + if (error) + { + error = XP_ERROR_FAULT; + break; + } + + temp_request12 = rsbac_smalloc_unlocked(access_compat12_slab); + if (temp_request12 == NULL) + { + error = XP_ERROR_FAULT; + break; + } + + if (call_xp_copyin(user_request12, temp_request12, sizeof(struct access_compat12)) != 0) + { + error = XP_ERROR_FAULT; + } + + temp_int = temp_request12->deny; + + rsbac_sfree(access_compat12_slab, temp_request12); + + error = dazuko_return_access(&did, temp_int, NULL); + break; + + case IOCTL_SET_OPTION: + /* The daemon wants to set a configuration + * option in the kernel. */ + + error = call_xp_verify_user_readable(ptr, 2*sizeof(int)); + if (error) + { + error = XP_ERROR_FAULT; + break; + } + + /* copy option type from userspace */ + if (call_xp_copyin(ptr, &temp_int, sizeof(int)) != 0) + { + error = XP_ERROR_FAULT; + break; + } + + ptr = ((char *)ptr + sizeof(int)); + + /* copy path length from userspace */ + if (call_xp_copyin(ptr, &temp_length, sizeof(int)) != 0) + { + error = XP_ERROR_FAULT; + break; + } + + /* sanity check */ + if (temp_length < 0 || temp_length > 4096) + { + error = XP_ERROR_INVALID; + break; + } + + ptr = ((char *)ptr + sizeof(int)); + + error = call_xp_verify_user_readable(ptr, temp_length); + if (error) + { + error = XP_ERROR_FAULT; + break; + } + + k_param = rsbac_kmalloc_unlocked(temp_length + 1); + if (k_param == NULL) + { + error = XP_ERROR_FAULT; + break; + } + + /* We must copy the param from userspace to kernelspace. */ + + if (call_xp_copyin(ptr, k_param, temp_length) != 0) + { + rsbac_kfree(k_param); + error = XP_ERROR_FAULT; + break; + } + + k_param[temp_length] = 0; + + if (temp_int == REGISTER) + error = dazuko_register_daemon(&did, k_param, temp_length, 1); + else + error = dazuko_set_option(&did, temp_int, k_param, temp_length); + + rsbac_kfree(k_param); + + break; + + default: + rsbac_printk(KERN_INFO "dazuko: daemon requested unknown device_ioctl %d (possible bug)\n", cmd); + + break; + } + + call_xp_id_free(did.xp_id); + + return error; +} + +static struct slot * dazuko_get_and_hold_ready_slot(struct slot_list *sl) +{ + /* This is a simple search to find a + * slot whose state is DAZUKO_READY. This means + * it is able to accept work. If a slot + * is found, the slot.mutex is held so + * it can be filled with work by the caller. + * It is the responsibility of the caller + * to RELEASE THE MUTEX. */ + + int i; + struct slot *s; + + for (i=0 ; islots[i]); +/* DOWN? */ + if (dazuko_change_slot_state(s, DAZUKO_READY, DAZUKO_WAITING, 0)) + { +/* DOWN */ + return s; + } + } + + /* we didn't find a slot that is ready for work */ + + return NULL; +} + +static int get_ready_slot_condition(void *param) +{ + return ((((struct get_ready_slot_condition_param *)param)->slot = dazuko_get_and_hold_ready_slot(((struct get_ready_slot_condition_param *)param)->slotlist)) != NULL + || call_xp_atomic_read(&active) == 0 + || call_xp_atomic_read(&(((struct get_ready_slot_condition_param *)param)->slotlist->use_count)) == 0); +} + +static int dazuko_run_daemon_on_slotlist(int event, char *filename, int filenamelength, struct event_properties *event_p, struct file_properties *file_p, int prev_response, struct slot_list *sl) +{ + /* This is the main function called by the kernel + * to work with a daemon. */ + + int rc; + int unique; + struct slot *s; + struct get_ready_slot_condition_param cond_p1; + struct two_slot_state_not_condition_param cond_p2; + +begin: + /* we initialize the slot value because + * we cannot guarentee that it will be + * assigned a new value BEFORE !active + * is checked */ + s = NULL; + + /* wait for a slot to become ready */ + cond_p1.slotlist = sl; + cond_p1.slot = s; + if (call_xp_wait_until_condition(&wait_kernel_waiting_for_free_slot, get_ready_slot_condition, &cond_p1, 0) != 0) + { + /* The kernel process was killed while + * waiting for a slot to become ready. + * This is fine. */ + + DPRINT(("dazuko: kernel process %d killed while waiting for free slot\n", event_p->pid)); + + return -1; /* user interrupted */ + } + + /* Make sure we have a slot. We may have + * gotten past the last wait because we + * are no longer active. */ + + s = cond_p1.slot; + + if (s == NULL) + { + /* We were no longer active. We don't + * need to initiate a daemon. This also + * means we never acquired the lock. */ + + return 0; /* allow access */ + } + +/* DOWN */ + + /* the slot is already locked at this point */ + + /* grab the daemon's unique */ + unique = s->did.unique; + + /* At this point we have a locked slot. It IS + * sitting in the DAZUKO_WAITING state, waiting for + * us to give it some work. */ + + /* set up the slot to do work */ + s->filename = filename; + s->event = event; + s->response = prev_response; + s->filenamelength = filenamelength; + + if (event_p == NULL) + dazuko_bzero(&(s->event_p), sizeof(struct event_properties)); + else + memcpy(&(s->event_p), event_p, sizeof(struct event_properties)); + + if (file_p == NULL) + dazuko_bzero(&(s->file_p), sizeof(struct file_properties)); + else + memcpy(&(s->file_p), file_p, sizeof(struct file_properties)); + + /* we are done modifying the slot */ + call_xp_up(&(s->mutex)); +/* UP */ + + /* wake up any daemons waiting for work */ + call_xp_notify(&wait_daemon_waiting_for_work); + + /* wait until the daemon is finished with the slot */ + cond_p2.slot1 = s; + cond_p2.state1 = DAZUKO_WAITING; + cond_p2.slot2 = s; + cond_p2.state2 = DAZUKO_WORKING; + if (call_xp_wait_until_condition(&wait_kernel_waiting_while_daemon_works, two_slot_state_not_condition, &cond_p2, 0) != 0) + { + /* The kernel process was killed while + * waiting for a daemon to process the file. + * This is fine. */ + + DPRINT(("dazuko: kernel process %d killed while waiting for daemon response\n", event_p->pid)); + + /* change the slot's state to let the + * daemon know we are not interested + * in a response */ + dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE, 1); + + return -1; /* user interrupted */ + } + + /* we are working with the slot, so + * we need to lock it */ +/* DOWN */ + if (call_xp_down(&(s->mutex)) != 0) + { + return -1; /* user interrupted */ + } + + /* make sure this is the right daemon */ + if (s->did.unique != unique) + { + /* This is a different daemon than + * the one we assigned work to. + * We need to scan again. */ + call_xp_up(&(s->mutex)); +/* UP */ + goto begin; + } + + /* The slot should now be in the DAZUKO_DONE state. */ + if (!__dazuko_change_slot_state(s, DAZUKO_DONE, DAZUKO_FREE)) + { + /* The daemon was killed while scanning. + * We need to scan again. */ + + call_xp_up(&(s->mutex)); +/* UP */ + goto begin; + } + + /* grab the response */ + rc = s->response; + + call_xp_up(&(s->mutex)); +/* UP */ + + /* CONGRATULATIONS! You successfully completed a full state cycle! */ + + return rc; +} + +static int dazuko_run_daemon(int event, char *filename, int filenamelength, struct event_properties *event_p, struct file_properties *file_p) +{ + struct slot_list *sl; + int i; + int rc = 0; + int error; + + if (event_p != NULL) + { + /* we don't want to throw the same event twice */ + if (event_p->thrown) + return 0; + event_p->thrown = 1; + } + + for (i=0 ; i 0) + { + /* this daemon wants access blocked */ + rc = 1; + } + } + } + + return rc; +} + +inline int dazuko_is_our_daemon(struct xp_daemon_id *xp_id) +{ + /* Check if the current process is one + * of the daemons. */ + + struct daemon_id did; + int ret; + + did.xp_id = call_xp_id_copy(xp_id); + did.unique = -1; + + ret = (dazuko_find_slot(&did, 1, NULL) != NULL); + + call_xp_id_free(did.xp_id); + + return ret; +} + +#ifdef CONFIG_RSBAC_DAZ_SELECT +static int dazuko_is_selected(struct dazuko_file_struct *kfs) +{ + /* Check if the given filename (with path) is + * under our include directories but not under + * the exclude directories. */ + + struct dazuko_file_listnode *cur; + struct dazuko_path *path; + int selected = 0; + int use_aliases = 1; + + if (kfs == NULL) + return 0; + + /* If we are interrupted here, we will report that + * this file is not selected. This will make the + * kernel allow normal access. Is this dangerous? */ +/* LOCK */ + call_xp_read_lock(&lock_lists); + + if (kfs->aliases == NULL && kfs->filename != NULL) + { + /* extension is not using aliases */ + + use_aliases = 0; + + kfs->aliases = rsbac_smalloc_clear(dazuko_file_listnode_slab); + if (kfs->aliases == NULL) + { + rsbac_printk(KERN_WARNING "dazuko: warning: access not controlled (%s)\n", kfs->filename); + return 0; + } + + kfs->aliases->filename = kfs->filename; + kfs->aliases->filename_length = kfs->filename_length; + } + + for (cur=kfs->aliases ; cur ; cur=cur->next) + { + if (cur->filename != NULL && cur->filename_length > 0) + { + /* check if filename is under our include paths */ + for (path=incl_paths ; path ; path=path->next) + { + /* the include item must be at least as long as the given filename */ + if (path->len <= cur->filename_length) + { + /* the include item should match the beginning of the given filename */ + if (memcmp(path->path, cur->filename, path->len) == 0) + { + kfs->filename = cur->filename; + kfs->filename_length = cur->filename_length; + + selected = 1; + break; + } + } + } + + /* If we didn't find a path, it isn't in our + * include directories. It can't be one of + * the selected files to scan. */ + if (!selected) + { + continue; + } + + /* check if filename is under our exclude paths */ + for (path=excl_paths ; path ; path=path->next) + { + /* the exclude item must be at least as long as the given filename */ + if (path->len <= cur->filename_length) + { + /* the exclude item should match the beginning of the given filename */ + if (memcmp(path->path, cur->filename, path->len) == 0) + { + kfs->filename = NULL; + kfs->filename_length = 0; + + selected = 0; + break; + } + } + } + + /* If we are still selected, then we can stop. */ + if (selected) + break; + } + } + + call_xp_read_unlock(&lock_lists); +/* UNLOCK */ + + if (!use_aliases) + { + rsbac_sfree(dazuko_file_listnode_slab, kfs->aliases); + kfs->aliases = NULL; + } + + return selected; +} +#endif + +static int dazuko_add_hash(struct xp_file *file, char *filename, int len) +{ + /* Add the given file and filename to the linked list + * of files to scan once they are closed. */ + + struct hash *h; + + /* create a new struct hash structure making room for name also */ + h = rsbac_kmalloc_unlocked(sizeof(struct hash) + len + 1); + if (h == NULL) + return XP_ERROR_FAULT; + + /* fill in structure items */ + + call_xp_copy_file(&(h->file), file); + h->dirty = 0; + h->namelen = len; + memcpy(h->name, filename, len); + h->name[len] = 0; + + /* add the new struct hash item to the head of the + * struct hash linked list */ + +/* LOCK */ + call_xp_write_lock(&lock_hash); + h->next = hash; + hash = h; + call_xp_write_unlock(&lock_hash); +/* UNLOCK */ + return 0; +} + +/* Code based on code from: Swade 12/08/02: Move dirty to end of list */ +static void dazuko_mark_hash_dirty(struct xp_file *file) +{ + struct hash *h = NULL; + struct hash *entry = NULL; + struct hash *prev = NULL; + struct hash *prev_entry = NULL; + +/* LOCK */ + call_xp_write_lock(&lock_hash); + + for (h=hash ; h ; h=h->next) + { + /* not found if hit first dirty entry */ + if (h->dirty) + { + entry = NULL; + break; + } + + if (call_xp_compare_file(&(h->file), file) == 0) + { + /* we found the entry */ + + prev_entry = prev; + entry = h; + break; + } + + prev = h; + } + + if (entry) + { + if (!entry->dirty) + { + /* mark as dirty */ + entry->dirty = 1; + + /* If we already are last entry or next + * entry dirty, we don't need to move */ + + if (entry->next) + { + if (!entry->next->dirty) + { + for (h=entry->next ; h ; h=h->next) + { + if (h->dirty) + break; + + prev = h; + } + + /* remove from current position */ + if (prev_entry) + prev_entry->next = entry->next; + else + hash = entry->next; + + if (prev == NULL) + { + /* insert as first item */ + entry->next = hash; + hash = entry; + } + else if (h) + { + /* insert before h (after prev) */ + entry->next = prev->next; + prev->next = entry; + } + else + { + /* insert as last item (after prev) */ + entry->next = NULL; + prev->next = entry; + } + } + } + } + } + + call_xp_write_unlock(&lock_hash); +/* UNLOCK */ + +} + +static struct hash *dazuko_get_hash(struct xp_file *file) +{ + /* Find the given file within our list + * and then remove it from the list and + * return it. */ + + struct hash *prev; + struct hash *cur; + +/* LOCK */ + call_xp_write_lock(&lock_hash); + + prev = NULL; + cur = hash; + while (cur) + { + if (call_xp_compare_file(&(cur->file), file) == 0) + { + /* we found the entry */ + + /* remove the item from the list */ + if (!prev) + hash = cur->next; + else + prev->next = cur->next; + break; + } + + prev = cur; + cur = cur->next; + } + + call_xp_write_unlock(&lock_hash); +/* UNLOCK */ + + return cur; +} + +static int dazuko_should_scan(struct dazuko_file_struct *kfs) +{ + /* Check if we are supposed to scan this file. + * This checks for all the correct file types, + * permissions, and if it is within the desired + * paths to scan. */ + + int result = 0; + + /* check if we already know if we scan this file */ + switch (kfs->should_scan) + { + /* case 0 means that we do not know yet. This is a little + * confusing, because 0 represents uninitialized. However, + * the should_scan variable is used in this function ONLY + * so this optimization shouldn't cause any problems. */ + + case 1: + /* we already know it should be scanned */ + return 1; + + case 2: + /* we already know it should not be scanned */ + return 2; + } + + /* make necessary platform-dependent checks */ + if (call_xp_fill_file_struct(kfs) == 0) + { +#ifdef CONFIG_RSBAC_DAZ_SELECT + if (dazuko_is_selected(kfs)) + { +#endif + /* If we made it this far, we are supposed + * to scan this file. We mark it so that + * any further immediate inquiries don't have + * to do all this work all over again. */ + + /* yes, should be scanned */ + kfs->should_scan = 1; + + result = 1; +#ifdef CONFIG_RSBAC_DAZ_SELECT + } + else + { + /* We will still mark it so that any further + * immediate inquiries don't have to do all + * this work all over again. */ + + /* no, should not be scanned */ + kfs->should_scan = 2; + } +#endif + } + + return result; +} + +inline int dazuko_sys_check(unsigned long event, int daemon_is_allowed, struct xp_daemon_id *xp_id) +{ + /* is this event in our mask? */ + switch (event) + { + case DAZUKO_ON_OPEN: + /* this is a special case because the on_close information needs + * to be saved during the on_open event */ + + if ((SCAN_ON_OPEN || SCAN_ON_CLOSE || SCAN_ON_CLOSE_MODIFIED) == 0) + return -1; + break; + + case DAZUKO_ON_CLOSE: + /* will need to scan if ON_CLOSE_MODIFIED is in the mask too */ + + if ((SCAN_ON_CLOSE || SCAN_ON_CLOSE_MODIFIED) == 0) + return -2; + break; + + default: + if ((access_mask & event) == 0) + return -3; + break; + } + + /* do we have any daemons? */ + if (call_xp_atomic_read(&active) <= 0) + return -4; + + /* should daemons be allowed this event without a scan? */ + if (daemon_is_allowed) + { + if (dazuko_is_our_daemon(xp_id)) + { + /* this is one of our daemons, so we will report as + * as if this event was not in the mask */ + + return -5; + } + } + + return 0; +} + +inline int dazuko_sys_pre(unsigned long event, struct dazuko_file_struct *kfs, struct xp_file *file, struct event_properties *event_p) +{ + /* return codes: + * >0 -> access should be blocked + * <0 -> access should be blocked (because user interrupted) + * 0 -> access is allowed + * -2 -> unscanned access should not be taken care of + */ + + int error = 0; + struct hash *h = NULL; + + switch (event) + { + case DAZUKO_ON_OPEN: + /* special case, because this pre may be called + * in order to record ON_CLOSE events (in post) */ + + if (!SCAN_ON_OPEN) + return 2; + break; + + case DAZUKO_ON_CLOSE: + /* handled in post */ + + return 2; + + case DAZUKO_ON_CLOSE_MODIFIED: + /* (this is really sys_write) always permitted */ + + return 2; + + default: + break; + } + + if (kfs == NULL) + { + /* kfs is required */ + + rsbac_printk(KERN_WARNING "dazuko: kfs=NULL (possible bug)\n"); + + return XP_ERROR_PERMISSION; + } + + if (file != NULL) + { + /* we search for the file descriptor first */ + +/* LOCK */ + call_xp_read_lock(&lock_hash); + + for (h=hash ; h ; h=h->next) + { + if (call_xp_compare_file(&(h->file), file) == 0) + { + /* we found the file descriptor */ + + kfs->filename = rsbac_kmalloc_unlocked(h->namelen + 1); + if (kfs->filename != NULL) + { + memcpy(kfs->filename, h->name, h->namelen); + kfs->filename[h->namelen] = 0; + kfs->filename_length = h->namelen; + kfs->should_scan = 1; + } + else + { + /* error allocating, so we get out */ + h = NULL; + } + break; + } + } + + call_xp_read_unlock(&lock_hash); +/* UNLOCK */ + + if (h == NULL && kfs->extra_data == NULL) + { + /* we don't know this file descriptor + * and we cannot fallback on name lookups + */ + + /* we should not scan this file */ + kfs->should_scan = 2; + + return 0; + } + } + + /* make sure we should scan this file */ + if (dazuko_should_scan(kfs)) + error = dazuko_run_daemon(event, kfs->filename, kfs->filename_length, event_p, &(kfs->file_p)); + else + return 2; + + if (error > 0) + { + /* access will be blocked */ + + /* dazuko_sys_post should NOT be called! */ + + return XP_ERROR_PERMISSION; + } + else if (error < 0) + { + /* user interrupted */ + + /* dazuko_sys_post should NOT be called! */ + + return XP_ERROR_INTERRUPT; + } + + /* access allowed */ + + return 0; +} + +inline int dazuko_sys_post(unsigned long event, struct dazuko_file_struct *kfs, struct xp_file *file, struct event_properties *event_p) +{ + struct hash *h = NULL; + + switch (event) + { + case DAZUKO_ON_OPEN: /* kfs,file required */ + /* if the file was opened and we are interested + * in scanning on close, add this file to our struct hash list */ + + if ((call_xp_atomic_read(&active) > 0) && file != NULL && kfs != NULL) + { + if (SCAN_ON_OPEN || SCAN_ON_CLOSE || SCAN_ON_CLOSE_MODIFIED) + { + /* make sure we should scan this file */ + if (dazuko_should_scan(kfs)) + { + /* hash is added if we were given an xp_file */ + if (file != NULL) + dazuko_add_hash(file, kfs->filename, kfs->filename_length); + + /* this is a fallback in case we didn't process the event in "sys_pre" */ + dazuko_run_daemon(event, kfs->filename, kfs->filename_length, event_p, &(kfs->file_p)); + } + } + } + break; + + case DAZUKO_ON_CLOSE: /* file,o_flags,o_mode,pid,uid required */ + if (file != NULL) + { + /* find hash entry and remove it from list */ + h = dazuko_get_hash(file); + + /* if we found the file in our list and the file was + * successfully closed, we need to scan it */ + if (h != NULL) + { + /* determine if we are scanning on close or close_modified */ + + /* note that close_modified has priority over just close */ + + if (SCAN_ON_CLOSE_MODIFIED && h->dirty) + dazuko_run_daemon(DAZUKO_ON_CLOSE_MODIFIED, h->name, h->namelen, event_p, NULL); + else if (SCAN_ON_CLOSE) + dazuko_run_daemon(DAZUKO_ON_CLOSE, h->name, h->namelen, event_p, NULL); + + /* clean up the struct hash structure */ + rsbac_kfree(h); + } + } + else + { + if (SCAN_ON_CLOSE) + { + if (dazuko_should_scan(kfs)) + { + dazuko_run_daemon(DAZUKO_ON_CLOSE, kfs->filename, kfs->filename_length, event_p, &(kfs->file_p)); + } + } + } + break; + + case DAZUKO_ON_CLOSE_MODIFIED: /* file required */ + if (file != NULL) + { + /* if we actually wrote something and we found the + * file in our list, set it as dirty */ + + /* Swade 4/24/02: Move to end of clean list */ + dazuko_mark_hash_dirty(file); + } + break; + + default: + break; + } + + return 0; +} + +inline int dazuko_init(void) +{ + int i; + int error; + +#ifdef CONFIG_RSBAC_DAZ_SELECT + dazuko_file_listnode_slab = rsbac_slab_create("rsbac_dazuko_file_listnode", + sizeof(struct dazuko_file_listnode)); +#endif + dazuko_request_slab = rsbac_slab_create("rsbac_dazuko_request", + sizeof(struct dazuko_request)); + access_compat12_slab = rsbac_slab_create("rsbac_dazuko_access_compat12", + sizeof(struct access_compat12)); + + call_xp_init_mutex(&mutex_unique_count); + + call_xp_init_rwlock(&lock_hash); + call_xp_init_rwlock(&lock_lists); + + call_xp_init_queue(&wait_kernel_waiting_for_free_slot); + call_xp_init_queue(&wait_daemon_waiting_for_work); + call_xp_init_queue(&wait_kernel_waiting_while_daemon_works); + call_xp_init_queue(&wait_daemon_waiting_for_free); + + dazuko_bzero(&slot_lists, sizeof(slot_lists)); + + for (i=0 ; iuse_count)) != 0) + rsbac_printk(KERN_WARNING "dazuko: slot_list count was not 0 (possible bug)\n"); + + for (j=0 ; jslots[j].mutex)); + } + + rsbac_kfree(slot_lists[i].slot_list); + slot_lists[i].slot_list = NULL; + } + + call_xp_destroy_mutex(&(slot_lists[i].mutex)); + } + + rsbac_printk(KERN_INFO "dazuko: unloaded, version=%s\n", VERSION); + } + + return error; +} diff --git a/rsbac/adf/daz/dazuko_xp.h b/rsbac/adf/daz/dazuko_xp.h new file mode 100644 index 000000000000..d755c87f2c3f --- /dev/null +++ b/rsbac/adf/daz/dazuko_xp.h @@ -0,0 +1,225 @@ +/* DazukoXP. Allow cross platform file access control for 3rd-party applications. + Written by John Ogness + + Copyright (c) 2002, 2003, 2004, 2005 H+BEDV Datentechnik GmbH + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of Dazuko nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef DAZUKO_XP_H +#define DAZUKO_XP_H + +#define VERSION "2.0.5" + +#include "dazukoio_xp.h" + +/* various requests */ +#define SET_ACCESS_MASK 0 +#define ADD_INCLUDE_PATH 1 +#define ADD_EXCLUDE_PATH 2 +#define REGISTER 3 +#define REMOVE_ALL_PATHS 4 +#define UNREGISTER 5 +#define GET_AN_ACCESS 6 +#define RETURN_AN_ACCESS 7 + +/* slot states */ +#define DAZUKO_FREE 0 /* the daemon is not ready */ +#define DAZUKO_READY 1 /* a daemon waits for something to do */ +#define DAZUKO_WAITING 2 /* a request is waiting to be served */ +#define DAZUKO_WORKING 3 /* daemon is currently in action */ +#define DAZUKO_DONE 4 /* daemon response is available */ +#define DAZUKO_BROKEN 5 /* invalid state (interrupt from ready,waiting) */ + +/* file types */ +#define DAZUKO_NONE 0 +#define DAZUKO_REGULAR 1 +#define DAZUKO_DIRECTORY 2 +#define DAZUKO_LINK 3 + + +/********************************************************* + * structures that MUST be implemented by platform-layer * + *********************************************************/ + +/* +struct xp_file; +struct xp_mutex; +struct xp_atomic; +struct xp_file_struct; +struct xp_queue; +struct xp_rwlock; +struct xp_daemon_id; +*/ + + +/****************************************** + * structures available to platform-layer * + ******************************************/ + +struct event_properties +{ + int thrown; + + int flags; + char set_flags; + int mode; + char set_mode; + int uid; + char set_uid; + int pid; + char set_pid; +}; + +struct file_properties +{ + unsigned long size; + char set_size; + int uid; + char set_uid; + int gid; + char set_gid; + int mode; + char set_mode; + int device_type; + char set_device_type; + int type; + char set_type; +}; + +struct dazuko_file_listnode +{ + char *filename; + int filename_length; + struct dazuko_file_listnode *next; +}; + +struct dazuko_file_struct +{ + /* A structure designed for simple and + * intelligent memory management when + * doing filename lookups in the kernel. */ + + int should_scan; /* already know we need to scan? */ + char *filename; /* filename to report (pointer in alias list) */ + int filename_length; /* length of filename reported */ + struct dazuko_file_listnode *aliases; /* list of file names (alias names) */ + struct file_properties file_p; /* properties of file */ + struct xp_file_struct *extra_data; /* extra platform-dependant data */ +}; + + +/******************************************************** + * functions that MUST be implemented by platform-layer * + ********************************************************/ + +/* mutex */ +int xp_init_mutex(struct xp_mutex *mutex); +int xp_down(struct xp_mutex *mutex); +int xp_up(struct xp_mutex *mutex); +int xp_destroy_mutex(struct xp_mutex *mutex); + +/* read-write lock */ +int xp_init_rwlock(struct xp_rwlock *rwlock); +int xp_write_lock(struct xp_rwlock *rwlock); +int xp_write_unlock(struct xp_rwlock *rwlock); +int xp_read_lock(struct xp_rwlock *rlock); +int xp_read_unlock(struct xp_rwlock *rlock); +int xp_destroy_rwlock(struct xp_rwlock *rwlock); + +/* wait-notify queue */ +int xp_init_queue(struct xp_queue *queue); +int xp_wait_until_condition(struct xp_queue *queue, int (*cfunction)(void *), void *cparam, int allow_interrupt); +int xp_notify(struct xp_queue *queue); +int xp_destroy_queue(struct xp_queue *queue); + +/* memory */ +void* xp_malloc(size_t size); +int xp_free(void *ptr); +int xp_copyin(const void *user_src, void *kernel_dest, size_t size); +int xp_copyout(const void *kernel_src, void *user_dest, size_t size); +int xp_verify_user_writable(const void *user_ptr, size_t size); +int xp_verify_user_readable(const void *user_ptr, size_t size); + +/* path attribute */ +int xp_is_absolute_path(const char *path); + +/* atomic */ +int xp_atomic_set(struct xp_atomic *atomic, int value); +int xp_atomic_inc(struct xp_atomic *atomic); +int xp_atomic_dec(struct xp_atomic *atomic); +int xp_atomic_read(struct xp_atomic *atomic); + +/* file descriptor */ +int xp_copy_file(struct xp_file *dest, struct xp_file *src); +int xp_compare_file(struct xp_file *file1, struct xp_file *file2); + +/* system hook */ +int xp_sys_hook(void); +int xp_sys_unhook(void); + +/* file structure */ +int xp_fill_file_struct(struct dazuko_file_struct *dfs); + +/* daemon id */ +int xp_id_compare(struct xp_daemon_id *id1, struct xp_daemon_id *id2); +int xp_id_free(struct xp_daemon_id *id); +struct xp_daemon_id* xp_id_copy(struct xp_daemon_id *id); + +/* output */ +int xp_print(const char *fmt, ...); + +/* debug */ +#ifdef DEBUG +#define DPRINT(fmt) xp_print fmt +#else +#define DPRINT(fmt) +#endif + + +/***************************************** + * functions available to platform-layer * + *****************************************/ + +int dazuko_vsnprintf(char *str, size_t size, const char *format, va_list ap); +int dazuko_snprintf(char *str, size_t size, const char *format, ...); +int dazuko_is_our_daemon(struct xp_daemon_id *xp_id); +int dazuko_get_value(const char *key, const char *string, char **value); +int dazuko_unregister_daemon(struct xp_daemon_id *xp_id); +int dazuko_handle_user_request(struct dazuko_request *user_request, struct xp_daemon_id *xp_id); +int dazuko_handle_user_request_compat12(void *ptr, int cmd, struct xp_daemon_id *xp_id); +int dazuko_get_filename_length(char *filename); +void dazuko_bzero(void *p, int len); +int dazuko_sys_check(unsigned long event, int daemon_is_allowed, struct xp_daemon_id *xp_id); +int dazuko_sys_pre(unsigned long event, struct dazuko_file_struct *kfs, struct xp_file *file, struct event_properties *event_p); +int dazuko_sys_post(unsigned long event, struct dazuko_file_struct *kfs, struct xp_file *file, struct event_properties *event_p); +int dazuko_init(void); +int dazuko_exit(void); + +#endif diff --git a/rsbac/adf/daz/dazukoio.h b/rsbac/adf/daz/dazukoio.h new file mode 100644 index 000000000000..9c8ea3967e33 --- /dev/null +++ b/rsbac/adf/daz/dazukoio.h @@ -0,0 +1,96 @@ +/* Dazuko Interface. Interace with Dazuko for file access control. + Written by John Ogness + + Copyright (c) 2002, 2003, 2004 H+BEDV Datentechnik GmbH + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of Dazuko nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef DAZUKOIO_H +#define DAZUKOIO_H + +/* event types */ +#define DAZUKO_ON_OPEN 1 +#define DAZUKO_ON_CLOSE 2 +#define DAZUKO_ON_EXEC 4 +#define DAZUKO_ON_CLOSE_MODIFIED 8 +#define DAZUKO_ON_UNLINK 16 +#define DAZUKO_ON_RMDIR 32 + +struct dazuko_access +{ + int deny; + int event; + char set_event; + int flags; + char set_flags; + int mode; + char set_mode; + int uid; + char set_uid; + int pid; + char set_pid; + char *filename; + char set_filename; + unsigned long file_size; + char set_file_size; + int file_uid; + char set_file_uid; + int file_gid; + char set_file_gid; + int file_mode; + char set_file_mode; + int file_device; + char set_file_device; +}; + +struct dazuko_id; +typedef struct dazuko_id dazuko_id_t; + +/* single-threaded API */ +int dazukoRegister(const char *groupName, const char *mode); +int dazukoSetAccessMask(unsigned long accessMask); +int dazukoAddIncludePath(const char *path); +int dazukoAddExcludePath(const char *path); +int dazukoRemoveAllPaths(void); +int dazukoGetAccess(struct dazuko_access **acc); +int dazukoReturnAccess(struct dazuko_access **acc); +int dazukoUnregister(void); + +/* thread-safe API (as long as each thread has its own "dazuko_id_t") */ +int dazukoRegister_TS(dazuko_id_t **dazuko, const char *groupName, const char *mode); +int dazukoSetAccessMask_TS(dazuko_id_t *dazuko, unsigned long accessMask); +int dazukoAddIncludePath_TS(dazuko_id_t *dazuko, const char *path); +int dazukoAddExcludePath_TS(dazuko_id_t *dazuko, const char *path); +int dazukoRemoveAllPaths_TS(dazuko_id_t *dazuko); +int dazukoGetAccess_TS(dazuko_id_t *dazuko, struct dazuko_access **acc); +int dazukoReturnAccess_TS(dazuko_id_t *dazuko, struct dazuko_access **acc); +int dazukoUnregister_TS(dazuko_id_t **dazuko); + +#endif diff --git a/rsbac/adf/daz/dazukoio_xp.h b/rsbac/adf/daz/dazukoio_xp.h new file mode 100644 index 000000000000..4f8ccf036f03 --- /dev/null +++ b/rsbac/adf/daz/dazukoio_xp.h @@ -0,0 +1,100 @@ +/* DazukoXP Interface. Interace with Dazuko for file access control. + Written by John Ogness + + Copyright (c) 2002, 2003, 2004 H+BEDV Datentechnik GmbH + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of Dazuko nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef DAZUKOIO_XP_H +#define DAZUKOIO_XP_H + +/* various requests */ +#define SET_ACCESS_MASK 0 +#define ADD_INCLUDE_PATH 1 +#define ADD_EXCLUDE_PATH 2 +#define REGISTER 3 +#define REMOVE_ALL_PATHS 4 +#define UNREGISTER 5 +#define GET_AN_ACCESS 6 +#define RETURN_AN_ACCESS 7 + +/* this is just a large number to "guarentee" + to contain the full filename */ +#define DAZUKO_FILENAME_MAX_LENGTH 6144 + +/* this is the hard-limit file length restriction from + the 1.x series */ +#define DAZUKO_FILENAME_MAX_LENGTH_COMPAT12 4095 + +struct dazuko_request +{ + char type[2]; + int buffer_size; + char *buffer; + int reply_buffer_size; + char *reply_buffer; + int reply_buffer_size_used; +}; + +struct dazuko_id +{ + int device; + int dev_major; + int id; + int write_mode; +}; + +/* compat12 ioctls */ + +#define IOCTL_SET_OPTION 0 +#define IOCTL_GET_AN_ACCESS 1 +#define IOCTL_RETURN_ACCESS 2 + +/* compat12 structures */ + +struct access_compat12 +{ + int deny; /* set to deny file access */ + int event; /* ON_OPEN, etc */ + int o_flags; /* access flags */ + int o_mode; /* access mode */ + int uid; /* user id */ + int pid; /* user process id */ + char filename[DAZUKO_FILENAME_MAX_LENGTH_COMPAT12]; /* accessed file */ +}; + +struct option_compat12 +{ + int command; + int buffer_length; + char buffer[DAZUKO_FILENAME_MAX_LENGTH_COMPAT12]; +}; + +#endif diff --git a/rsbac/adf/ff/Makefile b/rsbac/adf/ff/Makefile new file mode 100644 index 000000000000..139b30b6b828 --- /dev/null +++ b/rsbac/adf/ff/Makefile @@ -0,0 +1,9 @@ +# +# File: rsbac/adf/ff/Makefile +# +# Makefile for the Linux rsbac ff decision module. +# +# Author and (c) 1999-2012 Amon Ott +# + +obj-y := ff_main.o diff --git a/rsbac/adf/ff/ff_main.c b/rsbac/adf/ff/ff_main.c new file mode 100644 index 000000000000..bd0f725724f6 --- /dev/null +++ b/rsbac/adf/ff/ff_main.c @@ -0,0 +1,714 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - File Flags */ +/* File: rsbac/adf/ff/main.c */ +/* */ +/* Author and (c) 1999-2017: Amon Ott */ +/* */ +/* Last modified: 21/Mar/2017 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + + +static enum rsbac_adf_req_ret_t + check_flags_ff(enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_ff_flags_t flags) + { + union rsbac_attribute_value_t i_attr_val1; + + /* get target's file flags */ + if (rsbac_get_attr(SW_FF, target, + tid, + A_ff_flags, + &i_attr_val1, + TRUE)) + { + rsbac_printk(KERN_WARNING "check_flags_ff(): rsbac_get_attr() returned error!\n"); + return(NOT_GRANTED); + } + + /* Access is granted, if none of the flags in argument flags is set */ + if (i_attr_val1.ff_flags & flags) + return(NOT_GRANTED); + else + return(GRANTED); + } + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +inline enum rsbac_adf_req_ret_t + rsbac_adf_request_ff (enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + enum rsbac_adf_req_ret_t result = DO_NOT_CARE; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + int err=0; + + switch (request) + { + case R_GET_STATUS_DATA: + switch(target) + { + case T_SCD: + switch(tid.scd) + { + case ST_rsbac_log: + case ST_rsbac_remote_log: + break; + default: + return GRANTED; + } + i_tid.user = owner; + if ((err=rsbac_get_attr(SW_FF, T_USER, + i_tid, + A_ff_role, + &i_attr_val1, + FALSE))) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_request_ff(): rsbac_get_attr() returned error %i!\n",err); + return(NOT_GRANTED); + } + if ( (i_attr_val1.system_role == SR_security_officer) + || (i_attr_val1.system_role == SR_auditor) + ) + return(GRANTED); + else + return(NOT_GRANTED); + default: + return(DO_NOT_CARE); + } + +#if defined(CONFIG_RSBAC_FF_UM_PROT) + case R_GET_PERMISSIONS_DATA: + switch(target) + { + case T_USER: + case T_GROUP: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_FF, + T_USER, + i_tid, + A_ff_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_ff()", A_ff_role); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + /* We do not care about */ + /* all other cases */ + default: return(DO_NOT_CARE); + } +#endif + + case R_READ: + switch(target) + { + case T_DIR: + return(check_flags_ff(target,tid, + FF_search_only)); + +#ifdef CONFIG_RSBAC_RW + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + return(check_flags_ff(target,tid, + FF_write_only)); +#endif + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_READ_OPEN: + switch(target) + { + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + return(check_flags_ff(target,tid, + FF_execute_only | FF_write_only)); + case T_DIR: + return(check_flags_ff(target,tid, + FF_search_only)); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_MAP_EXEC: + case R_EXECUTE: + switch(target) + { + case T_FILE: + return(check_flags_ff(target,tid, + FF_write_only | FF_no_execute | FF_append_only)); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_APPEND_OPEN: + switch(target) + { + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + return(check_flags_ff(target,tid, + FF_read_only | FF_execute_only)); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_READ_WRITE_OPEN: + switch(target) + { + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + return(check_flags_ff(target,tid, + FF_read_only | FF_execute_only + | FF_write_only | FF_append_only)); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_CHDIR: + switch(target) + { + case T_DIR: + return(check_flags_ff(target,tid, + FF_search_only)); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + /* Creating dir or (pseudo) file IN target dir! */ + case R_CREATE: + switch(target) + { + case T_DIR: + return(check_flags_ff(target,tid, + FF_read_only | FF_search_only)); + +#if defined(CONFIG_RSBAC_FF_UM_PROT) + case T_USER: + case T_GROUP: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_FF, + T_USER, + i_tid, + A_ff_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_ff()", A_ff_role); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); +#endif + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_DELETE: + case R_RENAME: + switch(target) + { + case T_FILE: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + return(check_flags_ff(target,tid, + FF_read_only | FF_execute_only | FF_no_delete_or_rename + | FF_append_only)); + case T_DIR: + return(check_flags_ff(target,tid, + FF_read_only | FF_search_only | FF_no_delete_or_rename)); + +#if defined(CONFIG_RSBAC_FF_UM_PROT) + case T_USER: + case T_GROUP: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_FF, + T_USER, + i_tid, + A_ff_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_ff()", A_ff_role); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); +#endif + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_CHANGE_GROUP: + case R_MODIFY_PERMISSIONS_DATA: + switch(target) + { + case T_FILE: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + return(check_flags_ff(target,tid, + FF_read_only | FF_execute_only | FF_append_only)); + case T_DIR: + return(check_flags_ff(target,tid, + FF_read_only | FF_search_only)); + +#if defined(CONFIG_RSBAC_FF_UM_PROT) + case T_USER: + case T_GROUP: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_FF, + T_USER, + i_tid, + A_ff_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_ff()", A_ff_role); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); +#endif + + /* all other cases are undefined */ + default: + return(DO_NOT_CARE); + } + + case R_CHANGE_OWNER: + switch(target) + { + case T_FILE: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + return(check_flags_ff(target,tid, + FF_read_only | FF_execute_only | FF_append_only)); + case T_DIR: + return(check_flags_ff(target,tid, + FF_read_only | FF_search_only)); + /* all other cases are undefined */ + default: + return(DO_NOT_CARE); + } + + case R_SEARCH: + switch(target) + { + case T_FILE: + case T_DIR: + case T_SYMLINK: + case T_FIFO: + case T_UNIXSOCK: + i_tid.user = owner; + if ((err = rsbac_get_attr(SW_FF, T_USER, + i_tid, + A_ff_role, + &i_attr_val1, FALSE))) { + rsbac_printk(KERN_WARNING "rsbac_adf_request_ff(): rsbac_get_attr() returned error %i!\n",err); + return (NOT_GRANTED); + } + if (i_attr_val1.system_role == (SR_security_officer || SR_auditor)) + return (GRANTED); + else + return(check_flags_ff(target,tid, + FF_no_search)); + default: + return(DO_NOT_CARE); + } + + case R_LINK_HARD: + switch(target) + { + case T_FILE: + case T_UNIXSOCK: + case T_FIFO: + case T_SYMLINK: + return(check_flags_ff(target,tid, + FF_read_only | FF_execute_only)); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_MODIFY_ACCESS_DATA: + switch(target) + { + case T_FILE: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + return(check_flags_ff(target,tid, + FF_read_only | FF_execute_only | FF_append_only)); + case T_DIR: + return(check_flags_ff(target,tid, + FF_read_only | FF_search_only)); + + /* all other cases are undefined */ + default: + return(DO_NOT_CARE); + } + + case R_MODIFY_ATTRIBUTE: + switch(attr) + { + case A_ff_flags: + case A_system_role: + case A_ff_role: + #ifdef CONFIG_RSBAC_FF_AUTH_PROT + case A_auth_may_setuid: + case A_auth_may_set_cap: + case A_auth_start_uid: + case A_auth_start_euid: + case A_auth_start_gid: + case A_auth_start_egid: + case A_auth_learn: + case A_auth_add_f_cap: + case A_auth_remove_f_cap: + #endif + #ifdef CONFIG_RSBAC_FF_GEN_PROT + case A_log_array_low: + case A_log_array_high: + case A_log_program_based: + case A_log_user_based: + case A_symlink_add_remote_ip: + case A_symlink_add_uid: + case A_symlink_add_rc_role: + case A_allow_write_exec: + case A_pseudo: + case A_fake_root_uid: + case A_audit_uid: + case A_auid_exempt: + case A_remote_ip: + case A_vset: + #endif + /* All attributes (remove target!) */ + case A_none: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_FF, T_USER, + i_tid, + A_ff_role, + &i_attr_val1, + FALSE)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_request_ff(): rsbac_get_attr() returned error!\n"); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + default: + return(DO_NOT_CARE); + } + + case R_MODIFY_SYSTEM_DATA: + switch(target) + { + case T_SCD: + switch(tid.scd) + { + case ST_rsbac_log: + case ST_rsbac_remote_log: + break; + case ST_kmem: + return NOT_GRANTED; + default: + return GRANTED; + } + /* Get role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_FF, T_USER, + i_tid, + A_ff_role, + &i_attr_val1, + FALSE)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_request_ff(): rsbac_get_attr() returned error!\n"); + return(NOT_GRANTED); + } + /* grant only for secoff */ + if ( (i_attr_val1.system_role == SR_security_officer) + || (i_attr_val1.system_role == SR_auditor) + ) + return(GRANTED); + else + return(NOT_GRANTED); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_MOUNT: + case R_UMOUNT: + switch(target) + { + case T_FILE: + return(check_flags_ff(target,tid, + FF_read_only | FF_execute_only + | FF_write_only | FF_append_only | FF_no_mount)); + case T_DIR: + return(check_flags_ff(target,tid, + FF_read_only | FF_search_only | FF_no_mount)); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_SWITCH_LOG: + switch(target) + { + case T_NONE: + /* test owner's ff_role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_FF, T_USER, + i_tid, + A_ff_role, + &i_attr_val1, + FALSE)) + { + rsbac_printk(KERN_WARNING "rsbac_adf_request_ff(): rsbac_get_attr() returned error!\n"); + return(NOT_GRANTED); + } + /* security officer? -> grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_SWITCH_MODULE: + switch(target) + { + case T_NONE: + /* we need the switch_target */ + if(attr != A_switch_target) + return NOT_GRANTED; + /* do not care for other modules */ + if( (attr_val.switch_target != SW_FF) + #ifdef CONFIG_RSBAC_SOFTMODE + && (attr_val.switch_target != SW_SOFTMODE) + #endif + #ifdef CONFIG_RSBAC_FREEZE + && (attr_val.switch_target != SW_FREEZE) + #endif + #ifdef CONFIG_RSBAC_MPROTECT + && (attr_val.switch_target != SW_MPROTECT) + #endif + #ifdef CONFIG_RSBAC_FF_AUTH_PROT + && (attr_val.switch_target != SW_AUTH) + #endif + ) + return(DO_NOT_CARE); + /* test owner's ff_role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_FF, T_USER, + i_tid, + A_ff_role, + &i_attr_val1, + FALSE)) + { + rsbac_printk(KERN_WARNING "rsbac_adf_request_ff(): rsbac_get_attr() returned error!\n"); + return(NOT_GRANTED); + } + /* security officer? -> grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_TRUNCATE: + switch(target) + { + case T_FILE: + case T_FIFO: + return(check_flags_ff(target,tid, + FF_read_only | FF_execute_only | FF_append_only)); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_WRITE_OPEN: + switch(target) + { + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + return(check_flags_ff(target,tid, + FF_read_only | FF_execute_only | FF_append_only)); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_WRITE: + switch(target) + { + case T_DIR: + return(check_flags_ff(target,tid, + FF_read_only | FF_search_only)); + +#ifdef CONFIG_RSBAC_RW + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + return(check_flags_ff(target,tid, + FF_read_only | FF_execute_only)); +#endif +#if defined(CONFIG_RSBAC_FF_UM_PROT) + case T_USER: + case T_GROUP: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_FF, + T_USER, + i_tid, + A_ff_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_ff()", A_ff_role); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); +#endif + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + case R_MOVETO: + switch(target) + { + case T_DIR: + return(check_flags_ff(target,tid, + FF_read_only | FF_search_only)); + + /* all other cases are undefined */ + default: return(DO_NOT_CARE); + } + + +/*********************/ + default: return DO_NOT_CARE; + } + + return result; + } /* end of rsbac_adf_request_ff() */ + + +/******************************************/ +#ifdef CONFIG_RSBAC_SECDEL +inline rsbac_boolean_t rsbac_need_overwrite_ff(struct dentry * dentry_p) + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + if( !dentry_p + || !dentry_p->d_inode) + return FALSE; + + i_tid.file.device = dentry_p->d_sb->s_dev; + i_tid.file.inode = dentry_p->d_inode->i_ino; + i_tid.file.dentry_p = dentry_p; + /* get target's file flags */ + if (rsbac_get_attr(SW_FF, T_FILE, + i_tid, + A_ff_flags, + &i_attr_val1, + TRUE)) + { + rsbac_printk(KERN_WARNING "rsbac_need_overwrite_ff(): rsbac_get_attr() returned error!\n"); + return FALSE; + } + + /* overwrite, if secure_delete is set */ + if (i_attr_val1.ff_flags & FF_secure_delete) + return TRUE; + else + return FALSE; + } +#endif + +/* end of rsbac/adf/ff/main.c */ diff --git a/rsbac/adf/jail/Makefile b/rsbac/adf/jail/Makefile new file mode 100644 index 000000000000..91607dc7f0e5 --- /dev/null +++ b/rsbac/adf/jail/Makefile @@ -0,0 +1,10 @@ +# +# File: rsbac/adf/jail/Makefile +# +# Makefile for the Linux rsbac jail decision module. +# +# Author and (c) 1999-2013 Amon Ott +# + +obj-y := jail_syscalls.o jail_main.o + diff --git a/rsbac/adf/jail/jail_main.c b/rsbac/adf/jail/jail_main.c new file mode 100644 index 000000000000..7239cd399c9a --- /dev/null +++ b/rsbac/adf/jail/jail_main.c @@ -0,0 +1,1456 @@ +/**************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - Authorization module */ +/* File: rsbac/adf/jail/jail_main.c */ +/* */ +/* Author and (c) 1999-2017: Amon Ott */ +/* */ +/* Last modified: 28/Feb/2017 */ +/**************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +static inline rsbac_boolean_t jail_dev_tty(struct rsbac_dev_desc_t dev) +{ + if (dev.type != D_char) + return FALSE; + if (((dev.major >= 2) + && (dev.major <= 4) + ) + || ((dev.major >= 128) + && (dev.major <= 143) + ) + ) + return TRUE; + else + return FALSE; +} + +static rsbac_jail_id_t +jail_get_id(enum rsbac_target_t target, union rsbac_target_id_t tid) +{ + int err; + union rsbac_attribute_value_t i_attr_val1; + + if ((err = rsbac_get_attr(SW_JAIL, + target, + tid, A_jail_id, &i_attr_val1, FALSE))) { + rsbac_ds_get_error("jail_get_id()", A_jail_id); + return 0; + } else + return i_attr_val1.jail_id; +} + +static rsbac_jail_id_t jail_get_id_process(rsbac_pid_t pid) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + i_tid.process = pid; + if ((err = rsbac_get_attr(SW_JAIL, T_PROCESS, + i_tid, A_jail_id, &i_attr_val1, FALSE))) { + rsbac_ds_get_error("jail_get_id_process()", A_jail_id); + return 0; + } else + return i_attr_val1.jail_id; +} + +static inline rsbac_jail_id_t jail_get_parent_process(rsbac_pid_t pid) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + i_tid.process = pid; + if ((err = rsbac_get_attr(SW_JAIL, T_PROCESS, + i_tid, A_jail_parent, &i_attr_val1, FALSE))) { + rsbac_ds_get_error("jail_get_parent_process()", A_jail_parent); + return 0; + } else + return i_attr_val1.jail_parent; +} + +#if defined(CONFIG_RSBAC_NET_OBJ) +static inline rsbac_jail_ip_t jail_get_ip_process(rsbac_pid_t pid) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + i_tid.process = pid; + if ((err = rsbac_get_attr(SW_JAIL, T_PROCESS, + i_tid, A_jail_ip, &i_attr_val1, FALSE))) { + rsbac_ds_get_error("jail_get_ip_process()", A_jail_ip); + return 0; + } else + return i_attr_val1.jail_ip; +} +#endif + +static rsbac_jail_flags_t jail_get_flags_process(rsbac_pid_t pid) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + i_tid.process = pid; + if ((err = rsbac_get_attr(SW_JAIL, T_PROCESS, i_tid, + A_jail_flags, &i_attr_val1, FALSE))) { + rsbac_ds_get_error("jail_get_flags_process()", + A_jail_flags); + return 0; + } else + return i_attr_val1.jail_flags; +} + +static inline rsbac_jail_scd_vector_t jail_get_scd_get_process(rsbac_pid_t pid) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + i_tid.process = pid; + if ((err = rsbac_get_attr(SW_JAIL, T_PROCESS, i_tid, + A_jail_scd_get, &i_attr_val1, FALSE))) { + rsbac_ds_get_error("jail_get_scd_get_process()", + A_jail_scd_get); + return 0; + } else + return i_attr_val1.jail_scd_get; +} + +static inline rsbac_jail_scd_vector_t jail_get_scd_modify_process(rsbac_pid_t pid) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + i_tid.process = pid; + if ((err = rsbac_get_attr(SW_JAIL, T_PROCESS, i_tid, + A_jail_scd_modify, + &i_attr_val1, FALSE))) { + rsbac_ds_get_error("jail_get_scd_modify_process()", + A_jail_scd_modify); + return 0; + } else + return i_attr_val1.jail_scd_modify; +} + +static enum rsbac_adf_req_ret_t +jail_check_sysrole(rsbac_uid_t owner, + enum rsbac_system_role_t role) +{ + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + i_tid.user = owner; + if (rsbac_get_attr(SW_JAIL, T_USER, i_tid, + A_jail_role, &i_attr_val1, FALSE)) { + rsbac_ds_get_error("jail_check_sysrole()", A_jail_role); + return (NOT_GRANTED); + } + /* if correct role, then grant */ + if (i_attr_val1.system_role == role) + return (GRANTED); + else + return (NOT_GRANTED); +} + +#if defined(CONFIG_RSBAC_NET_OBJ) +enum rsbac_adf_req_ret_t +jail_check_ip(rsbac_pid_t pid, union rsbac_target_id_t tid) +{ + rsbac_jail_ip_t jail_ip; + rsbac_jail_flags_t jail_flags; + + if (!tid.netobj.sock_p) { + rsbac_printk(KERN_WARNING + "jail_check_ip(): NULL sock_p!\n"); + return NOT_GRANTED; + } + if (!tid.netobj.sock_p->ops) { + return DO_NOT_CARE; + } + switch (tid.netobj.sock_p->ops->family) { + case AF_UNIX: + return DO_NOT_CARE; + + case AF_INET: + switch (tid.netobj.sock_p->type) { + case SOCK_STREAM: + case SOCK_DGRAM: + case SOCK_RDM: + jail_ip = jail_get_ip_process(pid); + if (jail_ip == INADDR_ANY) + return GRANTED; + jail_flags = jail_get_flags_process(pid); + if (tid.netobj.local_addr) { + struct sockaddr_in *addr = + tid.netobj.local_addr; + + if ((jail_ip == addr->sin_addr.s_addr) + || ( + (jail_flags & + JAIL_allow_inet_localhost) + && (addr->sin_addr.s_addr == + RSBAC_JAIL_LOCALHOST) + ) +#if defined(CONFIG_RSBAC_JAIL_NET_ADJUST) + || ( + (jail_flags & + JAIL_auto_adjust_inet_any) + && (addr->sin_addr.s_addr == + INADDR_ANY) + ) +#endif + ) + return GRANTED; + else { + rsbac_pr_debug(adf_jail, "local_addr does not match jail_ip -> NOT_GRANTED!\n"); + return NOT_GRANTED; + } + } else if ((tid.netobj.remote_addr) + && (jail_flags & + JAIL_allow_inet_localhost) + && + (((struct sockaddr_in *) tid.netobj. + remote_addr)->sin_addr.s_addr == + RSBAC_JAIL_LOCALHOST) + ) + return GRANTED; + else { + if (((jail_ip == + inet_sk(tid.netobj.sock_p->sk)-> + inet_rcv_saddr) + && (jail_ip == + inet_sk(tid.netobj.sock_p->sk)-> + inet_saddr) + ) + || ( + (jail_flags & + JAIL_allow_inet_localhost) + && + ((inet_sk(tid.netobj.sock_p->sk)-> + inet_saddr == RSBAC_JAIL_LOCALHOST) + || ( + inet_sk(tid.netobj.sock_p->sk)-> + inet_daddr == RSBAC_JAIL_LOCALHOST) + ) + ) +#if defined(CONFIG_RSBAC_JAIL_NET_ADJUST) + || ( + (jail_flags & + JAIL_auto_adjust_inet_any) + && (inet_sk(tid.netobj.sock_p->sk)-> + inet_rcv_saddr == INADDR_ANY) + && (inet_sk(tid.netobj.sock_p->sk)-> + inet_saddr == INADDR_ANY) + ) +#endif + ) + return GRANTED; + else { + rsbac_pr_debug(adf_jail, "sk->inet_rcv_saddr or sk->inet_saddr does not match jail_ip -> NOT_GRANTED!\n"); + return NOT_GRANTED; + } + } + + case SOCK_RAW: + if (jail_get_flags_process(pid) & + JAIL_allow_inet_raw) + return GRANTED; + else { + rsbac_pr_debug(adf_jail, "network type is raw and allow_inet_raw is not set -> NOT_GRANTED!\n"); + return NOT_GRANTED; + } + + default: + rsbac_pr_debug(adf_jail, "network type not STREAM, DGRAM, RDM or RAW -> NOT_GRANTED!\n"); + return NOT_GRANTED; + } + + case AF_NETLINK: + if (jail_get_flags_process(pid) & + (JAIL_allow_all_net_family | JAIL_allow_netlink)) + return GRANTED; + else { + rsbac_pr_debug(adf_jail, "network family is NETLINK and neither allow_netlink nor allow_all_net_family is set -> NOT_GRANTED!\n"); + return NOT_GRANTED; + } + + default: + if (jail_get_flags_process(pid) & + JAIL_allow_all_net_family) + return GRANTED; + else { + rsbac_pr_debug(adf_jail, "network family not UNIX or INET and allow_all_net_family not set -> NOT_GRANTED!\n"); + return NOT_GRANTED; + } + } +} +#endif + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +enum rsbac_adf_req_ret_t +rsbac_adf_request_jail(enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + rsbac_jail_id_t jail_id; + rsbac_jail_id_t jail_id2; + rsbac_jail_id_t jail_id_object; + rsbac_jail_flags_t jail_flags; + + switch(target) { + case T_DEV: + switch(request) { + case R_SEND: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + else + return GRANTED; + case R_APPEND_OPEN: + case R_WRITE_OPEN: + if (jail_get_id_process(caller_pid)) { + jail_flags = + jail_get_flags_process(caller_pid); + if (!(jail_flags & JAIL_allow_dev_write)) + return NOT_GRANTED; + else if (jail_dev_tty(tid.dev) + && !(jail_flags & + JAIL_allow_tty_open) + ) + return NOT_GRANTED; + else + return GRANTED; + } else + return GRANTED; + case R_READ_OPEN: + if (jail_get_id_process(caller_pid)) { + jail_flags = + jail_get_flags_process(caller_pid); + if (!(jail_flags & JAIL_allow_dev_read)) + return NOT_GRANTED; + else if (jail_dev_tty(tid.dev) + && !(jail_flags & + JAIL_allow_tty_open) + ) + return NOT_GRANTED; + else + return GRANTED; + } else + return GRANTED; + case R_READ_WRITE_OPEN: + if (jail_get_id_process(caller_pid)) { + jail_flags = + jail_get_flags_process(caller_pid); + if (!(jail_flags & JAIL_allow_dev_read) + || !(jail_flags & JAIL_allow_dev_write) + ) + return NOT_GRANTED; + else if (jail_dev_tty(tid.dev) + && !(jail_flags & + JAIL_allow_tty_open) + ) + return NOT_GRANTED; + else + return GRANTED; + } else + return GRANTED; + case R_GET_STATUS_DATA: + if (jail_get_id_process(caller_pid) + && !(jail_get_flags_process(caller_pid) & + JAIL_allow_dev_get_status) + ) + return NOT_GRANTED; + else + return GRANTED; + case R_MODIFY_SYSTEM_DATA: + if (jail_get_id_process(caller_pid) + && !(jail_get_flags_process(caller_pid) & + JAIL_allow_dev_mod_system) + ) + return NOT_GRANTED; + else + return GRANTED; + case R_READ: + if (jail_get_id_process(caller_pid) + && !(jail_get_flags_process(caller_pid) & + JAIL_allow_dev_read) + ) + return NOT_GRANTED; + else + return GRANTED; + case R_WRITE: + if (jail_get_id_process(caller_pid) + && !(jail_get_flags_process(caller_pid) & + JAIL_allow_dev_write) + ) + return NOT_GRANTED; + else + return GRANTED; + default: + return DO_NOT_CARE; + } + case T_DIR: + switch(request) { + case R_CREATE: + if (!jail_get_id_process(caller_pid)) + return GRANTED; + /* no mknod for devices or suid/sgid */ + if ((attr == A_create_data) + && ( S_ISCHR(attr_val.create_data.mode) + || S_ISBLK(attr_val.create_data.mode) + || ((attr_val.create_data.mode & (S_ISUID | S_ISGID)) + && !(jail_get_flags_process(caller_pid) & JAIL_allow_suid_files) + ) + ) + ) + return NOT_GRANTED; + else if ((attr == A_mode) + && ( S_ISCHR(attr_val.mode) + || S_ISBLK(attr_val.mode) + || ((attr_val.mode & (S_ISUID | S_ISGID)) + && !(jail_get_flags_process(caller_pid) & JAIL_allow_suid_files) + ) + ) + ) + return NOT_GRANTED; + else + return GRANTED; + case R_MODIFY_PERMISSIONS_DATA: + if (jail_get_id_process(caller_pid) + && (attr == A_mode) + && (attr_val.mode & (S_ISUID | S_ISGID)) + && !(jail_get_flags_process(caller_pid) & JAIL_allow_suid_files) + ) + return NOT_GRANTED; + else + return GRANTED; + default: + return DO_NOT_CARE; + } + case T_FILE: + switch(request) { + case R_ADD_TO_KERNEL: + case R_REMOVE_FROM_KERNEL: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + else + return GRANTED; + case R_MOUNT: + case R_UMOUNT: + if (!jail_get_id_process(caller_pid) + || (jail_get_flags_process(caller_pid) & JAIL_allow_mount) + ) + return GRANTED; + else + return NOT_GRANTED; + case R_MODIFY_PERMISSIONS_DATA: + if (jail_get_id_process(caller_pid) + && (attr == A_mode) + && (attr_val.mode & (S_ISUID | S_ISGID)) + && !(jail_get_flags_process(caller_pid) & JAIL_allow_suid_files) + ) + return NOT_GRANTED; + else + return GRANTED; + default: + return DO_NOT_CARE; + } + case T_PROCESS: + switch(request) { + case R_GET_STATUS_DATA: + case R_MODIFY_SYSTEM_DATA: + case R_TRACE: + jail_id = jail_get_id_process(caller_pid); + if (!jail_id + || (jail_id == jail_get_id(target, tid)) + || ( (jail_get_flags_process(tid.process) & JAIL_allow_process_by_parent) + && (jail_get_parent_process(tid.process) == jail_id) + ) + ) + return GRANTED; + else + return NOT_GRANTED; + case R_SEND_SIGNAL: + jail_id = jail_get_id_process(caller_pid); + if (!jail_id) + return GRANTED; + jail_id2 = jail_get_id(target, tid); + if (jail_id == jail_id2) + return GRANTED; + if (!jail_id2 && (attr == A_signal) && (attr_val.signal == SIGCHLD)) + return DO_NOT_CARE; + if ( (jail_get_flags_process(tid.process) & JAIL_allow_process_by_parent) + && (jail_get_parent_process(tid.process) == jail_id) + ) + return GRANTED; + return NOT_GRANTED; + case R_MODIFY_ATTRIBUTE: + switch (attr) { + case A_jail_id: + case A_jail_ip: + case A_jail_flags: + case A_jail_max_caps: + case A_jail_parent: + case A_jail_scd_get: + case A_jail_scd_modify: + /* All attributes (remove target!) */ + case A_none: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + + /* Security Officer? */ + return jail_check_sysrole(owner, + SR_security_officer); + default: + return DO_NOT_CARE; + } + case R_READ_ATTRIBUTE: + switch (attr) { + case A_jail_id: + case A_jail_ip: + case A_jail_flags: + case A_jail_max_caps: + case A_jail_parent: + case A_jail_scd_get: + case A_jail_scd_modify: + /* All attributes (remove target!) */ + case A_none: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + + /* Security Officer? */ + if (jail_check_sysrole(owner, SR_administrator) == + NOT_GRANTED) + return jail_check_sysrole(owner, + SR_security_officer); + else + return GRANTED; + default: + return (DO_NOT_CARE); + } + default: + return DO_NOT_CARE; + } + case T_UNIXSOCK: + switch(request) { + case R_SEND: + case R_CONNECT: + case R_LISTEN: + case R_ACCEPT: + case R_RECEIVE: +#ifdef CONFIG_RSBAC_RW + case R_READ: + case R_WRITE: +#endif + case R_BIND: + jail_id = jail_get_id_process(caller_pid); + if (!jail_id) + return GRANTED; + if (attr == A_process) { + union rsbac_target_id_t i_tid; + rsbac_jail_id_t jail_id_parent; + + i_tid.process = attr_val.process; + jail_id_parent = jail_get_parent_process(caller_pid); + if((jail_id != (jail_id_object = jail_get_id(T_PROCESS, i_tid))) + && !((jail_flags = jail_get_flags_process(caller_pid)) & JAIL_allow_external_ipc) + && (!(jail_flags & JAIL_allow_parent_ipc) + || (jail_id_object != jail_id_parent) + ) + && (!(jail_flags & JAIL_allow_ipc_to_syslog) + || (jail_id_object != rsbac_jail_syslog_jail_id) + ) + && (!(jail_get_flags_process(attr_val.process) & JAIL_allow_parent_ipc) + || (jail_get_parent_process(attr_val.process) != jail_id) + ) + ) { + if (rsbac_log_levels[request][target] != LL_none) { + rsbac_pr_debug(adf_jail, + "process jail %u does not match partner process jail %u, parent jail is %u -> NOT_GRANTED!\n", + jail_id, jail_id_object, jail_id_parent); + } + return NOT_GRANTED; + } + } else { + if(!(jail_get_flags_process(caller_pid) & JAIL_allow_external_ipc)) { + if (rsbac_log_levels[request][target] != LL_none) { + rsbac_pr_debug(adf_jail, + "process jail is %u, no allow_ipc and partner process unknown -> NOT_GRANTED!\n", + jail_id); + } + return NOT_GRANTED; + } + } + return GRANTED; + default: + return DO_NOT_CARE; + } +#ifdef CONFIG_RSBAC_NET_OBJ + case T_NETOBJ: + switch(request) { + case R_SEND: + case R_RECEIVE: + case R_CONNECT: + case R_LISTEN: + case R_ACCEPT: + case R_GET_PERMISSIONS_DATA: + case R_MODIFY_PERMISSIONS_DATA: + case R_GET_STATUS_DATA: + case R_READ: + case R_WRITE: + case R_BIND: + if (!jail_get_id_process(caller_pid)) + return GRANTED; + return (jail_check_ip(caller_pid, tid)); + case R_CREATE: + if (!jail_get_id_process(caller_pid)) + return GRANTED; + if (!tid.netobj.sock_p) { + rsbac_printk(KERN_WARNING "rsbac_adf_request_jail(): NULL sock_p on CREATE!\n"); + return NOT_GRANTED; + } + if (!tid.netobj.sock_p->ops) { + return DO_NOT_CARE; + } + switch (tid.netobj.sock_p->ops->family) { + case AF_UNIX: + return (GRANTED); + + case AF_INET: + switch (tid.netobj.sock_p->type) { + case SOCK_STREAM: + case SOCK_DGRAM: + case SOCK_RDM: + if (tid.netobj.sock_p->sk + && (tid.netobj.sock_p->sk-> + sk_protocol == IPPROTO_RAW) + ) { + jail_flags = + jail_get_flags_process + (caller_pid); + if (jail_flags & + JAIL_allow_inet_raw) + return (GRANTED); + else + return NOT_GRANTED; + } else + return GRANTED; + + case SOCK_RAW: + jail_flags = + jail_get_flags_process + (caller_pid); + if (jail_flags & + JAIL_allow_inet_raw) + return (GRANTED); + else + return NOT_GRANTED; + + default: + return (NOT_GRANTED); + } + + case AF_NETLINK: + jail_flags = jail_get_flags_process(caller_pid); + if (jail_flags & + (JAIL_allow_all_net_family | JAIL_allow_netlink)) + return GRANTED; + else { + if (rsbac_log_levels[request][target] != LL_none) { + rsbac_pr_debug(adf_jail, "network family is NETLINK and neither allow_netlink nor allow_all_net_family is set -> NOT_GRANTED!\n"); + } + return NOT_GRANTED; + } + default: + jail_flags = jail_get_flags_process(caller_pid); + if (jail_flags & JAIL_allow_all_net_family) + return GRANTED; + else + return NOT_GRANTED; + } + default: + return DO_NOT_CARE; + } +#endif /* NET_OBJ */ + case T_IPC: + switch(request) { + case R_ALTER: + case R_APPEND_OPEN: + case R_WRITE_OPEN: + case R_READ_OPEN: + case R_READ_WRITE_OPEN: + case R_DELETE: + case R_MODIFY_PERMISSIONS_DATA: + case R_GET_STATUS_DATA: + jail_id = jail_get_id_process(caller_pid); + if (!jail_id + || (jail_id == (jail_id_object = jail_get_id(target, tid))) + || ((jail_flags = jail_get_flags_process(caller_pid)) & + JAIL_allow_external_ipc) + || ((jail_flags & JAIL_allow_parent_ipc) + && (jail_get_parent_process(caller_pid) == jail_id_object) + ) + || ((jail_flags & JAIL_allow_ipc_to_syslog) + && (rsbac_jail_syslog_jail_id == jail_id_object) + ) + ) + return GRANTED; + else { + if (rsbac_log_levels[request][target] != LL_none) { + rsbac_pr_debug(adf_jail, + "process jail %u does not match IPC object jail %u -> NOT_GRANTED!\n", + jail_id, jail_id_object); + } + return NOT_GRANTED; + } + case R_CREATE: + return GRANTED; + case R_MODIFY_ATTRIBUTE: + switch (attr) { + case A_jail_id: + /* All attributes (remove target!) */ + case A_none: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + + /* Security Officer? */ + return jail_check_sysrole(owner, + SR_security_officer); + default: + return DO_NOT_CARE; + } + case R_READ_ATTRIBUTE: + switch (attr) { + case A_jail_id: + /* All attributes (remove target!) */ + case A_none: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + + /* Security Officer? */ + if (jail_check_sysrole(owner, SR_administrator) == + NOT_GRANTED) + return jail_check_sysrole(owner, + SR_security_officer); + else + return GRANTED; + default: + return (DO_NOT_CARE); + } + default: + jail_id = jail_get_id_process(caller_pid); + if (!jail_id) + return GRANTED; + if((jail_flags = jail_get_flags_process(caller_pid)) & + JAIL_allow_external_ipc) + return GRANTED; + jail_id_object = jail_get_id(target, tid); + if((jail_flags & JAIL_allow_parent_ipc) + && (jail_get_parent_process(caller_pid) == jail_id_object)) + return GRANTED; + if((attr == A_process) + && (jail_get_flags_process(attr_val.process) & JAIL_allow_parent_ipc) + && (jail_get_parent_process(attr_val.process) == jail_id)) + return GRANTED; + if((jail_flags & JAIL_allow_ipc_to_syslog) + && (rsbac_jail_syslog_jail_id == jail_id_object)) + return GRANTED; + if(jail_id != jail_id_object) { + if (rsbac_log_levels[request][target] != LL_none) { + rsbac_pr_debug(adf_jail, + "process jail %u does not match IPC object jail %u -> NOT_GRANTED!\n", + jail_id, jail_id_object); + } + return NOT_GRANTED; + } + if (attr == A_process) { + union rsbac_target_id_t i_tid; + rsbac_jail_id_t jail_id_parent; + + i_tid.process = attr_val.process; + jail_id_parent = jail_get_parent_process(caller_pid); + if((jail_id != (jail_id_object = jail_get_id(T_PROCESS, i_tid))) + && !(jail_flags & JAIL_allow_external_ipc) + && (!(jail_flags & JAIL_allow_parent_ipc) + || (jail_id_object != jail_id_parent) + ) + ) { + if (rsbac_log_levels[request][target] != LL_none) { + rsbac_pr_debug(adf_jail, + "process jail %u does not match partner process jail %u, parent jail is %u -> NOT_GRANTED!\n", + jail_id, jail_id_object, jail_id_parent); + } + return NOT_GRANTED; + } + } + return GRANTED; + } + case T_FIFO: + case T_SYMLINK: + switch(request) { + case R_MODIFY_PERMISSIONS_DATA: + if (jail_get_id_process(caller_pid) + && (attr == A_mode) + && (attr_val.mode & (S_ISUID | S_ISGID)) + && !(jail_get_flags_process(caller_pid) & JAIL_allow_suid_files) + ) + return NOT_GRANTED; + else + return GRANTED; + default: + return DO_NOT_CARE; + } + case T_SCD: + switch(request) { + case R_MODIFY_PERMISSIONS_DATA: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + else + return GRANTED; + case R_GET_STATUS_DATA: + if (jail_get_id_process(caller_pid)) { + if (jail_get_scd_get_process(caller_pid) & + RSBAC_SCD_VECTOR(tid.scd)) + return GRANTED; + else + return NOT_GRANTED; + } else + return GRANTED; + case R_MODIFY_SYSTEM_DATA: + if (jail_get_id_process(caller_pid)) { + if (jail_get_scd_modify_process(caller_pid) + & RSBAC_SCD_VECTOR(tid.scd)) + return (GRANTED); + else + return NOT_GRANTED; + } else + return GRANTED; + default: + return DO_NOT_CARE; + } + case T_NONE: + switch(request) { + case R_ADD_TO_KERNEL: + case R_REMOVE_FROM_KERNEL: + case R_SHUTDOWN: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + else + return GRANTED; + case R_SWITCH_LOG: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + /* test owner's fc_role */ + return jail_check_sysrole(owner, + SR_security_officer); + case R_SWITCH_MODULE: + /* we need the switch_target */ + if (attr != A_switch_target) + return NOT_GRANTED; + /* do not care for other modules */ + if ((attr_val.switch_target != SW_JAIL) +#ifdef CONFIG_RSBAC_SOFTMODE + && (attr_val.switch_target != SW_SOFTMODE) +#endif +#ifdef CONFIG_RSBAC_FREEZE + && (attr_val.switch_target != SW_FREEZE) +#endif +#ifdef CONFIG_RSBAC_MPROTECT + && (attr_val.switch_target != SW_MPROTECT) +#endif + ) + return (DO_NOT_CARE); + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + /* test owner's fc_role */ + return jail_check_sysrole(owner, + SR_security_officer); + + default: + return DO_NOT_CARE; + } + case T_NETDEV: + switch(request) { +#ifdef CONFIG_RSBAC_JAIL_NET_DEV_PROT + case R_MODIFY_SYSTEM_DATA: + if (jail_get_id_process(caller_pid)) { + if(jail_get_flags_process(caller_pid) & JAIL_allow_netdev_mod_system) + return GRANTED; + else + return NOT_GRANTED; + } else + return GRANTED; + case R_BIND: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + else + return GRANTED; +#endif + default: + return DO_NOT_CARE; + } + +#if defined(CONFIG_RSBAC_NET_OBJ) + case T_NETTEMP: + switch(request) { + case R_CREATE: + case R_DELETE: + case R_WRITE: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + return jail_check_sysrole(owner, SR_security_officer); + case R_READ: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + if (jail_check_sysrole(owner, SR_security_officer) + == GRANTED) + return GRANTED; + return jail_check_sysrole(owner, SR_administrator); + default: + return DO_NOT_CARE; + } +#endif + + case T_USER: + switch(request) { + case R_MODIFY_ATTRIBUTE: + switch (attr) { + case A_system_role: + case A_jail_role: + /* All attributes (remove target!) */ + case A_none: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + + /* Security Officer? */ + return jail_check_sysrole(owner, + SR_security_officer); + default: + return DO_NOT_CARE; + } + case R_READ_ATTRIBUTE: + switch (attr) { + case A_system_role: + case A_jail_role: + /* All attributes (remove target!) */ + case A_none: + if (jail_get_id_process(caller_pid)) + return NOT_GRANTED; + + /* Security Officer? */ + if (jail_check_sysrole(owner, SR_administrator) == + NOT_GRANTED) + return jail_check_sysrole(owner, + SR_security_officer); + else + return GRANTED; + default: + return (DO_NOT_CARE); + } + default: + return DO_NOT_CARE; + } + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } +} + +/*****************************************************************************/ +/* If the request returned granted and the operation is performed, */ +/* the following function can be called by the AEF to get all aci set */ +/* correctly. For write accesses that are performed fully within the kernel, */ +/* this is usually not done to prevent extra calls, including R_CLOSE for */ +/* cleaning up. */ +/* The second instance of target specification is the new target, if one has */ +/* been created, otherwise its values are ignored. */ +/* On success, 0 is returned, and an error from rsbac/error.h otherwise. */ + +int rsbac_adf_set_attr_jail(enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ +#ifdef CONFIG_RSBAC_JAIL_NET_ADJUST + int err; +#endif + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_attribute_value_t i_attr_val2; + + switch (request) { + case R_CHANGE_OWNER: + switch (target) { + case T_PROCESS: + /* Adjust Linux caps */ + i_tid.process = caller_pid; +#ifdef CONFIG_RSBAC_SOFTMODE + if (!rsbac_softmode) +#endif + { + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_max_caps, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_max_caps); + } else { + struct cred *override_cred; + + override_cred = prepare_creds(); + if (!override_cred) + return -ENOMEM; + if ( ((override_cred->cap_permitted.cap[0] & i_attr_val1.jail_max_caps.cap[0]) != override_cred->cap_permitted.cap[0]) + || ((override_cred->cap_effective.cap[0] & i_attr_val1.jail_max_caps.cap[0]) != override_cred->cap_effective.cap[0]) + || ((override_cred->cap_inheritable.cap[0] & i_attr_val1.jail_max_caps.cap[0]) != override_cred->cap_inheritable.cap[0]) + || ((override_cred->cap_permitted.cap[1] & i_attr_val1.jail_max_caps.cap[1]) != override_cred->cap_permitted.cap[1]) + || ((override_cred->cap_effective.cap[1] & i_attr_val1.jail_max_caps.cap[1]) != override_cred->cap_effective.cap[1]) + || ((override_cred->cap_inheritable.cap[1] & i_attr_val1.jail_max_caps.cap[1]) != override_cred->cap_inheritable.cap[1]) + ) { + override_cred->cap_permitted.cap[0] &= i_attr_val1.jail_max_caps.cap[0]; + override_cred->cap_effective.cap[0] &= i_attr_val1.jail_max_caps.cap[0]; + override_cred->cap_inheritable.cap[0] &= i_attr_val1.jail_max_caps.cap[0]; + override_cred->cap_permitted.cap[1] &= i_attr_val1.jail_max_caps.cap[1]; + override_cred->cap_effective.cap[1] &= i_attr_val1.jail_max_caps.cap[1]; + override_cred->cap_inheritable.cap[1] &= i_attr_val1.jail_max_caps.cap[1]; + commit_creds(override_cred); + } else { + abort_creds(override_cred); + } + } + } + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + + case R_CLONE: + if (target == T_PROCESS) { + union rsbac_attribute_value_t i_attr_val3; + union rsbac_attribute_value_t i_attr_val4; + union rsbac_attribute_value_t i_attr_val5; + union rsbac_attribute_value_t i_attr_val6; + + /* Get jail_id from first process */ + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + tid, + A_jail_id, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_id); + return (-RSBAC_EREADFAILED); + } + /* Do not copy anything, if not jailed - defaults are fine */ + if(!i_attr_val1.jail_id) + return 0; + /* Get jail_ip from first process */ + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + tid, + A_jail_ip, + &i_attr_val2, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_ip); + return (-RSBAC_EREADFAILED); + } + /* Get jail_flags from first process */ + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + tid, + A_jail_flags, + &i_attr_val3, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_flags); + return (-RSBAC_EREADFAILED); + } + /* Get jail_max_caps from first process */ + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + tid, + A_jail_max_caps, + &i_attr_val4, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_max_caps); + return (-RSBAC_EREADFAILED); + } + /* Get jail_scd_get from first process */ + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + tid, + A_jail_scd_get, + &i_attr_val5, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_scd_get); + return (-RSBAC_EREADFAILED); + } + /* Get jail_scd_modify from first process */ + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + tid, + A_jail_scd_modify, + &i_attr_val6, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_scd_modify); + return (-RSBAC_EREADFAILED); + } + /* Set jail_id for new process */ + if (i_attr_val1.jail_id && rsbac_set_attr(SW_JAIL, + T_PROCESS, + new_tid, + A_jail_id, i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_jail()", + A_jail_id); + return (-RSBAC_EWRITEFAILED); + } + /* Set jail_ip for new process */ + if (i_attr_val2.jail_ip && rsbac_set_attr(SW_JAIL, + T_PROCESS, + new_tid, + A_jail_ip, i_attr_val2)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_jail()", + A_jail_ip); + return (-RSBAC_EWRITEFAILED); + } + /* Set jail_flags for new process */ + if (i_attr_val3.jail_flags && rsbac_set_attr(SW_JAIL, + T_PROCESS, + new_tid, + A_jail_flags, i_attr_val3)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_jail()", + A_jail_flags); + return (-RSBAC_EWRITEFAILED); + } + /* Set jail_max_caps for new process */ + if (rsbac_set_attr(SW_JAIL, + T_PROCESS, + new_tid, + A_jail_max_caps, i_attr_val4)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_jail()", + A_jail_max_caps); + return (-RSBAC_EWRITEFAILED); + } + /* Set jail_scd_get for new process */ + if (i_attr_val5.jail_scd_get && rsbac_set_attr(SW_JAIL, + T_PROCESS, + new_tid, + A_jail_scd_get, i_attr_val5)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_jail()", + A_jail_scd_get); + return (-RSBAC_EWRITEFAILED); + } + /* Set jail_scd_modify for new process */ + if (i_attr_val6.jail_scd_modify && rsbac_set_attr(SW_JAIL, + T_PROCESS, + new_tid, + A_jail_scd_modify, + i_attr_val6)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_jail()", + A_jail_scd_modify); + return (-RSBAC_EWRITEFAILED); + } + return 0; + } else + return 0; + + case R_EXECUTE: + switch (target) { + case T_FILE: + /* Adjust Linux caps */ + i_tid.process = caller_pid; +#ifdef CONFIG_RSBAC_SOFTMODE + if (!rsbac_softmode) +#endif + { + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_max_caps, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_max_caps); + } else { + struct cred *override_cred; + + override_cred = prepare_creds(); + if (!override_cred) + return -ENOMEM; + if ( ((override_cred->cap_permitted.cap[0] & i_attr_val1.jail_max_caps.cap[0]) != override_cred->cap_permitted.cap[0]) + || ((override_cred->cap_effective.cap[0] & i_attr_val1.jail_max_caps.cap[0]) != override_cred->cap_effective.cap[0]) + || ((override_cred->cap_inheritable.cap[0] & i_attr_val1.jail_max_caps.cap[0]) != override_cred->cap_inheritable.cap[0]) + || ((override_cred->cap_permitted.cap[1] & i_attr_val1.jail_max_caps.cap[1]) != override_cred->cap_permitted.cap[1]) + || ((override_cred->cap_effective.cap[1] & i_attr_val1.jail_max_caps.cap[1]) != override_cred->cap_effective.cap[1]) + || ((override_cred->cap_inheritable.cap[1] & i_attr_val1.jail_max_caps.cap[1]) != override_cred->cap_inheritable.cap[1]) + ) { + override_cred->cap_permitted.cap[0] &= i_attr_val1.jail_max_caps.cap[0]; + override_cred->cap_effective.cap[0] &= i_attr_val1.jail_max_caps.cap[0]; + override_cred->cap_inheritable.cap[0] &= i_attr_val1.jail_max_caps.cap[0]; + override_cred->cap_permitted.cap[1] &= i_attr_val1.jail_max_caps.cap[1]; + override_cred->cap_effective.cap[1] &= i_attr_val1.jail_max_caps.cap[1]; + override_cred->cap_inheritable.cap[1] &= i_attr_val1.jail_max_caps.cap[1]; + commit_creds(override_cred); + } else { + abort_creds(override_cred); + } + } + } + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + + case R_CREATE: + switch (target) { + case T_IPC: + /* Get jail_id from process */ + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_id, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_id); + return -RSBAC_EREADFAILED; + } + if (i_attr_val1.jail_id) { + /* Set jail_id for new IPC */ + if (rsbac_set_attr(SW_JAIL, + T_IPC, + tid, A_jail_id, i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_jail()", + A_jail_id); + return -RSBAC_EWRITEFAILED; + } + } + return 0; + +#ifdef CONFIG_RSBAC_JAIL_NET_ADJUST + case T_NETOBJ: + if (!tid.netobj.sock_p) { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_jail(): NULL sock_p!\n"); + return 0; + } + if (!tid.netobj.sock_p->ops) { + return 0; + } + switch (tid.netobj.sock_p->ops->family) { + case AF_INET: + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_ip, + &i_attr_val1, FALSE))) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_ip); + return -RSBAC_EREADFAILED; + } + if (i_attr_val1.jail_ip == INADDR_ANY) + return 0; + if ((err = rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_flags, + &i_attr_val2, FALSE))) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_flags); + return -RSBAC_EREADFAILED; + } + if (i_attr_val2. + jail_flags & JAIL_auto_adjust_inet_any) { + inet_sk(tid.netobj.sock_p->sk)->inet_rcv_saddr = + i_attr_val1.jail_ip; + inet_sk(tid.netobj.sock_p->sk)->inet_saddr = + i_attr_val1.jail_ip; + } + return 0; + + default: + break; + } +#endif + + default: + return 0; + } + + case R_BIND: + switch (target) { + case T_IPC: + /* Get jail_id from process */ + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_id, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_id); + return -RSBAC_EREADFAILED; + } + if (i_attr_val1.jail_id) { + /* Set jail_id for new IPC */ + if (rsbac_set_attr(SW_JAIL, + T_IPC, + tid, A_jail_id, i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_jail()", + A_jail_id); + return -RSBAC_EWRITEFAILED; + } + } + return 0; + +#ifdef CONFIG_RSBAC_JAIL_NET_ADJUST + case T_NETOBJ: + if (!tid.netobj.sock_p) { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_jail(): NULL sock_p!\n"); + return 0; + } + if (!tid.netobj.sock_p->ops) { + return 0; + } + switch (tid.netobj.sock_p->ops->family) { + case AF_INET: + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_ip, + &i_attr_val1, FALSE))) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_ip); + return -RSBAC_EREADFAILED; + } + if (i_attr_val1.jail_ip == INADDR_ANY) + return 0; + if ((err = rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_flags, + &i_attr_val2, FALSE))) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_flags); + return -RSBAC_EREADFAILED; + } + if (i_attr_val2. + jail_flags & JAIL_auto_adjust_inet_any) { + inet_sk(tid.netobj.sock_p->sk)->inet_rcv_saddr = + i_attr_val1.jail_ip; + inet_sk(tid.netobj.sock_p->sk)->inet_saddr = + i_attr_val1.jail_ip; + } + return 0; + + default: + break; + } +#endif + default: + return 0; + } + + case R_CONNECT: + switch (target) { + case T_IPC: + if (new_target != T_IPC) + return 0; + /* Get jail_id from old IPC */ + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_JAIL, + T_IPC, + tid, + A_jail_id, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_jail()", + A_jail_id); + return -RSBAC_EREADFAILED; + } + if (i_attr_val1.jail_id) { + /* Set jail_id for new IPC */ + if (rsbac_set_attr(SW_JAIL, + T_IPC, + new_tid, A_jail_id, i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_jail()", + A_jail_id); + return -RSBAC_EWRITEFAILED; + } + } + return 0; + + default: + return 0; + } + + default: + return 0; + } + + return 0; +} diff --git a/rsbac/adf/jail/jail_syscalls.c b/rsbac/adf/jail/jail_syscalls.c new file mode 100644 index 000000000000..8994aa74b532 --- /dev/null +++ b/rsbac/adf/jail/jail_syscalls.c @@ -0,0 +1,301 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - JAIL module */ +/* File: rsbac/adf/jail/syscalls.c */ +/* */ +/* Author and (c) 1999-2016: Amon Ott */ +/* */ +/* Last modified: 25/Oct/2016 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static rsbac_jail_id_t next_id = 1; + +/* Create a jail for current process */ +/* Note: It is allowed to create jails within jails, but with restrictions */ +int rsbac_jail_sys_jail(rsbac_version_t version, + char __user * path, + rsbac_jail_ip_t ip, + rsbac_jail_flags_t flags, + rsbac_cap_vector_t max_caps, + rsbac_jail_scd_vector_t scd_get, + rsbac_jail_scd_vector_t scd_modify) +{ + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + int err = 0; + rsbac_jail_id_t parent = 0; +#ifdef CONFIG_RSBAC_NET + int chk_addr_ret; +#endif + + if(version != RSBAC_JAIL_VERSION) + return -RSBAC_EINVALIDVERSION; + +#ifdef CONFIG_RSBAC_NET + chk_addr_ret = inet_addr_type(&init_net, ip); + if (ip != INADDR_ANY && + chk_addr_ret != RTN_LOCAL && + chk_addr_ret != RTN_MULTICAST && + chk_addr_ret != RTN_BROADCAST) + return -EADDRNOTAVAIL; +#endif + + /* Get jail_id for this process */ + i_tid.process = task_pid(current); + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_id, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_jail_sys_jail()", A_jail_id); + return(-RSBAC_EREADFAILED); + } + + if (i_attr_val1.jail_id) + { /* this process is already in a jail -> limit ip and flags */ + parent = i_attr_val1.jail_id; + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_flags, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_jail_sys_jail()", A_jail_flags); + return(-RSBAC_EREADFAILED); + } + + flags &= i_attr_val1.jail_flags | JAIL_allow_parent_ipc | JAIL_allow_process_by_parent; + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_scd_get, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_jail_sys_jail()", A_jail_scd_get); + return(-RSBAC_EREADFAILED); + } + + scd_get &= i_attr_val1.jail_scd_get; + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_scd_modify, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_jail_sys_jail()", A_jail_scd_modify); + return(-RSBAC_EREADFAILED); + } + + scd_modify &= i_attr_val1.jail_scd_modify; + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_ip, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_jail_sys_jail()", A_jail_ip); + return(-RSBAC_EREADFAILED); + } + + if(i_attr_val1.jail_ip) + ip = i_attr_val1.jail_ip; + + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_max_caps, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_jail_sys_jail()", A_jail_max_caps); + return(-RSBAC_EREADFAILED); + } + + max_caps.cap[0] &= i_attr_val1.jail_max_caps.cap[0]; + max_caps.cap[1] &= i_attr_val1.jail_max_caps.cap[1]; + } + + /* check syslog id */ + if(flags & JAIL_this_is_syslog) { + if( rsbac_jail_syslog_jail_id + && rsbac_jail_exists(rsbac_jail_syslog_jail_id) + ) + return -RSBAC_EEXISTS; + } + + if(path) + { + mm_segment_t oldfs; + struct file * file; + struct files_struct *files = current->files; + struct fdtable *fdt; + int fd; + + err = sys_chroot(path); + if(err) + return err; + /* Set current user space to kernel space, because sys_chdir() takes name */ + /* from user space */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = sys_chdir("/"); + /* Set current user space back to user space */ + set_fs(oldfs); + +restart: + rcu_read_lock(); + fdt = files_fdtable(files); + fdt = rcu_dereference((files)->fdt); + + for(fd=0; fd < fdt->max_fds; fd++) + { + file = fcheck(fd); + if( file + && file->f_path.dentry + && file->f_path.dentry->d_inode + && S_ISDIR(file->f_path.dentry->d_inode->i_mode) + ) + { + char * filename; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + filename = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + 4); + if(filename) + rsbac_get_full_path(file->f_path.dentry, filename, CONFIG_RSBAC_MAX_PATH_LEN); +#else + filename = rsbac_kmalloc(RSBAC_MAXNAMELEN + 4); + if(filename) + rsbac_get_full_path(file->f_path.dentry, filename, RSBAC_MAXNAMELEN); +#endif + + rsbac_printk(KERN_INFO + "rsbac_jail_sys_jail(): avoid possible chroot breakout by closing open dir fd %u, inode %lu, device %02u:%02u, path %s\n", + fd, + file->f_path.dentry->d_inode->i_ino, + MAJOR(file->f_path.dentry->d_sb->s_dev), + MINOR(file->f_path.dentry->d_sb->s_dev), + filename); + if(filename) + rsbac_kfree(filename); + + rcu_read_unlock(); + sys_close(fd); + goto restart; + } + } + rcu_read_unlock(); + } + + /* Set jail_id for this process - number might wrap, so better check */ + i_attr_val1.jail_id = next_id++; + while (!i_attr_val1.jail_id || rsbac_jail_exists(i_attr_val1.jail_id)) + i_attr_val1.jail_id = next_id++; + + if (rsbac_set_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_id, + i_attr_val1)) + { + rsbac_ds_set_error("rsbac_jail_sys_jail()", A_jail_id); + return(-RSBAC_EWRITEFAILED); + } + + if (flags & JAIL_this_is_syslog) { + rsbac_jail_syslog_jail_id = i_attr_val1.jail_id; + } + + /* Set jail_parent for this process */ + i_attr_val1.jail_parent = parent; + if (rsbac_set_attr(SW_JAIL, T_PROCESS, i_tid, A_jail_parent, i_attr_val1)) { + rsbac_ds_set_error("rsbac_jail_sys_jail()", A_jail_parent); + return (-RSBAC_EWRITEFAILED); + } + + /* Set jail_ip for this process */ + i_attr_val1.jail_ip = ip; + if (rsbac_set_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_ip, + i_attr_val1)) + { + rsbac_ds_set_error("rsbac_jail_sys_jail()", A_jail_ip); + return(-RSBAC_EWRITEFAILED); + } + + /* Set jail_flags for this process */ + i_attr_val1.jail_flags = flags; + if (rsbac_set_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_flags, + i_attr_val1)) + { + rsbac_ds_set_error("rsbac_jail_sys_jail()", A_jail_flags); + return(-RSBAC_EWRITEFAILED); + } + + /* Set jail_max_caps for this process */ + i_attr_val1.jail_max_caps.cap[0] = max_caps.cap[0]; + i_attr_val1.jail_max_caps.cap[1] = max_caps.cap[1]; + if (rsbac_set_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_max_caps, + i_attr_val1)) + { + rsbac_ds_set_error("rsbac_jail_sys_jail()", A_jail_max_caps); + return(-RSBAC_EWRITEFAILED); + } + + /* Set jail_scd_get for this process */ + i_attr_val1.jail_scd_get = scd_get; + if (rsbac_set_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_scd_get, + i_attr_val1)) + { + rsbac_ds_set_error("rsbac_jail_sys_jail()", A_jail_scd_get); + return(-RSBAC_EWRITEFAILED); + } + + /* Set jail_scd_modify for this process */ + i_attr_val1.jail_scd_modify = scd_modify; + if (rsbac_set_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_scd_modify, + i_attr_val1)) + { + rsbac_ds_set_error("rsbac_jail_sys_jail()", A_jail_scd_modify); + return(-RSBAC_EWRITEFAILED); + } + return err; +} diff --git a/rsbac/adf/mac/Makefile b/rsbac/adf/mac/Makefile new file mode 100644 index 000000000000..50c43570667b --- /dev/null +++ b/rsbac/adf/mac/Makefile @@ -0,0 +1,9 @@ +# +# File: rsbac/adf/mac/Makefile +# +# Makefile for the Linux rsbac mac decision module. +# +# Author and (c) 1999-2013 Amon Ott +# + +obj-y := mac_syscalls.o mac_main.o diff --git a/rsbac/adf/mac/mac_main.c b/rsbac/adf/mac/mac_main.c new file mode 100644 index 000000000000..d15fd19d7f3a --- /dev/null +++ b/rsbac/adf/mac/mac_main.c @@ -0,0 +1,4892 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - Mandatory Access Control */ +/* File: rsbac/adf/mac/main.c */ +/* */ +/* Author and (c) 1999-2017: Amon Ott */ +/* MAC_LIGHT Modifications (c) 2000 Stanislav Ievlev */ +/* and (c) 2001 Amon Ott */ +/* */ +/* Last modified: 21/Mar/2017 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +static enum rsbac_adf_req_ret_t +mac_check_role(rsbac_uid_t owner, + enum rsbac_system_role_t role) +{ + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + i_tid.user = owner; + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, A_mac_role, &i_attr_val1, FALSE)) { + rsbac_ds_get_error("mac_check_role", A_mac_role); + return NOT_GRANTED; + } + /* if correct role, then grant */ + if (i_attr_val1.system_role == role) + return GRANTED; + else { + rsbac_pr_debug(adf_mac, "pid %u(%s): wrong mac_role %u -> NOT_GRANTED!\n", + current->pid, current->comm, + i_attr_val1.system_role); + return NOT_GRANTED; + } +} + +/* auto_write() */ +/* This function builds a decision for write-only access based on */ +/* ss-property and *-property. The Subject is given by process-id pid, */ +/* its attributes are taken from the data structures module. */ +/* For the object, only security_level is given to become independent */ +/* from different object/target types. */ +/* If attribute mac_auto is set, the current_security_level is changed */ +/* within min_write and max_read boundaries to allow for more accesses.*/ +/* If set_level is TRUE, the current_security_level and read/write */ +/* boundaries are set to appropiate values, otherwise they are only */ +/* checked. This provides only one function for decision and attribute */ +/* setting. */ +/* Trusted processes (attr. mac_trusted set) are always granted write */ +/* access. */ + +static enum rsbac_adf_req_ret_t +auto_write_attr(rsbac_pid_t pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t t_level_attr, + enum rsbac_attribute_t t_cat_attr, + rsbac_boolean_t set_level) +{ + rsbac_security_level_t curr_level; + rsbac_mac_category_vector_t curr_categories; + rsbac_security_level_t target_sec_level; + rsbac_mac_category_vector_t target_categories; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t attr_val1; + union rsbac_attribute_value_t attr_val2; + rsbac_mac_process_flags_t flags; + rsbac_boolean_t mac_auto_used_level = FALSE; + rsbac_boolean_t mac_auto_used_cat = FALSE; + rsbac_boolean_t raise_object_level = FALSE; + rsbac_boolean_t raise_object_cat = FALSE; + + /* first check for mac_override, which allows everything */ + i_tid.process = pid; + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_mac_process_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", A_mac_process_flags); + return NOT_GRANTED; + } + flags = attr_val1.mac_process_flags; + if (flags & MAC_override) + return GRANTED; + + /* Get current security level */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_current_sec_level, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", A_current_sec_level); + return NOT_GRANTED; + } + curr_level = attr_val1.security_level; + /* Get current categories */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_mac_curr_categories, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", A_mac_curr_categories); + return NOT_GRANTED; + } + curr_categories = attr_val1.mac_categories; + /* Get target security level */ + if (rsbac_get_attr(SW_MAC, target, tid, t_level_attr, &attr_val1, TRUE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", t_level_attr); + return NOT_GRANTED; + } + target_sec_level = attr_val1.security_level; + /* Get target categories */ + if (rsbac_get_attr(SW_MAC, target, tid, t_cat_attr, &attr_val1, TRUE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", t_cat_attr); + return NOT_GRANTED; + } + target_categories = attr_val1.mac_categories; + + if (target_sec_level > curr_level) { + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_security_level, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", A_security_level); + return NOT_GRANTED; + } + if (attr_val1.security_level < target_sec_level) { + rsbac_pr_debug(adf_mac, "pid %u(%s): security_level %u under target_sec_level %u, no override -> NOT_GRANTED!\n", + current->pid, current->comm, + attr_val1.security_level, + target_sec_level); + return NOT_GRANTED; + } + /* curr_level < target_level <= max_level -> need mac_auto, + * write_up, trusted (at process) + * or shared (at object) */ + if (flags & MAC_auto) + mac_auto_used_level = TRUE; + else { + if (!(flags & MAC_write_up) + && !(flags & MAC_trusted) + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_write", + A_mac_file_flags); + return NOT_GRANTED; + } + if ((attr_val1. + mac_file_flags & MAC_write_up) + || (attr_val1. + mac_file_flags & + MAC_trusted) + ) { + break; + } + /* fall through */ + + default: + rsbac_pr_debug(adf_mac, "pid %u(%s): current security_level %u under target_sec_level %u, no auto, write_up, trusted -> NOT_GRANTED!\n", + current->pid, + current->comm, + curr_level, + target_sec_level); + return NOT_GRANTED; + } + } + } + } else if (target_sec_level < curr_level) { + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_min_security_level, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", A_min_security_level); + return NOT_GRANTED; + } + if (attr_val1.security_level > target_sec_level) { + rsbac_pr_debug(adf_mac, "pid %u(%s): min_security_level %u over target_sec_level %u, no override -> NOT_GRANTED!\n", + current->pid, + current->comm, attr_val1.security_level, + target_sec_level); + return NOT_GRANTED; + } + /* min_level <= target_level < curr_level -> need mac_auto, + * write_down or trusted */ + if (flags & MAC_auto) { + /* check max_read boundary */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_max_read_open, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", + A_max_read_open); + return NOT_GRANTED; + } + if (attr_val1.security_level > target_sec_level) { + if (!(flags & MAC_write_down) + && !(flags & MAC_trusted) + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_write", + A_mac_file_flags); + return (NOT_GRANTED); + } + if ((attr_val1. + mac_file_flags & + MAC_write_down) + || (attr_val1. + mac_file_flags & + MAC_trusted) + ) { + if (attr_val1. + mac_file_flags + & MAC_auto) { + raise_object_level + = TRUE; + } + break; + } + /* fall through */ + + default: + rsbac_pr_debug(adf_mac, "pid %u(%s): max_read_open %u over target_sec_level %u, no write_down or trusted -> NOT_GRANTED!\n", + current->pid, + current->comm, + attr_val1. + security_level, + target_sec_level); + return NOT_GRANTED; + } + } + } else + mac_auto_used_level = TRUE; + } else { + if (!(flags & MAC_write_down) + && !(flags & MAC_trusted) + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_write", + A_mac_file_flags); + return NOT_GRANTED; + } + if ((attr_val1. + mac_file_flags & + MAC_write_down) + || (attr_val1. + mac_file_flags & + MAC_trusted) + ) { + if (attr_val1. + mac_file_flags & + MAC_auto) { + raise_object_level + = TRUE; + } + break; + } + /* fall through */ + + default: + rsbac_pr_debug(adf_mac, "pid %u(%s): current security_level %u over target_sec_level %u, no auto, write_down or trusted -> NOT_GRANTED!\n", + current->pid, + current->comm, + curr_level, + target_sec_level); + return NOT_GRANTED; + } + } + } + } + + if ((target_categories & curr_categories) != target_categories) { + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_mac_categories, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", A_mac_categories); + return NOT_GRANTED; + } + if ((target_categories & attr_val1.mac_categories) != + target_categories) { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac(tmp, + attr_val1. + mac_categories); + u64tostrmac(tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): max_categories %s under target categories %s, no override -> NOT_GRANTED!\n", + current->pid, + current->comm, + tmp, tmp2); + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp); + } + } +#endif + return NOT_GRANTED; + } + /* curr_categories < target_categories <= max_categories -> need mac_auto, + * write_up or trusted */ + if (flags & MAC_auto) + mac_auto_used_cat = TRUE; + else { + if (!(flags & MAC_write_up) + && !(flags & MAC_trusted) + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_write", + A_mac_file_flags); + return NOT_GRANTED; + } + if ((attr_val1. + mac_file_flags & MAC_write_up) + || (attr_val1. + mac_file_flags & + MAC_trusted) + ) + break; + /* fall through */ + + default: +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac + (tmp, + curr_categories); + u64tostrmac + (tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): curr_categories %s under target categories %s, no auto, write_up or trusted -> NOT_GRANTED!\n", + current-> + pid, + current-> + comm, + tmp, + tmp2); + rsbac_kfree + (tmp2); + } + rsbac_kfree(tmp); + } + } +#endif + return NOT_GRANTED; + } + } + } + } else + if ((target_categories & curr_categories) != curr_categories) { + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_mac_min_categories, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", A_mac_min_categories); + return NOT_GRANTED; + } + if ((target_categories & attr_val1.mac_categories) != + attr_val1.mac_categories) { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac(tmp, + attr_val1. + mac_categories); + u64tostrmac(tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): min_categories %s over target categories %s, no override -> NOT_GRANTED!\n", + current->pid, + current->comm, + tmp, tmp2); + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp); + } + } +#endif + return NOT_GRANTED; + } + /* min_level <= target_level < curr_level -> need mac_auto, + * write_down or trusted */ + if (flags & MAC_auto) { + /* check max_read boundary */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_max_read_categories, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", + A_max_read_categories); + return NOT_GRANTED; + } + if ((target_categories & attr_val1. + mac_categories) != attr_val1.mac_categories) { + if (!(flags & MAC_write_down) + && !(flags & MAC_trusted) + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_write", + A_mac_file_flags); + return + (NOT_GRANTED); + } + if ((attr_val1. + mac_file_flags & + MAC_write_down) + || (attr_val1. + mac_file_flags & + MAC_trusted) + ) { + if (attr_val1. + mac_file_flags + & MAC_auto) { + raise_object_cat + = TRUE; + } + break; + } + /* fall through */ + + default: +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 + = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac + (tmp, + attr_val1. + mac_categories); + u64tostrmac + (tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): max_read_categories %s over target categories %s, no write_down or trusted -> NOT_GRANTED!\n", + current-> + pid, + current-> + comm, + tmp, + tmp2); + rsbac_kfree + (tmp2); + } + rsbac_kfree + (tmp); + } + } +#endif + return NOT_GRANTED; + } + } + } else + mac_auto_used_cat = TRUE; + } else { + if (!(flags & MAC_write_down) + && !(flags & MAC_trusted) + ) { + /* Try mac_file_flags on the target, if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_write", + A_mac_file_flags); + return NOT_GRANTED; + } + if ((attr_val1. + mac_file_flags & + MAC_write_down) + || (attr_val1. + mac_file_flags & + MAC_trusted) + ) { + if (attr_val1. + mac_file_flags & + MAC_auto) { + raise_object_cat = + TRUE; + } + break; + } + /* fall through */ + + default: +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac + (tmp, + curr_categories); + u64tostrmac + (tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): curr_categories %s over target categories %s, no auto, write_down or trusted -> NOT_GRANTED!\n", + current-> + pid, + current-> + comm, + tmp, + tmp2); + rsbac_kfree + (tmp2); + } + rsbac_kfree(tmp); + } + } +#endif + return NOT_GRANTED; + } + } + } + } + + /* grant area */ + + /* adjust current_sec_level and min_write_level, */ + /* if set_level is true and mac_auto has been used */ + if (set_level && (mac_auto_used_level || raise_object_level) + ) { +#ifdef CONFIG_RSBAC_MAC_LOG_LEVEL_CHANGE + { + char *target_type_name; + char *target_id_name; + + target_type_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (target_type_name) { +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = + rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + target_id_name = + rsbac_kmalloc(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif + if (target_id_name) { + get_target_name(target_type_name, + target, + target_id_name, + tid); + + if (mac_auto_used_level) { + rsbac_printk(KERN_INFO "mac_auto_write(): Changing process %u (%s, owner %u) current level from %u to %u for %s %s\n", + pid, + current->comm, + __kuid_val(current_uid()), + curr_level, + target_sec_level, + target_type_name, + target_id_name); + } else { + rsbac_printk(KERN_INFO "mac_auto_write(): Process %u (%s, owner %u): Raising object level from %u to %u for %s %s\n", + pid, + current->comm, + __kuid_val(current_uid()), + target_sec_level, + curr_level, + target_type_name, + target_id_name); + } + rsbac_kfree(target_id_name); + } + rsbac_kfree(target_type_name); + } + } +#endif + if (mac_auto_used_level) { + i_tid.process = pid; + attr_val1.current_sec_level = target_sec_level; + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_min_write_open, &attr_val2, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", + A_min_write_open); + return NOT_GRANTED; + } + if (attr_val1.min_write_open < + attr_val2.min_write_open) { + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_min_write_open, attr_val1)) { /* failed! */ + rsbac_ds_set_error + ("mac_auto_write", A_min_write_open); + return NOT_GRANTED; + } + } + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_current_sec_level, attr_val1)) { /* failed! */ + rsbac_ds_set_error("mac_auto_write", + A_none); + return NOT_GRANTED; + } + } else { + attr_val1.security_level = curr_level; + if (rsbac_set_attr(SW_MAC, target, tid, A_security_level, attr_val1)) { /* failed! */ + rsbac_ds_set_error("mac_auto_write", + A_none); + return NOT_GRANTED; + } + } + } + /* adjust current_categories and min_write_categories, */ + /* if set_level is true and mac_auto has been used */ + if (set_level && (mac_auto_used_cat || raise_object_cat) + ) { +#ifdef CONFIG_RSBAC_MAC_LOG_LEVEL_CHANGE + { + char *target_type_name = + rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (target_type_name) { + char *target_id_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = + rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + target_id_name = + rsbac_kmalloc(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif + if (target_id_name) { + char *tmp1 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + if (tmp1) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + if (tmp2) { + get_target_name + (target_type_name, + target, + target_id_name, + tid); + + if (mac_auto_used_cat) { + rsbac_printk + (KERN_INFO "mac_auto_write(): Changing process %u (%s, owner %u) current categories from %s to %s for %s %s\n", + pid, + current-> + comm, + __kuid_val(current_uid()), + u64tostrmac + (tmp1, + curr_categories), + u64tostrmac + (tmp2, + target_categories), + target_type_name, + target_id_name); + } else { + rsbac_printk + (KERN_INFO "mac_auto_write(): Process %u (%s, owner %u): raising current categories from %s to %s for %s %s\n", + pid, + current-> + comm, + __kuid_val(current_uid()), + u64tostrmac + (tmp2, + target_categories), + u64tostrmac + (tmp1, + curr_categories), + target_type_name, + target_id_name); + } + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp1); + } + rsbac_kfree(target_id_name); + } + rsbac_kfree(target_type_name); + } + } +#endif + if (mac_auto_used_cat) { + i_tid.process = pid; + attr_val1.mac_categories = target_categories; + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_min_write_categories, &attr_val2, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_write", + A_min_write_categories); + return NOT_GRANTED; + } + if ((attr_val1.mac_categories & attr_val2. + mac_categories) + != attr_val2.mac_categories) { + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_min_write_categories, attr_val1)) { /* failed! */ + rsbac_ds_set_error + ("mac_auto_write", A_min_write_categories); + return NOT_GRANTED; + } + } + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_mac_curr_categories, attr_val1)) { /* failed! */ + rsbac_ds_set_error("mac_auto_write", + A_none); + return NOT_GRANTED; + } + } else { + attr_val1.mac_categories = curr_categories; + if (rsbac_set_attr(SW_MAC, target, tid, A_mac_categories, attr_val1)) { /* failed! */ + rsbac_ds_set_error("mac_auto_write", + A_none); + return NOT_GRANTED; + } + } + } + + /* Everything done, so return */ + return GRANTED; +} + +static enum rsbac_adf_req_ret_t +auto_write(rsbac_pid_t pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, rsbac_boolean_t set_level) +{ + return auto_write_attr(pid, + target, + tid, + A_security_level, + A_mac_categories, set_level); +} + +/* auto_read() */ +/* This function works similar to auto_write() */ + +static enum rsbac_adf_req_ret_t +auto_read_attr(rsbac_pid_t pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t t_level_attr, + enum rsbac_attribute_t t_cat_attr, + rsbac_boolean_t set_level) +{ + rsbac_security_level_t curr_level; + rsbac_mac_category_vector_t curr_categories; + rsbac_security_level_t target_sec_level; + rsbac_mac_category_vector_t target_categories; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t attr_val1; + union rsbac_attribute_value_t attr_val2; + rsbac_mac_process_flags_t flags; + rsbac_boolean_t mac_auto_used_level = FALSE; + rsbac_boolean_t mac_auto_used_cat = FALSE; + rsbac_boolean_t set_level_level = FALSE; + rsbac_boolean_t set_level_cat = FALSE; + + /* first check for mac_override, which allows everything */ + i_tid.process = pid; + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_mac_process_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read", A_mac_process_flags); + return NOT_GRANTED; + } + flags = attr_val1.mac_process_flags; + if (flags & MAC_override) + return GRANTED; + + /* Get current security level */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_current_sec_level, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read", A_current_sec_level); + return NOT_GRANTED; + } + curr_level = attr_val1.security_level; + /* Get current categories */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_mac_curr_categories, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read", A_mac_curr_categories); + return NOT_GRANTED; + } + curr_categories = attr_val1.mac_categories; + /* Get target security level */ + if (rsbac_get_attr(SW_MAC, target, tid, t_level_attr, &attr_val1, TRUE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read", t_level_attr); + return NOT_GRANTED; + } + target_sec_level = attr_val1.security_level; + /* Get target categories */ + if (rsbac_get_attr(SW_MAC, target, tid, t_cat_attr, &attr_val1, TRUE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read", t_cat_attr); + return NOT_GRANTED; + } + target_categories = attr_val1.mac_categories; + + if (target_sec_level > curr_level) { + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_security_level, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read", A_security_level); + return NOT_GRANTED; + } + if (attr_val1.security_level < target_sec_level) { + rsbac_pr_debug(adf_mac, "pid %u(%s): security_level %u under target_sec_level %u, no override -> NOT_GRANTED!\n", + current->pid, current->comm, + attr_val1.security_level, + target_sec_level); + return NOT_GRANTED; + } + /* curr_level < target_level <= max_level -> need mac_auto, read_up or trusted (with read option) */ + if (flags & MAC_auto) { + /* check min_write boundary */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_min_write_open, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read", + A_min_write_open); + return NOT_GRANTED; + } + if (attr_val1.security_level < target_sec_level) { + if (!(flags & MAC_read_up) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ + && !(flags & MAC_trusted) +#endif + ) { + /* Try mac_file_flags on the target, if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_read", + A_mac_file_flags); + return + (NOT_GRANTED); + } + if ((attr_val1. + mac_file_flags & + MAC_read_up) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ + || (attr_val1. + mac_file_flags & + MAC_trusted) +#endif + ) { + break; + } + /* fall through */ + + default: + rsbac_pr_debug(adf_mac, "pid %u(%s): min_write_open %u under target_sec_level %u, no read_up or trusted -> NOT_GRANTED!\n", + current->pid, + current->comm, + attr_val1. + security_level, + target_sec_level); + return NOT_GRANTED; + } + } + } else { + mac_auto_used_level = TRUE; + set_level_level = TRUE; + } + } else { + if (!(flags & MAC_read_up) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ + && !(flags & MAC_trusted) +#endif + ) { + /* Try mac_file_flags on the target, if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_read", + A_mac_file_flags); + return NOT_GRANTED; + } + if ((attr_val1. + mac_file_flags & MAC_read_up) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ + || (attr_val1. + mac_file_flags & + MAC_trusted) +#endif + ) { + break; + } + /* fall through */ + + default: + rsbac_pr_debug(adf_mac, "pid %u(%s): current level %u under target_sec_level %u, no auto, read_up or trusted -> NOT_GRANTED!\n", + current->pid, + current->comm, + curr_level, + target_sec_level); + return NOT_GRANTED; + } + } + } + } else if (target_sec_level < curr_level) { + if (flags & MAC_auto) { + mac_auto_used_level = TRUE; + } + } + if ((target_categories & curr_categories) != target_categories) { + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_mac_categories, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read", A_mac_categories); + return NOT_GRANTED; + } + if ((target_categories & attr_val1.mac_categories) != + target_categories) { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac(tmp, + attr_val1. + mac_categories); + u64tostrmac(tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): max_categories %s under target categories %s, no override -> NOT_GRANTED!\n", + current->pid, + current->comm, + tmp, tmp2); + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp); + } + } +#endif + return NOT_GRANTED; + } + /* curr_categories < target_categories <= max_categories -> need mac_auto, + * read_up or trusted */ + if (flags & MAC_auto) { + /* check min_write boundary */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_min_write_categories, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read", + A_min_write_categories); + return NOT_GRANTED; + } + if ((target_categories & attr_val1. + mac_categories) != target_categories) { + if (!(flags & MAC_read_up) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ + && !(flags & MAC_trusted) +#endif + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_read", + A_mac_file_flags); + return + (NOT_GRANTED); + } + if ((attr_val1. + mac_file_flags & + MAC_read_up) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ + || (attr_val1. + mac_file_flags & + MAC_trusted) +#endif + ) { + break; + } + /* fall through */ + + default: +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 + = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac + (tmp, + attr_val1. + mac_categories); + u64tostrmac + (tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): min_write_categories %s under target categories %s, no read_up or trusted with read option -> NOT_GRANTED!\n", + current-> + pid, + current-> + comm, + tmp, + tmp2); + rsbac_kfree + (tmp2); + } + rsbac_kfree + (tmp); + } + } +#endif + return NOT_GRANTED; + } + } + } else { + mac_auto_used_cat = TRUE; + set_level_cat = TRUE; + } + } else { + if (!(flags & MAC_read_up) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ + && !(flags & MAC_trusted) +#endif + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_read", + A_mac_file_flags); + return NOT_GRANTED; + } + if ((attr_val1. + mac_file_flags & MAC_read_up) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ + || (attr_val1. + mac_file_flags & + MAC_trusted) +#endif + ) { + break; + } + /* fall through */ + + default: +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac + (tmp, + curr_categories); + u64tostrmac + (tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): curr_categories %s under target categories %s, no auto, read_up or trusted with read option -> NOT_GRANTED!\n", + current-> + pid, + current-> + comm, + tmp, + tmp2); + rsbac_kfree + (tmp2); + } + rsbac_kfree(tmp); + } + } +#endif + return NOT_GRANTED; + } + } + } + } else + if ((target_categories & curr_categories) != curr_categories) { + if (flags & MAC_auto) { + mac_auto_used_level = TRUE; + } + } + + /* grant area */ + + /* adjust current_sec_level and max_read_level, */ + /* if set_level is true and mac_auto has been used */ + if (set_level && mac_auto_used_level) { + i_tid.process = pid; + attr_val1.current_sec_level = target_sec_level; + if (set_level_level) { +#ifdef CONFIG_RSBAC_MAC_LOG_LEVEL_CHANGE + char *target_type_name; + char *target_id_name; + + target_type_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (target_type_name) { +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = + rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + target_id_name = + rsbac_kmalloc(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif + if (target_id_name) { + get_target_name(target_type_name, + target, + target_id_name, + tid); + + rsbac_printk(KERN_INFO "mac_auto_read(): Changing process %u (%s, owner %u) current level from %u to %u for %s %s\n", + pid, + current->comm, + __kuid_val(current_uid()), + curr_level, + target_sec_level, + target_type_name, + target_id_name); + rsbac_kfree(target_id_name); + } + rsbac_kfree(target_type_name); + } +#endif + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_current_sec_level, attr_val1)) { /* failed! */ + rsbac_ds_set_error("mac_auto_read", + A_none); + return NOT_GRANTED; + } + } + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_max_read_open, &attr_val2, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read", A_max_read_open); + return NOT_GRANTED; + } + if (attr_val1.max_read_open > attr_val2.max_read_open) { + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_max_read_open, attr_val1)) { /* failed! */ + rsbac_ds_set_error("mac_auto_read", + A_none); + return NOT_GRANTED; + } + } + } + /* adjust current_categories and max_read_categories, */ + /* if set_level is true and mac_auto has been used */ + if (set_level && mac_auto_used_cat) { + i_tid.process = pid; + attr_val1.mac_categories = target_categories; + if (set_level_cat) { +#ifdef CONFIG_RSBAC_MAC_LOG_LEVEL_CHANGE + char *target_type_name = + rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (target_type_name) { + char *target_id_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = + rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + target_id_name = + rsbac_kmalloc(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif + if (target_id_name) { + char *tmp1 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + if (tmp1) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + if (tmp2) { + get_target_name + (target_type_name, + target, + target_id_name, + tid); + + rsbac_printk + (KERN_INFO "mac_auto_read(): Changing process %u (15%s, owner %u) current categories from %s to %s for %s %s\n", + pid, + current->comm, + __kuid_val(current_uid()), + u64tostrmac + (tmp1, + curr_categories), + u64tostrmac + (tmp2, + target_categories), + target_type_name, + target_id_name); + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp1); + } + rsbac_kfree(target_id_name); + } + rsbac_kfree(target_type_name); + } +#endif + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_mac_curr_categories, attr_val1)) { /* failed! */ + rsbac_ds_set_error("mac_auto_read", + A_mac_curr_categories); + return NOT_GRANTED; + } + } + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_max_read_categories, &attr_val2, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read", A_max_read_categories); + return NOT_GRANTED; + } + if ((attr_val1.mac_categories & attr_val2.mac_categories) + != attr_val1.mac_categories) { + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_max_read_categories, attr_val1)) { /* failed! */ + rsbac_ds_set_error("mac_auto_read", + A_max_read_categories); + return NOT_GRANTED; + } + } + } + + /* Everything done, so return */ + return GRANTED; +} + +static enum rsbac_adf_req_ret_t +auto_read(rsbac_pid_t pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, rsbac_boolean_t set_level) +{ + return auto_read_attr(pid, + target, + tid, + A_security_level, + A_mac_categories, set_level); +} + + +/* auto-read-write() */ +/* combines auto-read and auto-write */ + +static enum rsbac_adf_req_ret_t +auto_read_write_attr(rsbac_pid_t pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t t_level_attr, + enum rsbac_attribute_t t_cat_attr, + rsbac_boolean_t set_level) +{ + rsbac_security_level_t curr_level; + rsbac_mac_category_vector_t curr_categories; + rsbac_security_level_t target_sec_level; + rsbac_mac_category_vector_t target_categories; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t attr_val1; + union rsbac_attribute_value_t attr_val2; + rsbac_mac_process_flags_t flags; + rsbac_boolean_t mac_auto_used_level = FALSE; + rsbac_boolean_t mac_auto_used_cat = FALSE; + rsbac_boolean_t raise_object_level = FALSE; + rsbac_boolean_t raise_object_cat = FALSE; + + /* first check for mac_override, which allows everything */ + i_tid.process = pid; + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_mac_process_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", A_mac_process_flags); + return NOT_GRANTED; + } + flags = attr_val1.mac_process_flags; + if (flags & MAC_override) + return GRANTED; + + /* Get current security level */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_current_sec_level, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", A_current_sec_level); + return NOT_GRANTED; + } + curr_level = attr_val1.security_level; + /* Get current categories */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_mac_curr_categories, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", A_mac_curr_categories); + return NOT_GRANTED; + } + curr_categories = attr_val1.mac_categories; + /* Get target security level */ + if (rsbac_get_attr(SW_MAC, target, tid, t_level_attr, &attr_val1, TRUE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", t_level_attr); + return NOT_GRANTED; + } + target_sec_level = attr_val1.security_level; + /* Get target categories */ + if (rsbac_get_attr(SW_MAC, target, tid, t_cat_attr, &attr_val1, TRUE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", t_cat_attr); + return NOT_GRANTED; + } + target_categories = attr_val1.mac_categories; + + if (target_sec_level > curr_level) { + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_security_level, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", A_security_level); + return NOT_GRANTED; + } + if (attr_val1.security_level < target_sec_level) { + rsbac_pr_debug(adf_mac, "pid %u(%s): security_level %u under target_sec_level %u, no override -> NOT_GRANTED!\n", + current->pid, current->comm, + attr_val1.security_level, + target_sec_level); + return NOT_GRANTED; + } + /* curr_level < target_level <= max_level */ + /* -> need mac_auto, (write_up && read_up) + * or trusted (with read option) */ + if (flags & MAC_auto) { + /* check min_write boundary */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_min_write_open, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", + A_min_write_open); + return NOT_GRANTED; + } + if (attr_val1.security_level < target_sec_level) { + if (! + ((flags & MAC_write_up) + && (flags & MAC_read_up)) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ +&& !(flags & MAC_trusted) +#endif + ) { + /* Try mac_file_flags on the target, if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_read_write", + A_mac_file_flags); + return + (NOT_GRANTED); + } + if (((attr_val1. + mac_file_flags & + MAC_write_up) + && (attr_val1. + mac_file_flags & + MAC_read_up) + ) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ + || (flags & + MAC_trusted) +#endif + ) { + break; + } + /* fall through */ + + default: + rsbac_pr_debug(adf_mac, "pid %u(%s): min_write_open %u under target_sec_level %u, no read_up or trusted -> NOT_GRANTED!\n", + current->pid, + current->comm, + attr_val1. + security_level, + target_sec_level); + return NOT_GRANTED; + } + } + } else + mac_auto_used_level = TRUE; + } else { + if (! + ((flags & MAC_write_up) + && (flags & MAC_read_up)) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ +&& !(flags & MAC_trusted) +#endif + ) { + /* Try mac_file_flags on the target, if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_read_write", + A_mac_file_flags); + return NOT_GRANTED; + } + if (((attr_val1. + mac_file_flags & + MAC_write_up) + && (attr_val1. + mac_file_flags & + MAC_read_up) + ) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ + || (flags & MAC_trusted) +#endif + ) { + break; + } + /* fall through */ + + default: + rsbac_pr_debug(adf_mac, "pid %u(%s): current level %u under target_sec_level %u, no auto, (write_up && read_up) or trusted -> NOT_GRANTED!\n", + current->pid, + current->comm, + curr_level, + target_sec_level); + return NOT_GRANTED; + } + } + } + } else if (target_sec_level < curr_level) { + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_min_security_level, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", A_min_security_level); + return NOT_GRANTED; + } + if (attr_val1.security_level > target_sec_level) { + rsbac_pr_debug(adf_mac, "pid %u(%s): min_security_level %u over target_sec_level %u, no override -> NOT_GRANTED!\n", + current->pid, + current->comm, attr_val1.security_level, + target_sec_level); + return NOT_GRANTED; + } + /* min_level <= target_level < curr_level -> need mac_auto, + * write_down or trusted */ + if (flags & MAC_auto) { + /* check max_read boundary */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_max_read_open, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", + A_max_read_open); + return NOT_GRANTED; + } + if (attr_val1.security_level > target_sec_level) { + if (!(flags & MAC_write_down) + && !(flags & MAC_trusted) + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_read_write", + A_mac_file_flags); + return + (NOT_GRANTED); + } + if ((attr_val1. + mac_file_flags & + MAC_write_down) + || (attr_val1. + mac_file_flags & + MAC_trusted) + ) { + if (attr_val1. + mac_file_flags + & MAC_auto) { + raise_object_level + = TRUE; + } + break; + } + /* fall through */ + + default: + rsbac_pr_debug(adf_mac, "pid %u(%s): max_read_open %u over target_sec_level %u, no write_down or trusted -> NOT_GRANTED!\n", + current->pid, + current->comm, + attr_val1. + security_level, + target_sec_level); + return NOT_GRANTED; + } + } + } else + mac_auto_used_level = TRUE; + } else { + if (!(flags & MAC_write_down) + && !(flags & MAC_trusted) + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_read_write", + A_mac_file_flags); + return NOT_GRANTED; + } + if ((attr_val1. + mac_file_flags & + MAC_write_down) + || (attr_val1. + mac_file_flags & + MAC_trusted) + ) { + if (attr_val1. + mac_file_flags & + MAC_auto) { + raise_object_level + = TRUE; + } + break; + } + /* fall through */ + + default: + rsbac_pr_debug(adf_mac, "pid %u(%s): current security_level %u over target_sec_level %u, no auto, write_down or trusted -> NOT_GRANTED!\n", + current->pid, + current->comm, + curr_level, + target_sec_level); + return NOT_GRANTED; + } + } + } + } + if ((target_categories & curr_categories) != target_categories) { + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_mac_categories, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", A_mac_categories); + return NOT_GRANTED; + } + if ((target_categories & attr_val1.mac_categories) != + target_categories) { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac(tmp, + attr_val1. + mac_categories); + u64tostrmac(tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): max_categories %s under target categories %s, no override -> NOT_GRANTED!\n", + current->pid, + current->comm, + tmp, tmp2); + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp); + } + } +#endif + return NOT_GRANTED; + } + /* curr_categories < target_categories <= max_categories */ + /* -> need mac_auto, (read_up && write_up) or + * trusted (with read option) */ + if (flags & MAC_auto) { + /* check min_write boundary */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_min_write_categories, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", + A_min_write_categories); + return NOT_GRANTED; + } + if ((target_categories & attr_val1. + mac_categories) != target_categories) { + if (! + ((flags & MAC_write_up) + && (flags & MAC_read_up)) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ +&& !(flags & MAC_trusted) +#endif + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_read_write", + A_mac_file_flags); + return + (NOT_GRANTED); + } + if (((attr_val1. + mac_file_flags & + MAC_write_up) + && (attr_val1. + mac_file_flags & + MAC_read_up) + ) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ + || (flags & + MAC_trusted) +#endif + ) { + break; + } + /* fall through */ + + default: +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 + = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac + (tmp, + attr_val1. + mac_categories); + u64tostrmac + (tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): min_write_categories %s under target categories %s, no (read_up and write_up) or trusted with read option -> NOT_GRANTED!\n", + current-> + pid, + current-> + comm, + tmp, + tmp2); + rsbac_kfree + (tmp2); + } + rsbac_kfree + (tmp); + } + } +#endif + return NOT_GRANTED; + } + } + } else + mac_auto_used_cat = TRUE; + } else { + if (! + ((flags & MAC_write_up) + && (flags & MAC_read_up)) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ +&& !(flags & MAC_trusted) +#endif + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_read_write", + A_mac_file_flags); + return NOT_GRANTED; + } + if (((attr_val1. + mac_file_flags & + MAC_write_up) + && (attr_val1. + mac_file_flags & + MAC_read_up) + ) +#ifdef CONFIG_RSBAC_MAC_TRUSTED_READ + || (flags & MAC_trusted) +#endif + ) { + break; + } + /* fall through */ + + default: +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac + (tmp, + curr_categories); + u64tostrmac + (tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): curr_categories %s under target categories %s, no auto, (read_up and write_up) or trusted -> NOT_GRANTED!\n", + current-> + pid, + current-> + comm, + tmp, + tmp2); + rsbac_kfree + (tmp2); + } + rsbac_kfree(tmp); + } + } +#endif + return NOT_GRANTED; + } + } + } + } else + if ((target_categories & curr_categories) != curr_categories) { + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_mac_min_categories, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", A_mac_min_categories); + return NOT_GRANTED; + } + if ((target_categories & attr_val1.mac_categories) != + attr_val1.mac_categories) { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac(tmp, + attr_val1. + mac_categories); + u64tostrmac(tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): min_categories %s over target categories %s, no override -> NOT_GRANTED!\n", + current->pid, + current->comm, + tmp, tmp2); + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp); + } + } +#endif + return NOT_GRANTED; + } + /* min_level <= target_level < curr_level -> need mac_auto, + * write_down or trusted */ + if (flags & MAC_auto) { + /* check max_read boundary */ + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_max_read_categories, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", + A_max_read_categories); + return NOT_GRANTED; + } + if ((target_categories & attr_val1. + mac_categories) != attr_val1.mac_categories) { + if (!(flags & MAC_write_down) + && !(flags & MAC_trusted) + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_read_write", + A_mac_file_flags); + return + (NOT_GRANTED); + } + if ((attr_val1. + mac_file_flags & + MAC_write_down) + || (attr_val1. + mac_file_flags & + MAC_trusted) + ) { + if (attr_val1. + mac_file_flags + & MAC_auto) { + raise_object_cat + = TRUE; + } + break; + } + /* fall through */ + + default: +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 + = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac + (tmp, + attr_val1. + mac_categories); + u64tostrmac + (tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): max_read_categories %s over target categories %s, no write_down or trusted -> NOT_GRANTED!\n", + current-> + pid, + current-> + comm, + tmp, + tmp2); + rsbac_kfree + (tmp2); + } + rsbac_kfree + (tmp); + } + } +#endif + return NOT_GRANTED; + } + } + } else + mac_auto_used_cat = TRUE; + } else { + if (!(flags & MAC_write_down) + && !(flags & MAC_trusted) + ) { + /* Try mac_file_flags on the target, + * if FD object */ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_file_flags, &attr_val1, FALSE)) { /* failed! */ + rsbac_ds_get_error + ("mac_auto_read_write", + A_mac_file_flags); + return NOT_GRANTED; + } + if ((attr_val1. + mac_file_flags & + MAC_write_down) + || (attr_val1. + mac_file_flags & + MAC_trusted) + ) { + if (attr_val1. + mac_file_flags & + MAC_auto) { + raise_object_cat = + TRUE; + } + break; + } + /* fall through */ + + default: +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_mac) { + char *tmp = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + + if (tmp2) { + u64tostrmac + (tmp, + curr_categories); + u64tostrmac + (tmp2, + target_categories); + rsbac_pr_debug(adf_mac, "pid %u(%s): curr_categories %s over target categories %s, no auto, write_down or trusted -> NOT_GRANTED!\n", + current-> + pid, + current-> + comm, + tmp, + tmp2); + rsbac_kfree + (tmp2); + } + rsbac_kfree(tmp); + } + } +#endif + return NOT_GRANTED; + } + } + } + } + + /* grant area */ + + /* adjust current_sec_level and min_write_level, */ + /* if set_level is true and mac_auto has been used */ + if (set_level && (mac_auto_used_level || raise_object_level) + ) { +#ifdef CONFIG_RSBAC_MAC_LOG_LEVEL_CHANGE + { + char *target_type_name; + char *target_id_name; + + target_type_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (target_type_name) { +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = + rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + target_id_name = + rsbac_kmalloc(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif + if (target_id_name) { + get_target_name(target_type_name, + target, + target_id_name, + tid); + + if (mac_auto_used_level) { + rsbac_printk(KERN_INFO "mac_auto_read_write(): Changing process %u (%s, owner %u) current level from %u to %u for %s %s\n", + pid, + current->comm, + __kuid_val(current_uid()), + curr_level, + target_sec_level, + target_type_name, + target_id_name); + } else { + rsbac_printk(KERN_INFO "mac_auto_read_write(): Process %u (%s, owner %u): Raising object level from %u to %u for %s %s\n", + pid, + current->comm, + __kuid_val(current_uid()), + target_sec_level, + curr_level, + target_type_name, + target_id_name); + } + rsbac_kfree(target_id_name); + } + rsbac_kfree(target_type_name); + } + } +#endif + if (mac_auto_used_level) { + i_tid.process = pid; + attr_val1.current_sec_level = target_sec_level; + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_min_write_open, &attr_val2, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", + A_min_write_open); + return NOT_GRANTED; + } + if (attr_val1.min_write_open < + attr_val2.min_write_open) { + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_min_write_open, attr_val1)) { /* failed! */ + rsbac_ds_set_error + ("mac_auto_read_write", + A_min_write_open); + return NOT_GRANTED; + } + } + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_max_read_open, &attr_val2, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", + A_max_read_open); + return NOT_GRANTED; + } + if (attr_val1.max_read_open > + attr_val2.max_read_open) { + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_max_read_open, attr_val1)) { /* failed! */ + rsbac_ds_set_error + ("mac_auto_read_write", + A_max_read_open); + return NOT_GRANTED; + } + } + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_current_sec_level, attr_val1)) { /* failed! */ + rsbac_ds_set_error("mac_auto_read_write", + A_none); + return NOT_GRANTED; + } + } else { + attr_val1.security_level = curr_level; + if (rsbac_set_attr(SW_MAC, target, tid, A_security_level, attr_val1)) { /* failed! */ + rsbac_ds_set_error("mac_auto_read_write", + A_none); + return NOT_GRANTED; + } + } + } + /* adjust current_categories and min_write_categories, */ + /* if set_level is true and mac_auto has been used */ + if (set_level && (mac_auto_used_cat || raise_object_cat) + ) { +#ifdef CONFIG_RSBAC_MAC_LOG_LEVEL_CHANGE + { + char *target_type_name = + rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (target_type_name) { + char *target_id_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = + rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + target_id_name = + rsbac_kmalloc(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif + if (target_id_name) { + char *tmp1 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + if (tmp1) { + char *tmp2 = + rsbac_kmalloc + (RSBAC_MAXNAMELEN); + if (tmp2) { + get_target_name + (target_type_name, + target, + target_id_name, + tid); + + if (mac_auto_used_cat) { + rsbac_printk + (KERN_INFO "mac_auto_read_write(): Changing process %u (%s, owner %u) current categories from %s to %s for %s %s\n", + pid, + current-> + comm, + __kuid_val(current_uid()), + u64tostrmac + (tmp1, + curr_categories), + u64tostrmac + (tmp2, + target_categories), + target_type_name, + target_id_name); + } else { + rsbac_printk + (KERN_INFO "mac_auto_read_write(): Process %u (%s, owner %u): raising current categories from %s to %s for %s %s\n", + pid, + current-> + comm, + __kuid_val(current_uid()), + u64tostrmac + (tmp2, + target_categories), + u64tostrmac + (tmp1, + curr_categories), + target_type_name, + target_id_name); + } + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp1); + } + rsbac_kfree(target_id_name); + } + rsbac_kfree(target_type_name); + } + } +#endif + if (mac_auto_used_cat) { + i_tid.process = pid; + attr_val1.mac_categories = target_categories; + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_min_write_categories, &attr_val2, FALSE)) { /* failed! */ + rsbac_ds_set_error("mac_auto_read_write", + A_min_write_categories); + return NOT_GRANTED; + } + if ((attr_val1.mac_categories & attr_val2. + mac_categories) + != attr_val2.mac_categories) { + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_min_write_categories, attr_val1)) { /* failed! */ + rsbac_ds_set_error + ("mac_auto_read_write", + A_min_write_categories); + return NOT_GRANTED; + } + } + if (rsbac_get_attr(SW_MAC, T_PROCESS, i_tid, A_max_read_categories, &attr_val2, FALSE)) { /* failed! */ + rsbac_ds_get_error("mac_auto_read_write", + A_max_read_categories); + return NOT_GRANTED; + } + if ((attr_val1.mac_categories & attr_val2. + mac_categories) + != attr_val1.mac_categories) { + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_max_read_categories, attr_val1)) { /* failed! */ + rsbac_ds_set_error + ("mac_auto_read_write", + A_max_read_categories); + return NOT_GRANTED; + } + } + if (rsbac_set_attr(SW_MAC, T_PROCESS, i_tid, A_mac_curr_categories, attr_val1)) { /* failed! */ + rsbac_ds_set_error("mac_auto_read_write", + A_none); + return NOT_GRANTED; + } + } else { + attr_val1.mac_categories = curr_categories; + if (rsbac_set_attr(SW_MAC, target, tid, A_mac_categories, attr_val1)) { /* failed! */ + rsbac_ds_set_error("mac_auto_read_write", + A_none); + return NOT_GRANTED; + } + } + } + + /* Everything done, so return */ + return GRANTED; +} + +static enum rsbac_adf_req_ret_t +auto_read_write(rsbac_pid_t pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, rsbac_boolean_t set_level) +{ + return auto_read_write_attr(pid, + target, + tid, + A_security_level, + A_mac_categories, set_level); +} + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +inline enum rsbac_adf_req_ret_t +rsbac_adf_request_mac(enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + enum rsbac_adf_req_ret_t result = DO_NOT_CARE; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; +#if defined(CONFIG_RSBAC_MAC_NET_OBJ_PROT) + union rsbac_attribute_value_t i_attr_val2; +#endif + + switch (request) { + case R_ADD_TO_KERNEL: + switch (target) { + case T_FILE: + case T_DEV: + case T_NONE: + /* test owner's mac_role */ + return mac_check_role(owner, SR_administrator); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_ALTER: + /* only for IPC */ + if (target == T_IPC) { + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + } else + /* all other targets are unknown */ + return DO_NOT_CARE; + break; + + case R_APPEND_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + break; + case T_IPC: + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + break; + case T_DEV: + /* Only check for devices with mac_check set */ + if (rsbac_get_attr(SW_MAC, + T_DEV, + tid, + A_mac_check, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error("rsbac_adf_request_mac", + A_mac_check); + return NOT_GRANTED; + } + if (!i_attr_val1.mac_check) + return DO_NOT_CARE; + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + break; + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_CHANGE_GROUP: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + case T_IPC: + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + +#if defined(CONFIG_RSBAC_MAC_UM_PROT) + case T_USER: + /* Security Officer? */ + return mac_check_role(owner, SR_security_officer); +#endif + /* We do not care about */ + /* all other cases */ + default: + return DO_NOT_CARE; + } + + case R_CHANGE_OWNER: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + + case T_IPC: + return (auto_write(caller_pid, + target, tid, FALSE)); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_CHDIR: + switch (target) { + case T_DIR: + /* and perform auto-read without setting attributes */ + return (auto_read(caller_pid, target, tid, FALSE)); + break; + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_CREATE: + switch (target) { + /* Creating dir or (pseudo) file IN target dir! */ + case T_DIR: +#ifdef CONFIG_RSBAC_MAC_LIGHT + return GRANTED; +#else + /* Mode of created item is ignored! */ + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); +#endif + break; + +#ifdef CONFIG_RSBAC_MAC_NET_OBJ_PROT + case T_NETTEMP: + return mac_check_role(owner, SR_security_officer); + + case T_NETOBJ: + /* and perform auto-write without setting attributes */ + return (auto_write_attr(caller_pid, + target, + tid, + A_local_sec_level, + A_local_mac_categories, + FALSE)); +#endif + +#if defined(CONFIG_RSBAC_MAC_UM_PROT) + case T_USER: + case T_GROUP: + /* Security Officer? */ + return mac_check_role(owner, SR_security_officer); +#endif + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_DELETE: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + break; + case T_IPC: + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + break; + +#ifdef CONFIG_RSBAC_MAC_NET_OBJ_PROT + case T_NETTEMP: + return mac_check_role(owner, SR_security_officer); +#endif +#if defined(CONFIG_RSBAC_MAC_UM_PROT) + case T_USER: + case T_GROUP: + /* Security Officer? */ + return mac_check_role(owner, SR_security_officer); +#endif + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_EXECUTE: + case R_MAP_EXEC: + switch (target) { + case T_FILE: + /* and perform auto-read without setting attributes */ + return (auto_read(caller_pid, target, tid, FALSE)); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_GET_PERMISSIONS_DATA: + switch (target) { +#if defined(CONFIG_RSBAC_MAC_UM_PROT) + case T_USER: + case T_GROUP: + /* Security Officer? */ + return mac_check_role(owner, SR_security_officer); +#endif +#ifdef CONFIG_RSBAC_MAC_NET_OBJ_PROT + case T_NETOBJ: + /* and perform auto-read without setting attributes */ + return (auto_read_attr(caller_pid, + target, + tid, + A_local_sec_level, + A_local_mac_categories, + FALSE)); +#endif + + default: + return DO_NOT_CARE; + } + + case R_GET_STATUS_DATA: + switch (target) { + case T_SCD: + /* target rsbaclog? only for secoff */ + if (tid.scd != ST_rsbac_log) + return GRANTED; + /* Secoff? */ + if (mac_check_role(owner, SR_security_officer) == + NOT_GRANTED) + return mac_check_role(owner, SR_auditor); + else + return GRANTED; + + case T_PROCESS: + /* perform auto-read without setting attributes */ + return (auto_read_attr(caller_pid, + target, + tid, + A_current_sec_level, + A_mac_curr_categories, + FALSE)); + +#ifdef CONFIG_RSBAC_MAC_NET_OBJ_PROT + case T_NETOBJ: + /* and perform auto-read without setting attributes */ + return (auto_read_attr(caller_pid, + target, + tid, + A_local_sec_level, + A_local_mac_categories, + FALSE)); +#endif + + default: + return DO_NOT_CARE; + } + + case R_LINK_HARD: + switch (target) { + case T_FILE: + case T_UNIXSOCK: + case T_FIFO: + case T_SYMLINK: + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + break; + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_MODIFY_ACCESS_DATA: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + break; + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_MODIFY_ATTRIBUTE: + switch (attr) { + case A_security_level: + case A_initial_security_level: + case A_local_sec_level: + case A_remote_sec_level: + case A_min_security_level: + case A_mac_categories: + case A_mac_initial_categories: + case A_local_mac_categories: + case A_remote_mac_categories: + case A_mac_min_categories: + case A_mac_user_flags: + case A_mac_process_flags: + case A_mac_file_flags: + case A_system_role: + case A_mac_role: + case A_current_sec_level: + case A_mac_curr_categories: + case A_min_write_open: + case A_max_read_open: + case A_min_write_categories: + case A_max_read_categories: + case A_mac_check: + case A_mac_auto: + case A_mac_prop_trusted: + case A_symlink_add_mac_level: +#ifdef CONFIG_RSBAC_MAC_GEN_PROT + case A_pseudo: + case A_log_array_low: + case A_log_array_high: + case A_local_log_array_low: + case A_local_log_array_high: + case A_remote_log_array_low: + case A_remote_log_array_high: + case A_log_program_based: + case A_log_user_based: + case A_symlink_add_remote_ip: + case A_symlink_add_uid: + case A_allow_write_exec: + case A_fake_root_uid: + case A_audit_uid: + case A_auid_exempt: + case A_remote_ip: + case A_kernel_thread: + case A_vset: +#endif +#ifdef CONFIG_RSBAC_MAC_AUTH_PROT + case A_auth_may_setuid: + case A_auth_may_set_cap: + case A_auth_start_uid: + case A_auth_start_euid: + case A_auth_start_gid: + case A_auth_start_egid: + case A_auth_learn: + case A_auth_add_f_cap: + case A_auth_remove_f_cap: + case A_auth_last_auth: +#endif + /* All attributes (remove target!) */ + case A_none: + /* Security Officer? */ + return mac_check_role(owner, SR_security_officer); + + default: + return DO_NOT_CARE; + } + + case R_MODIFY_PERMISSIONS_DATA: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + break; + + case T_SCD: +#ifdef CONFIG_RSBAC_USER_MOD_IOPERM + if (tid.scd == ST_ioports) + return GRANTED; +#endif + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, + A_mac_role, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error("rsbac_adf_request_mac", + A_mac_role); + return NOT_GRANTED; + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return GRANTED; + /* For booting: if administrator and ioports, then grant */ + if ((i_attr_val1.system_role == SR_administrator) + && (tid.scd == ST_ioports)) + return GRANTED; + else + return NOT_GRANTED; + +#ifdef CONFIG_RSBAC_MAC_NET_OBJ_PROT + case T_NETOBJ: + /* and perform auto-write without setting attributes */ + return (auto_write_attr(caller_pid, + target, + tid, + A_local_sec_level, + A_local_mac_categories, + FALSE)); +#endif + +#if defined(CONFIG_RSBAC_MAC_UM_PROT) + case T_USER: + case T_GROUP: + /* Security Officer? */ + return mac_check_role(owner, SR_security_officer); +#endif + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_MODIFY_SYSTEM_DATA: + switch (target) { + case T_SCD: + /* target rlimit? no problem, but needed -> grant */ + if ( (tid.scd == ST_rlimit) + || (tid.scd == ST_priority) + || (tid.scd == ST_mlock) + ) + return GRANTED; + /* Get role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, + A_mac_role, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error("rsbac_adf_request_mac", + A_mac_role); + return NOT_GRANTED; + } + /* if rsbaclog: grant only for secoff and auditor */ + if (tid.scd == ST_rsbac_log) { + if ((i_attr_val1.system_role == + SR_security_officer) + || (i_attr_val1.system_role == + SR_auditor) + ) + return GRANTED; + else + return NOT_GRANTED; + } + /* if rsbac_log_remote: grant only for secoff */ + if (tid.scd == ST_rsbac_remote_log) { + if ((i_attr_val1.system_role == + SR_security_officer) + ) + return GRANTED; + else + return NOT_GRANTED; + } + /* if rsbac: grant for secoff and adminr */ + if (tid.scd == ST_rsbac) { + if ((i_attr_val1.system_role == + SR_security_officer) + || (i_attr_val1.system_role == + SR_administrator) + ) + return GRANTED; + else + return NOT_GRANTED; + } + /* if administrator, then grant */ + if (i_attr_val1.system_role == SR_administrator) + return GRANTED; + else + return NOT_GRANTED; + + case T_DEV: + if (tid.dev.type == D_block) + return mac_check_role(owner, + SR_administrator); + else + return DO_NOT_CARE; + + case T_PROCESS: + /* and perform auto-write without setting attributes */ + return (auto_write_attr(caller_pid, + target, + tid, + A_current_sec_level, + A_mac_curr_categories, + FALSE)); + +#ifdef CONFIG_RSBAC_MAC_NET_DEV_PROT + case T_NETDEV: + return mac_check_role(owner, SR_administrator); +#endif +#ifdef CONFIG_RSBAC_MAC_NET_OBJ_PROT + case T_NETOBJ: + /* and perform auto-write without setting attributes */ + return (auto_write_attr(caller_pid, + target, + tid, + A_local_sec_level, + A_local_mac_categories, + FALSE)); +#endif + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_MOUNT: + switch (target) { + case T_FILE: + case T_DIR: + case T_DEV: + /* test owner's mac_role: Administrator? */ +#ifndef CONFIG_RSBAC_MAC_LIGHT + if (mac_check_role(owner, SR_administrator) == + NOT_GRANTED) + return NOT_GRANTED; +#endif + /* test read-write access to mount dir / dev: */ + /* and perform auto-read(-write) without setting of attributes */ + if ((target == T_DEV) + && (attr == A_mode) + && (attr_val.mode & MS_RDONLY)) + return (auto_read(caller_pid, + target, tid, FALSE)); + else + return (auto_read_write(caller_pid, + target, + tid, FALSE)); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_READ: + switch (target) { + case T_DIR: +#ifdef CONFIG_RSBAC_RW + case T_IPC: + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: +#endif + /* and perform auto-read without setting attributes */ + return (auto_read(caller_pid, target, tid, FALSE)); + break; + +#ifdef CONFIG_RSBAC_RW + case T_DEV: + /* Only check for devices with mac_check set */ + if (rsbac_get_attr(SW_MAC, + T_DEV, + tid, + A_mac_check, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error("rsbac_adf_request_mac", + A_mac_check); + return NOT_GRANTED; + } + if (!i_attr_val1.mac_check) + return DO_NOT_CARE; + /* and perform auto-read without setting attributes */ + return (auto_read(caller_pid, target, tid, FALSE)); + break; +#endif + +#if defined(CONFIG_RSBAC_MAC_NET_OBJ_PROT) + case T_NETTEMP: + if (mac_check_role(owner, SR_security_officer) == + GRANTED) + return GRANTED; + return mac_check_role(owner, SR_administrator); + + case T_NETOBJ: + /* and perform auto-read without setting attributes */ + return (auto_read_attr(caller_pid, + target, + tid, + A_remote_sec_level, + A_remote_mac_categories, + FALSE)); +#endif + +#if defined(CONFIG_RSBAC_MAC_UM_PROT) + case T_USER: + /* Security Officer or Admin? */ + if (mac_check_role(owner, SR_security_officer) == + GRANTED) + return GRANTED; + else + return mac_check_role(owner, + SR_administrator); +#endif + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + + case R_READ_ATTRIBUTE: + switch (attr) { + case A_owner: + case A_security_level: + case A_local_sec_level: + case A_remote_sec_level: + case A_min_security_level: + case A_mac_categories: + case A_local_mac_categories: + case A_remote_mac_categories: + case A_mac_min_categories: + case A_pseudo: + case A_system_role: + case A_mac_role: + case A_current_sec_level: + case A_min_write_open: + case A_max_read_open: + case A_mac_user_flags: + case A_mac_process_flags: + case A_mac_check: + case A_mac_auto: + case A_mac_prop_trusted: + case A_mac_file_flags: + case A_initial_security_level: + case A_mac_initial_categories: + case A_symlink_add_mac_level: +#ifdef CONFIG_RSBAC_MAC_GEN_PROT + case A_log_array_low: + case A_log_array_high: + case A_log_program_based: + case A_log_user_based: + case A_symlink_add_remote_ip: + case A_symlink_add_uid: + case A_fake_root_uid: + case A_audit_uid: + case A_auid_exempt: + case A_remote_ip: + case A_kernel_thread: + case A_vset: +#endif +#ifdef CONFIG_RSBAC_MAC_AUTH_PROT + case A_auth_may_setuid: + case A_auth_may_set_cap: + case A_auth_start_uid: + case A_auth_start_euid: + case A_auth_start_gid: + case A_auth_start_egid: + case A_auth_learn: + case A_auth_last_auth: +#endif + /* Security Officer ot Admin? */ + if (mac_check_role(owner, SR_security_officer) == + GRANTED) + return GRANTED; + else + return mac_check_role(owner, + SR_administrator); + + default: + return DO_NOT_CARE; + } + + case R_READ_OPEN: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_UNIXSOCK: + case T_IPC: + /* and perform auto-read without setting attributes */ + return (auto_read(caller_pid, target, tid, FALSE)); + break; + case T_DEV: + /* Only check for devices with mac_check set */ + if (rsbac_get_attr(SW_MAC, + T_DEV, + tid, + A_mac_check, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error("rsbac_adf_request_mac", + A_mac_check); + return NOT_GRANTED; + } + if (!i_attr_val1.mac_check) + return DO_NOT_CARE; + /* and perform auto-read without setting attributes */ + return (auto_read(caller_pid, target, tid, FALSE)); + break; + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_READ_WRITE_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + case T_IPC: + /* and perform auto-read-write without setting attributes */ + return (auto_read_write(caller_pid, + target, tid, FALSE)); + + case T_DEV: + /* Only check for devices with mac_check set */ + if (rsbac_get_attr(SW_MAC, + T_DEV, + tid, + A_mac_check, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error("rsbac_adf_request_mac", + A_mac_check); + return NOT_GRANTED; + } + if (!i_attr_val1.mac_check) + return DO_NOT_CARE; + /* and perform auto-read-write without setting attributes */ + return (auto_read_write(caller_pid, + target, tid, FALSE)); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_REMOVE_FROM_KERNEL: + switch (target) { + case T_FILE: + case T_DEV: + case T_NONE: + /* test owner's mac_role */ + return mac_check_role(owner, SR_administrator); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_SHUTDOWN: + switch (target) { + case T_NONE: + /* test owner's mac_role */ + return mac_check_role(owner, SR_administrator); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_RENAME: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + /* and perform auto-write without setting attributes */ + result = auto_write(caller_pid, + target, tid, FALSE); + /* if parent dir might change, convert inherit to explicit level/cat: + get and set effective value */ + if (((result == GRANTED) + || (result == DO_NOT_CARE) + ) + && ((attr != A_new_dir_dentry_p) + || (attr_val.new_dir_dentry_p != + tid.file.dentry_p->d_parent) + ) + ) { + if (rsbac_get_attr(SW_MAC, target, tid, A_security_level, &i_attr_val1, TRUE)) { /* failed! */ + rsbac_ds_get_error + ("rsbac_adf_request_mac", + A_security_level); + return NOT_GRANTED; + } + if (rsbac_set_attr(SW_MAC, target, tid, A_security_level, i_attr_val1)) { /* failed! */ + rsbac_ds_set_error + ("rsbac_adf_request_mac", + A_security_level); + return NOT_GRANTED; + } + if (rsbac_get_attr(SW_MAC, target, tid, A_mac_categories, &i_attr_val1, TRUE)) { /* failed! */ + rsbac_ds_get_error + ("rsbac_adf_request_mac", + A_mac_categories); + return NOT_GRANTED; + } + if (rsbac_set_attr(SW_MAC, target, tid, A_mac_categories, i_attr_val1)) { /* failed! */ + rsbac_ds_set_error + ("rsbac_adf_request_mac", + A_none); + return NOT_GRANTED; + } + } + return result; + break; +#if defined(CONFIG_RSBAC_MAC_UM_PROT) + case T_USER: + case T_GROUP: + /* Security Officer? */ + return mac_check_role(owner, SR_security_officer); +#endif + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + + case R_SEARCH: + switch (target) { + case T_DIR: + case T_SYMLINK: + case T_UNIXSOCK: + /* and perform auto-read without setting attributes */ + return (auto_read(caller_pid, target, tid, FALSE)); + break; + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_SEND_SIGNAL: + switch (target) { + case T_PROCESS: + /* and perform auto-write without setting attributes */ + return (auto_write_attr(caller_pid, + target, + tid, + A_current_sec_level, + A_mac_curr_categories, + FALSE)); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_SWITCH_LOG: + switch (target) { + case T_NONE: + /* test owner's mac_role */ + return mac_check_role(owner, SR_security_officer); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_SWITCH_MODULE: + switch (target) { + case T_NONE: + /* we need the switch_target */ + if (attr != A_switch_target) + return NOT_GRANTED; + /* do not care for other modules */ + if ((attr_val.switch_target != SW_MAC) +#ifdef CONFIG_RSBAC_MAC_AUTH_PROT + && (attr_val.switch_target != SW_AUTH) +#endif +#ifdef CONFIG_RSBAC_SOFTMODE + && (attr_val.switch_target != SW_SOFTMODE) +#endif +#ifdef CONFIG_RSBAC_FREEZE + && (attr_val.switch_target != SW_FREEZE) +#endif +#ifdef CONFIG_RSBAC_MPROTECT + && (attr_val.switch_target != SW_MPROTECT) +#endif + ) + return DO_NOT_CARE; + /* test owner's mac_role */ + return mac_check_role(owner, SR_security_officer); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_TRACE: + switch (target) { + case T_PROCESS: + /* and perform auto-read-write without setting attributes */ + return (auto_read_write_attr(caller_pid, + target, + tid, + A_current_sec_level, + A_mac_curr_categories, + FALSE)); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_TRUNCATE: + switch (target) { + case T_FILE: + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + break; + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_UMOUNT: + switch (target) { + case T_FILE: + case T_DIR: + case T_DEV: +#ifdef CONFIG_RSBAC_MAC_LIGHT + return GRANTED; +#else + return mac_check_role(owner, SR_administrator); +#endif + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_WRITE: + switch (target) { + case T_DIR: + case T_IPC: +#ifdef CONFIG_RSBAC_RW + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: +#endif + /* Mode of created item is ignored! */ + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + + +#ifdef CONFIG_RSBAC_RW + case T_DEV: + /* Only check for devices with mac_check set */ + if (rsbac_get_attr(SW_MAC, + T_DEV, + tid, + A_mac_check, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error("rsbac_adf_request_mac", + A_mac_check); + return NOT_GRANTED; + } + if (!i_attr_val1.mac_check) + return DO_NOT_CARE; + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + break; +#endif + +#if defined(CONFIG_RSBAC_MAC_NET_OBJ_PROT) + case T_NETTEMP: + return mac_check_role(owner, SR_security_officer); + + case T_NETOBJ: + /* test write access to target: get its sec_level */ + if (rsbac_get_attr(SW_MAC, + target, + tid, + A_remote_sec_level, + &i_attr_val1, TRUE)) { + rsbac_ds_get_error("rsbac_adf_request_mac", + A_remote_sec_level); + return NOT_GRANTED; + } + if (rsbac_get_attr(SW_MAC, + target, + tid, + A_remote_mac_categories, + &i_attr_val2, TRUE)) { + rsbac_ds_get_error("rsbac_adf_request_mac", + A_remote_mac_categories); + return NOT_GRANTED; + } + /* and perform auto-write without setting attributes */ + return (auto_write_attr(caller_pid, + target, + tid, + A_remote_sec_level, + A_remote_mac_categories, + FALSE)); +#endif + +#if defined(CONFIG_RSBAC_MAC_UM_PROT) + case T_USER: + case T_GROUP: + /* Security Officer? */ + return mac_check_role(owner, SR_security_officer); +#endif + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_MOVETO: + switch (target) { + case T_DIR: + /* Mode of created item is ignored! */ + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + default: + return DO_NOT_CARE; + } + + case R_WRITE_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + case T_IPC: + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + break; + case T_DEV: + /* Only check for devices with mac_check set */ + if (rsbac_get_attr(SW_MAC, + T_DEV, + tid, + A_mac_check, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error("rsbac_adf_request_mac", + A_mac_check); + return NOT_GRANTED; + } + if (!i_attr_val1.mac_check) + return DO_NOT_CARE; + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_SEND: + switch (target) { + case T_DEV: + /* Only check for devices with mac_check set */ + if (rsbac_get_attr(SW_MAC, + T_DEV, + tid, + A_mac_check, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error("rsbac_adf_request_mac", + A_mac_check); + return NOT_GRANTED; + } + if (!i_attr_val1.mac_check) + return DO_NOT_CARE; + /* and perform auto-write without setting attributes */ + return (auto_write(caller_pid, + target, tid, FALSE)); + + case T_UNIXSOCK: + return (auto_write(caller_pid, + target, tid, FALSE)); + +#if defined(CONFIG_RSBAC_MAC_NET_OBJ_PROT) + case T_NETOBJ: + /* and perform auto-read-write without setting attributes */ + return (auto_read_write_attr(caller_pid, + target, + tid, + A_remote_sec_level, + A_remote_mac_categories, + FALSE)); + +#endif + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_BIND: + case R_LISTEN: + switch (target) { + case T_UNIXSOCK: + return (auto_read(caller_pid, + target, tid, FALSE)); +#if defined(CONFIG_RSBAC_MAC_NET_OBJ_PROT) + case T_NETOBJ: + /* and perform auto-read-write without setting attributes */ + return (auto_read_write_attr(caller_pid, + target, + tid, + A_local_sec_level, + A_local_mac_categories, + FALSE)); + + /* all other cases are unknown */ +#endif + default: + return DO_NOT_CARE; + } + + case R_ACCEPT: + case R_CONNECT: + case R_RECEIVE: + switch (target) { + case T_UNIXSOCK: + return (auto_read_write(caller_pid, + target, tid, FALSE)); +#if defined(CONFIG_RSBAC_MAC_NET_OBJ_PROT) + case T_NETOBJ: + /* and perform auto-read-write without setting attributes */ + return (auto_read_write_attr(caller_pid, + target, + tid, + A_remote_sec_level, + A_remote_mac_categories, + FALSE)); +#endif + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + default: + return DO_NOT_CARE; + } + + return result; +} + + +/*****************************************************************************/ +/* If the request returned granted and the operation is performed, */ +/* the following function can be called by the AEF to get all aci set */ +/* correctly. For write accesses that are performed fully within the kernel, */ +/* this is usually not done to prevent extra calls, including R_CLOSE for */ +/* cleaning up. Because of this, the write boundary is not adjusted - there */ +/* is no user-level writing anyway... */ +/* The second instance of target specification is the new target, if one has */ +/* been created, otherwise its values are ignored. */ +/* On success, 0 is returned, and an error from rsbac/error.h otherwise. */ + +inline int rsbac_adf_set_attr_mac(enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + enum rsbac_adf_req_ret_t result = DO_NOT_CARE; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_attribute_value_t i_attr_val2; + union rsbac_attribute_value_t i_attr_val3; + union rsbac_attribute_value_t i_attr_val4; + union rsbac_attribute_value_t i_attr_val5; + union rsbac_attribute_value_t i_attr_val6; + union rsbac_attribute_value_t i_attr_val7; + union rsbac_attribute_value_t i_attr_val8; + union rsbac_attribute_value_t i_attr_val9; + rsbac_boolean_t inherit; + + switch (request) { + case R_APPEND_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + case T_IPC: + /* test write access to target: get its sec_level */ + if ((target == T_FILE) + || (target == T_FIFO) + ) + inherit = TRUE; + else + inherit = FALSE; + if (rsbac_get_attr(SW_MAC, + target, + tid, + A_security_level, + &i_attr_val1, inherit)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_security_level); + return (-RSBAC_EREADFAILED); + } + if (rsbac_get_attr(SW_MAC, + target, + tid, + A_mac_categories, + &i_attr_val2, inherit)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_categories); + return (-RSBAC_EREADFAILED); + } + /* and perform auto-write with setting attributes */ + result = auto_write(caller_pid, target, tid, TRUE); + if ((result == GRANTED) || (result == DO_NOT_CARE)) + return 0; + else + return (-RSBAC_EDECISIONMISMATCH); + break; + case T_DEV: + /* Only check for devices with mac_check set */ + if (rsbac_get_attr(SW_MAC, + T_DEV, + tid, + A_mac_check, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_check); + return (-RSBAC_EREADFAILED); + } + if (!i_attr_val1.mac_check) + return 0; + /* and perform auto-write with setting attributes */ + result = auto_write(caller_pid, target, tid, TRUE); + if ((result == GRANTED) || (result == DO_NOT_CARE)) + return 0; + else + return (-RSBAC_EDECISIONMISMATCH); + break; + /* all other cases are unknown */ + default: + return 0; + } + + case R_CHANGE_OWNER: + switch (target) { + /* Changing process owner affects access decisions, */ + /* so attributes have to be adjusted. */ + case T_PROCESS: + /* For target process there MUST be a new owner specified */ + if (attr != A_owner) + return (-RSBAC_EINVALIDATTR); + + /* Get owner-sec-level and mac_categories for new owner */ + i_tid.user = attr_val.owner; + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, + A_security_level, + &i_attr_val2, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_security_level); + return (-RSBAC_EREADFAILED); + } + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, + A_mac_categories, + &i_attr_val3, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_categories); + return (-RSBAC_EREADFAILED); + } + /* set owner-sec-level and mac_categories for process to new values */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + tid, + A_security_level, + i_attr_val2)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_categories, + i_attr_val3)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Get min_write_open and min_write_categories of process */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_min_write_open, + &i_attr_val4, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_min_write_open); + return (-RSBAC_EREADFAILED); + } + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_min_write_categories, + &i_attr_val5, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_min_write_categories); + return (-RSBAC_EREADFAILED); + } + /* adjust min_write_open and min_write_categories, if too high */ + if (i_attr_val2.security_level < + i_attr_val4.min_write_open) { + i_attr_val4.min_write_open = + i_attr_val2.security_level; + if (rsbac_set_attr + (SW_MAC, T_PROCESS, tid, A_min_write_open, + i_attr_val4)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", + A_none); + return (-RSBAC_EWRITEFAILED); + } + } + /* does process have categories in min_write + * that the new owner has not? */ + /* If yes, throw them out. */ + if ((i_attr_val3.mac_categories & i_attr_val5. + mac_categories) + != i_attr_val5.mac_categories) { + i_attr_val5.mac_categories &= + i_attr_val3.mac_categories; + if (rsbac_set_attr + (SW_MAC, T_PROCESS, tid, + A_min_write_categories, + i_attr_val5)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", + A_none); + return (-RSBAC_EWRITEFAILED); + } + } + /* Get owner-initial-sec-level and + * mac_initial_categories for new owner */ + /* These values will be adjusted by + * max_read / min_write and then used as */ + /* new current level/categories. */ + i_tid.user = owner; + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, + A_initial_security_level, + &i_attr_val6, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_initial_security_level); + return (-RSBAC_EREADFAILED); + } + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + tid, + A_initial_security_level, + i_attr_val6)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_initial_security_level); + return (-RSBAC_EWRITEFAILED); + } +#if 0 + /* restrict current_level to be a maximum of min_write */ + if (i_attr_val6.security_level > + i_attr_val4.min_write_open) + i_attr_val6.security_level = + i_attr_val4.min_write_open; +#endif + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, + A_mac_initial_categories, + &i_attr_val7, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_initial_categories); + return (-RSBAC_EREADFAILED); + } + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_initial_categories, + i_attr_val7)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_mac_initial_categories); + return (-RSBAC_EWRITEFAILED); + } +#if 0 + /* restrict current_categories to be a maximum of min_write */ + if ((i_attr_val7.mac_categories & i_attr_val5. + mac_categories) != i_attr_val7.mac_categories) + i_attr_val7.mac_categories &= + i_attr_val5.mac_categories; +#endif + /* Get owner-min-sec-level and mac_min_categories for new owner */ + i_tid.user = owner; + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, + A_min_security_level, + &i_attr_val8, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_min_security_level); + return (-RSBAC_EREADFAILED); + } + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, + A_mac_min_categories, + &i_attr_val9, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_min_categories); + return (-RSBAC_EREADFAILED); + } + /* set owner-sec-level and mac_categories for process to new values */ + /* owner is set by main dispatcher! */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + tid, + A_min_security_level, + i_attr_val8)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_min_categories, + i_attr_val9)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Get max_read_open and max_read_categories of process */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_max_read_open, + &i_attr_val4, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_max_read_open); + return (-RSBAC_EREADFAILED); + } + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_max_read_categories, + &i_attr_val5, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_max_read_categories); + return (-RSBAC_EREADFAILED); + } + /* adjust max_read_open and max_read_categories, if too low */ + if (i_attr_val8.security_level > + i_attr_val4.max_read_open) { + i_attr_val4.max_read_open = + i_attr_val8.security_level; + if (rsbac_set_attr + (SW_MAC, T_PROCESS, tid, A_max_read_open, + i_attr_val4)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", + A_none); + return (-RSBAC_EWRITEFAILED); + } + } +#if 0 + /* adjust current sec level to a minimum of max_read */ + if (i_attr_val6.security_level < + i_attr_val4.max_read_open) + i_attr_val6.security_level = + i_attr_val4.max_read_open; +#endif + /* but never set it over new max_level or under new min_level */ + if (i_attr_val6.security_level > + i_attr_val2.security_level) + i_attr_val6.security_level = + i_attr_val2.security_level; + else if (i_attr_val6.security_level < + i_attr_val8.security_level) + i_attr_val6.security_level = + i_attr_val8.security_level; + if (rsbac_set_attr + (SW_MAC, T_PROCESS, tid, A_current_sec_level, + i_attr_val6)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + + /* does new owner have categories in min_categories that the process max_read + has not? */ + /* If yes, add them. */ + if ((i_attr_val9.mac_categories & i_attr_val5. + mac_categories) + != i_attr_val9.mac_categories) { + i_attr_val5.mac_categories |= + i_attr_val9.mac_categories; + if (rsbac_set_attr + (SW_MAC, T_PROCESS, tid, + A_max_read_categories, i_attr_val5)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", + A_none); + return (-RSBAC_EWRITEFAILED); + } + } +#if 0 + /* adjust current categories to include all from max_read (from initial) */ + if ((i_attr_val7.mac_categories & i_attr_val5. + mac_categories) != i_attr_val5.mac_categories) + i_attr_val7.mac_categories |= + i_attr_val5.mac_categories; +#endif + /* but never set it over new max_cats or under new min_cats */ + if ((i_attr_val7.mac_categories & i_attr_val3. + mac_categories) != i_attr_val7.mac_categories) + i_attr_val7.mac_categories &= + i_attr_val3.mac_categories; + else if ((i_attr_val7.mac_categories & i_attr_val9. + mac_categories) != + i_attr_val9.mac_categories) + i_attr_val7.mac_categories |= + i_attr_val9.mac_categories; + if (rsbac_set_attr + (SW_MAC, T_PROCESS, tid, A_mac_curr_categories, + i_attr_val7)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + + /* Get mac_user_flags from user */ + i_tid.user = attr_val.owner; + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, + A_mac_user_flags, + &i_attr_val3, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_user_flags); + return (-RSBAC_EREADFAILED); + } + i_attr_val1.mac_process_flags = + i_attr_val3.mac_user_flags; + /* adjust flags - first get old process flags */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_process_flags, + &i_attr_val2, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_process_flags); + return (-RSBAC_EREADFAILED); + } + if ((i_attr_val2. + mac_process_flags & MAC_program_auto) + && (i_attr_val3. + mac_user_flags & MAC_allow_auto) + ) + i_attr_val1.mac_process_flags |= MAC_auto; + + i_attr_val1.mac_process_flags &= RSBAC_MAC_P_FLAGS; + + if (!(i_attr_val1.mac_process_flags & MAC_trusted)) { + if (rsbac_mac_p_truset_member + (caller_pid, owner)) + i_attr_val1.mac_process_flags |= + MAC_trusted; + } + /* Set mac_process_flags on process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_process_flags, + i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* OK, we are ready */ + return 0; + + /* We do not care about other cases here */ + default: + return 0; + } + + case R_CLONE: + if (target == T_PROCESS) { + /* Get owner-sec-level from first process */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_security_level, + &i_attr_val2, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_security_level); + return (-RSBAC_EREADFAILED); + } + /* Get current-sec-level from first process... */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_current_sec_level, + &i_attr_val3, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_current_sec_level); + return (-RSBAC_EREADFAILED); + } + /* Get min_write_open from first process */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_min_write_open, + &i_attr_val4, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_min_write_open); + return (-RSBAC_EREADFAILED); + } + /* Get max_read_open from first process */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_max_read_open, + &i_attr_val5, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_max_read_open); + return (-RSBAC_EREADFAILED); + } + /* Get mac_process_flags from first process */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_process_flags, + &i_attr_val7, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_process_flags); + return (-RSBAC_EREADFAILED); + } + /* Set owner_sec_level for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_security_level, + i_attr_val2)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Set current_sec_level for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_current_sec_level, + i_attr_val3)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Set min_write_open for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_min_write_open, + i_attr_val4)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Set max_read_open for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_max_read_open, i_attr_val5)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Set mac_process_flags for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_mac_process_flags, + i_attr_val7)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + + /* Get mac_categories from first process */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_categories, + &i_attr_val2, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_categories); + return (-RSBAC_EREADFAILED); + } + /* Get mac_curr_categories from first process... */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_curr_categories, + &i_attr_val3, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_curr_categories); + return (-RSBAC_EREADFAILED); + } + /* Get min_write_categories from first process */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_min_write_categories, + &i_attr_val4, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_min_write_categories); + return (-RSBAC_EREADFAILED); + } + /* Get max_read_categories from first process */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_max_read_categories, + &i_attr_val5, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_max_read_categories); + return (-RSBAC_EREADFAILED); + } + /* Get initial_sec_level from first process */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_initial_security_level, + &i_attr_val6, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_initial_security_level); + return (-RSBAC_EREADFAILED); + } + /* Get initial_categories from first process */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_initial_categories, + &i_attr_val7, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_initial_categories); + return (-RSBAC_EREADFAILED); + } + /* Set mac_categories for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_mac_categories, + i_attr_val2)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Set mac_curr_categories for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_mac_curr_categories, + i_attr_val3)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Set min_write_categories for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_min_write_categories, + i_attr_val4)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Set max_read_categories for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_max_read_categories, + i_attr_val5)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Set initial_security_level for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_initial_security_level, + i_attr_val6)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Set initial_categories for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_mac_initial_categories, + i_attr_val7)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Get owner-min_sec-level/cat from first process */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_min_security_level, + &i_attr_val2, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_min_security_level); + return (-RSBAC_EREADFAILED); + } + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_min_categories, + &i_attr_val3, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_min_categories); + return (-RSBAC_EREADFAILED); + } + /* Set min_security_level for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_min_security_level, + i_attr_val2)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Set min_categories for new process */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + new_tid, + A_mac_min_categories, + i_attr_val3)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + if (rsbac_mac_copy_pp_truset + (tid.process, new_tid.process)) { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_mac(): rsbac_mac_copy_pp_truset() returned error!\n"); + return (-RSBAC_EWRITEFAILED); + } + return 0; + } else + return 0; + + case R_CREATE: + switch (target) { + /* Creating dir or (pseudo) file IN target dir! */ + case T_DIR: + /* Mode of created item is ignored! */ + /* and perform auto-write without(!) + * setting of attributes - no need */ + /* -> decision consistency check only */ + /* only check, if not MAC_LIGHT */ +#ifndef CONFIG_RSBAC_MAC_LIGHT + result = auto_write(caller_pid, + target, tid, FALSE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); +#endif + /* test write access to target: get its sec_level */ + if (rsbac_get_attr(SW_MAC, + T_DIR, + tid, + A_security_level, + &i_attr_val1, TRUE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_security_level); + return (-RSBAC_EREADFAILED); + } + if (rsbac_get_attr(SW_MAC, + T_DIR, + tid, + A_mac_categories, + &i_attr_val2, TRUE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_categories); + return (-RSBAC_EREADFAILED); + } + /* Get current_sec_level from process (initialized to owner_sec_level)... */ + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_current_sec_level, + &i_attr_val3, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_current_sec_level); + return (-RSBAC_EREADFAILED); + } +#ifdef CONFIG_RSBAC_MAC_SMART_INHERIT + /* Only set, if different than inherited value */ + if (i_attr_val3.security_level != + i_attr_val1.security_level) +#endif + /* Set security-level for new item */ + if (rsbac_set_attr(SW_MAC, + new_target, + new_tid, + A_security_level, + i_attr_val3)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", + A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Get current_categories from process (initialized to owner_categories)... */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_mac_curr_categories, + &i_attr_val3, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_curr_categories); + return (-RSBAC_EREADFAILED); + } +#ifdef CONFIG_RSBAC_MAC_SMART_INHERIT + /* Only set, if different than inherited value */ + if (i_attr_val3.mac_categories != + i_attr_val2.mac_categories) +#endif + /* Set mac_categories for new item */ + if (rsbac_set_attr(SW_MAC, + new_target, + new_tid, + A_mac_categories, + i_attr_val3)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", + A_none); + return (-RSBAC_EWRITEFAILED); + } + return 0; + break; + + case T_IPC: + i_tid.process = caller_pid; + /* Get current-sec-level from process... */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_current_sec_level, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_current_sec_level); + return (-RSBAC_EREADFAILED); + } + /* Set security-level for this ipc item */ + if (rsbac_set_attr(SW_MAC, + T_IPC, + tid, + A_security_level, + i_attr_val1)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Get mac_curr_categories from process... */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_mac_curr_categories, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_curr_categories); + return (-RSBAC_EREADFAILED); + } + /* Set curr_categories for new item */ + if (rsbac_set_attr(SW_MAC, + T_IPC, + tid, + A_mac_categories, + i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + return 0; + break; + +#ifdef CONFIG_RSBAC_MAC_NET_OBJ_PROT + case T_NETOBJ: + i_tid.process = caller_pid; + /* Get current-sec-level from process... */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_current_sec_level, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_current_sec_level); + return (-RSBAC_EREADFAILED); + } + /* Set local security-level for this netobj item */ + if (rsbac_set_attr(SW_MAC, + target, + tid, + A_local_sec_level, + i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* Get mac_curr_categories from process... */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_mac_curr_categories, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_curr_categories); + return (-RSBAC_EREADFAILED); + } + /* Set local curr_categories for new item */ + if (rsbac_set_attr(SW_MAC, + target, + tid, + A_local_mac_categories, + i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + return 0; + break; +#endif + + /* all other cases are unknown */ + default: + return 0; + } + + /* removal of targets is done in main adf dispatcher! */ + case R_DELETE: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: + /* and perform auto-write without(!) setting of attributes */ + /* - no information flow apart from missing file */ + /* -> decision consistency check only */ + result = auto_write(caller_pid, + target, tid, FALSE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + else + return 0; + /* all other cases are unknown */ + default: + return 0; + } + + case R_EXECUTE: + switch (target) { + case T_FILE: + /* copy trusted user list from file to process */ + if (rsbac_mac_copy_fp_truset(tid.file, caller_pid)) { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_mac(): rsbac_mac_copy_fp_truset() returned error!\n"); + return (-RSBAC_EWRITEFAILED); + } + /* perform auto-read with setting of attributes */ + result = auto_read(caller_pid, target, tid, TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + + /* reset current_sec_level, mac_auto, min_write_open */ + /* and max_read_open for process */ + i_tid.process = caller_pid; + +#ifdef CONFIG_RSBAC_MAC_RESET_CURR + /* First, set current_sec_level and min_write_open to process owner's initial and seclevel */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_initial_security_level, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_initial_security_level); + return (-RSBAC_EREADFAILED); + } + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_mac_initial_categories, + &i_attr_val2, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_initial_categories); + return (-RSBAC_EREADFAILED); + } + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + i_tid, + A_current_sec_level, + i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + i_tid, + A_mac_curr_categories, + i_attr_val2)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } +#endif +#if 0 + /* Now, set min_write_open to process owner's seclevel */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_security_level, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_security_level); + return (-RSBAC_EREADFAILED); + } +#endif + i_attr_val1.min_write_open = SL_max; + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + i_tid, + A_min_write_open, + i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } +#if 0 + /* Next, set min_write_categories to process owner's mac_categories */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_mac_categories, + &i_attr_val2, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_categories); + return (-RSBAC_EREADFAILED); + } +#endif + i_attr_val2.mac_categories = + RSBAC_MAC_MAX_CAT_VECTOR; + if (rsbac_set_attr + (SW_MAC, T_PROCESS, i_tid, A_min_write_categories, + i_attr_val2)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* reset max_read boundary */ +#if 0 + /* Get owner-min-sec-level and mac_min_categories for owner */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_min_security_level, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_min_security_level); + return (-RSBAC_EREADFAILED); + } + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_mac_min_categories, + &i_attr_val2, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_min_categories); + return (-RSBAC_EREADFAILED); + } +#endif + i_attr_val1.max_read_open = SL_min; + i_attr_val2.mac_categories = + RSBAC_MAC_MIN_CAT_VECTOR; + if (rsbac_set_attr + (SW_MAC, T_PROCESS, i_tid, A_max_read_open, + i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* reset category max_read boundary */ + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + i_tid, + A_max_read_categories, + i_attr_val2)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + /* set flags */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + i_tid, + A_mac_process_flags, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_process_flags); + return (-RSBAC_EREADFAILED); + } + if (rsbac_get_attr(SW_MAC, + target, + tid, + A_mac_auto, + &i_attr_val2, TRUE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_auto); + return (-RSBAC_EREADFAILED); + } + if (i_attr_val2.mac_auto) { + i_attr_val1.mac_process_flags |= + MAC_program_auto; + i_tid.user = owner; + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, + A_mac_user_flags, + &i_attr_val2, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", + A_mac_user_flags); + return (-RSBAC_EREADFAILED); + } + if (i_attr_val2. + mac_user_flags & MAC_allow_auto) + i_attr_val1.mac_process_flags |= + MAC_auto; + else + i_attr_val1.mac_process_flags &= + ~MAC_auto; + i_tid.process = caller_pid; + } else { + i_attr_val1.mac_process_flags &= + ~MAC_program_auto; + i_attr_val1.mac_process_flags &= ~MAC_auto; + } + if (rsbac_get_attr(SW_MAC, + T_FILE, + tid, + A_mac_prop_trusted, + &i_attr_val3, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_prop_trusted); + return (-RSBAC_EREADFAILED); + } + if (!(i_attr_val3.mac_prop_trusted) + || !(i_attr_val1. + mac_process_flags & MAC_trusted) + ) { + if (rsbac_mac_p_truset_member + (caller_pid, owner)) + i_attr_val1.mac_process_flags |= + MAC_trusted; + else { + i_tid.user = owner; + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, + A_mac_user_flags, + &i_attr_val2, + FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", + A_mac_user_flags); + return(-RSBAC_EREADFAILED); + } + if (i_attr_val2. + mac_user_flags & MAC_trusted) + i_attr_val1. + mac_process_flags |= + MAC_trusted; + else + i_attr_val1. + mac_process_flags &= + ~MAC_trusted; + i_tid.process = caller_pid; + } + } + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + i_tid, + A_mac_process_flags, + i_attr_val1)) { + rsbac_ds_set_error + ("rsbac_adf_set_attr_mac", A_none); + return (-RSBAC_EWRITEFAILED); + } + return 0; + + /* all other cases */ + default: + return 0; + } + + case R_MOUNT: + switch (target) { + case T_DIR: + case T_DEV: + /* and perform auto-read(-write) with setting of attributes */ + if ((target == T_DEV) + && (attr == A_mode) + && (attr_val.mode & MS_RDONLY)) + result = auto_read(caller_pid, + target, tid, TRUE); + else + result = auto_read_write(caller_pid, + target, + tid, TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + else + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + + case R_READ: + switch (target) { + case T_DIR: +#ifdef CONFIG_RSBAC_RW + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + case T_IPC: +#endif + /* and perform auto-read with setting of attributes */ + result = auto_read(caller_pid, target, tid, TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; + +#ifdef CONFIG_RSBAC_RW + case T_DEV: + /* Only check for devices with mac_check set */ + if (rsbac_get_attr(SW_MAC, + T_DEV, + tid, + A_mac_check, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_check); + return (-RSBAC_EREADFAILED); + } + if (!i_attr_val1.mac_check) + return 0; + /* and perform auto-read with setting of attributes */ + result = auto_read(caller_pid, target, tid, TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; +#endif + +#ifdef CONFIG_RSBAC_MAC_NET_OBJ_PROT + case T_NETOBJ: + /* and perform auto-read with setting of attributes */ + result = auto_read_attr(caller_pid, + target, + tid, + A_remote_sec_level, + A_remote_mac_categories, + TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; +#endif + + /* all other cases are unknown */ + default: + return 0; + } + + case R_READ_OPEN: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_UNIXSOCK: + case T_IPC: + /* and perform auto-read with setting attributes */ + result = auto_read(caller_pid, target, tid, TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; + + case T_DEV: + /* Only check for devices with mac_check set */ + if (rsbac_get_attr(SW_MAC, + T_DEV, + tid, + A_mac_check, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_check); + return (-RSBAC_EREADFAILED); + } + if (!i_attr_val1.mac_check) + return 0; + /* and perform auto-read with setting attributes */ + result = auto_read(caller_pid, target, tid, TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + + case R_READ_WRITE_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + case T_IPC: + /* and perform auto-read-write without setting attributes */ + result = auto_read_write(caller_pid, + target, tid, TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; + + case T_DEV: + /* Only check for devices with mac_check set */ + if (rsbac_get_attr(SW_MAC, + T_DEV, + tid, + A_mac_check, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_check); + return (-RSBAC_EREADFAILED); + } + if (!i_attr_val1.mac_check) + return 0; + /* and perform auto-read-write with setting of attributes */ + result = auto_read_write(caller_pid, + target, tid, TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; + /* all other cases are unknown */ + default: + return 0; + } + + case R_SEARCH: + switch (target) { + case T_DIR: + case T_SYMLINK: + /* and perform auto-read with setting of attributes */ + result = auto_read(caller_pid, target, tid, TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; + /* all other cases are unknown */ + default: + return 0; + } + + case R_TRACE: + switch (target) { + case T_PROCESS: + /* and perform auto-read-write with setting attributes */ + result = auto_read_write_attr(caller_pid, + target, + tid, + A_current_sec_level, + A_mac_curr_categories, + TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + + case R_WRITE: + case R_WRITE_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + case T_IPC: + /* and perform auto-write with setting attributes */ + result = auto_write(caller_pid, target, tid, TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; + + case T_DEV: + /* Only check for devices with mac_check set */ + if (rsbac_get_attr(SW_MAC, + T_DEV, + tid, + A_mac_check, + &i_attr_val1, FALSE)) { + rsbac_ds_get_error + ("rsbac_adf_set_attr_mac", A_mac_check); + return (-RSBAC_EREADFAILED); + } + if (!i_attr_val1.mac_check) + return 0; + /* and perform auto-write with setting attributes */ + result = auto_write(caller_pid, target, tid, TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; + +#ifdef CONFIG_RSBAC_MAC_NET_OBJ_PROT + case T_NETOBJ: + /* and perform auto-write with setting attributes */ + result = auto_write_attr(caller_pid, + target, + tid, + A_remote_sec_level, + A_remote_mac_categories, + TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; +#endif + + /* all other cases are unknown */ + default: + return 0; + } + +#ifdef CONFIG_RSBAC_MAC_NET_OBJ_PROT + case R_BIND: + case R_LISTEN: + switch (target) { + case T_NETOBJ: + /* and perform auto-write with setting attributes */ + result = auto_write_attr(caller_pid, + target, + tid, + A_local_sec_level, + A_local_mac_categories, + TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + + case R_ACCEPT: + case R_CONNECT: + case R_SEND: + case R_RECEIVE: + switch (target) { + case T_NETOBJ: + /* and perform auto-write with setting attributes */ + result = auto_write_attr(caller_pid, + target, + tid, + A_remote_sec_level, + A_remote_mac_categories, + TRUE); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return (-RSBAC_EDECISIONMISMATCH); + return 0; + + /* all other cases are unknown */ + default: + return 0; + } +#endif + default: + return 0; + } + + return 0; +} diff --git a/rsbac/adf/mac/mac_syscalls.c b/rsbac/adf/mac/mac_syscalls.c new file mode 100644 index 000000000000..3ceb68651db9 --- /dev/null +++ b/rsbac/adf/mac/mac_syscalls.c @@ -0,0 +1,694 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - Mandatory Access Control */ +/* File: rsbac/adf/mac/syscalls.c */ +/* */ +/* Author and (c) 1999-2016: Amon Ott */ +/* */ +/* Last modified: 04/Apr/2016 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +static int + mac_sys_check_role(enum rsbac_system_role_t role) + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + i_tid.user = __kuid_val(current_uid()); + if (rsbac_get_attr(SW_MAC, + T_USER, + i_tid, + A_mac_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("mac_sys_check_role", A_mac_role); + return -EPERM; + } + /* if correct role, then grant */ + if (i_attr_val1.system_role == role) + return 0; + else + return -EPERM; + } + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +/*****************************************************************************/ +/* This function allows processes to set their own current security level */ +/* via sys_rsbac_mac_set_curr_seclevel() system call. */ +/* The level must keep within the min_write_open/max_read_open-boundary and */ +/* must not be greater than owner_sec_level. Setting current_sec_level by */ +/* this function also turns off auto-levelling via mac_auto. */ + +int rsbac_mac_set_curr_level(rsbac_security_level_t level, + rsbac_mac_category_vector_t categories) + { + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val1; + rsbac_mac_process_flags_t flags; + + if( (level > SL_max) + && (level != SL_none) + ) + return -RSBAC_EINVALIDVALUE; + + tid.process = task_pid(current); + + /* check flags */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_process_flags, + &attr_val1, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_set_curr_level", A_mac_process_flags); + return(-RSBAC_EREADFAILED); + } + flags = attr_val1.mac_process_flags; + if( !(flags & MAC_auto) + && !(flags & MAC_trusted) + && !(flags & MAC_override) + ) + { + rsbac_printk(KERN_INFO + "rsbac_mac_set_curr_level(): uid %u, pid %u(%s): no auto, trusted or override -> not granted \n", + __kuid_val(current_uid()), + current->pid, + current->comm); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MAC] + #endif + ) + #endif + return -EPERM; + } + + /* override allows full range */ + if(!(flags & MAC_override)) + { + if(level != SL_none) + { + /* get maximum security level */ + tid.process = task_pid(current); + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_security_level, + &attr_val1, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_set_curr_level", A_security_level); + return(-RSBAC_EREADFAILED); + } + /* if level is too high -> error */ + if (level > attr_val1.security_level) + { + rsbac_printk(KERN_INFO + "rsbac_mac_set_curr_level(): uid %u, pid %u(%s): requested level %u over max level %u, no override -> not granted \n", + __kuid_val(current_uid()), + current->pid, + current->comm, + level, + attr_val1.security_level); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MAC] + #endif + ) + #endif + return -EPERM; + } + /* get minimum security level */ + tid.process = task_pid(current); + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_min_security_level, + &attr_val1, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_set_curr_level", A_min_security_level); + return(-RSBAC_EREADFAILED); + } + /* if level is too low -> error */ + if (level < attr_val1.security_level) + { + rsbac_printk(KERN_INFO + "rsbac_mac_set_curr_level(): uid %u, pid %u(%s): requested level %u under min level %u, no override -> not granted \n", + __kuid_val(current_uid()), + current->pid, + current->comm, + level, + attr_val1.security_level); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MAC] + #endif + ) + #endif + return -EPERM; + } + + /* auto needed? -> stay inside boundaries */ + if(!(flags & MAC_trusted)) + { + /* check against upper/write boundary */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_min_write_open, + &attr_val1, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_set_curr_level", A_min_write_open); + return(-RSBAC_EREADFAILED); + } + if (level > attr_val1.min_write_open) + { + rsbac_printk(KERN_INFO + "rsbac_mac_set_curr_level(): uid %u, pid %u(%s): requested level %u over min_write_open %u, no override or trusted -> not granted \n", + __kuid_val(current_uid()), + current->pid, + current->comm, + level, + attr_val1.min_write_open); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MAC] + #endif + ) + #endif + return -EPERM; + } + + /* check against lower/read boundary */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_max_read_open, + &attr_val1, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_set_curr_level", A_max_read_open); + return(-RSBAC_EREADFAILED); + } + if (level < attr_val1.max_read_open) + return -EPERM; + } + } + if(categories != RSBAC_MAC_MIN_CAT_VECTOR) + { + /* get maximum categories */ + tid.process = task_pid(current); + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_categories, + &attr_val1, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_set_curr_level", A_mac_categories); + return(-RSBAC_EREADFAILED); + } + /* if categories are no subset -> error */ + if ((categories & attr_val1.mac_categories) != categories) + { + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp) + { + char * tmp2 = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp2) + { + rsbac_printk(KERN_INFO + "rsbac_mac_set_curr_level(): uid %u, pid %u(%s): requested categories %s over max categories %s, no override -> not granted \n", + __kuid_val(current_uid()), + current->pid, + current->comm, + u64tostrmac(tmp, categories), + u64tostrmac(tmp2, attr_val1.mac_categories)); + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MAC] + #endif + ) + #endif + return -EPERM; + } + /* get minimum categories */ + tid.process = task_pid(current); + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_min_categories, + &attr_val1, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_set_curr_level", A_mac_min_categories); + return(-RSBAC_EREADFAILED); + } + /* if level is too low -> error */ + if ((categories & attr_val1.mac_categories) != attr_val1.mac_categories) + { + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp) + { + char * tmp2 = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp2) + { + rsbac_printk(KERN_INFO + "rsbac_mac_set_curr_level(): uid %u, pid %u(%s): requested categories %s under min categories %s, no override -> not granted \n", + __kuid_val(current_uid()), + current->pid, + current->comm, + u64tostrmac(tmp, categories), + u64tostrmac(tmp2, attr_val1.mac_categories)); + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MAC] + #endif + ) + #endif + return -EPERM; + } + + /* auto needed? -> stay inside boundaries */ + if(!(flags & MAC_trusted)) + { + /* check against upper/write boundary */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_min_write_categories, + &attr_val1, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_set_curr_level", A_min_write_categories); + return(-RSBAC_EREADFAILED); + } + if ((categories & attr_val1.mac_categories) != categories) + { + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp) + { + char * tmp2 = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp2) + { + rsbac_printk(KERN_INFO + "rsbac_mac_set_curr_level(): uid %u, pid %u(%s): requested categories %s over min_write categories %s, no override or trusted -> not granted \n", + __kuid_val(current_uid()), + current->pid, + current->comm, + u64tostrmac(tmp, categories), + u64tostrmac(tmp2, attr_val1.mac_categories)); + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MAC] + #endif + ) + #endif + return -EPERM; + } + /* check against lower/read boundary */ + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_max_read_categories, + &attr_val1, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_set_curr_level", A_max_read_categories); + return(-RSBAC_EREADFAILED); + } + if ((categories & attr_val1.mac_categories) != attr_val1.mac_categories) + { + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp) + { + char * tmp2 = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp2) + { + rsbac_printk(KERN_INFO + "rsbac_mac_set_curr_level(): uid %u, pid %u(%s): requested categories %s under max_read categories %s, no override or trusted -> not granted \n", + __kuid_val(current_uid()), + current->pid, + current->comm, + u64tostrmac(tmp, categories), + u64tostrmac(tmp2, attr_val1.mac_categories)); + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MAC] + #endif + ) + #endif + return -EPERM; + } + } + } + } + + /* OK, checks passed: set values */ + if(level != SL_none) + { + attr_val1.current_sec_level = level; + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + tid, + A_current_sec_level, + attr_val1)) + { /* failed! */ + rsbac_ds_set_error("rsbac_mac_set_curr_level", A_none); + return(-RSBAC_EWRITEFAILED); + } + } + if(categories != RSBAC_MAC_MIN_CAT_VECTOR) + { + attr_val1.mac_categories = categories; + if (rsbac_set_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_curr_categories, + attr_val1)) + { /* failed! */ + rsbac_ds_set_error("rsbac_mac_set_curr_level", A_none); + return(-RSBAC_EWRITEFAILED); + } + } + return(0); + } + +/* getting own levels as well - no restrictions */ +int rsbac_mac_get_curr_level(rsbac_security_level_t * level_p, + rsbac_mac_category_vector_t * categories_p) + { + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val; + + tid.process = task_pid(current); + if(level_p) + { + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_current_sec_level, + &attr_val, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_get_curr_level", A_current_sec_level); + return(-RSBAC_EREADFAILED); + } + *level_p = attr_val.current_sec_level; + } + if(categories_p) + { + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_curr_categories, + &attr_val, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_get_curr_level", A_mac_curr_categories); + return(-RSBAC_EREADFAILED); + } + *categories_p = attr_val.mac_categories; + } + return 0; + } + +int rsbac_mac_get_max_level(rsbac_security_level_t * level_p, + rsbac_mac_category_vector_t * categories_p) + { + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val; + + tid.process = task_pid(current); + if(level_p) + { + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_security_level, + &attr_val, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_get_max_level", A_security_level); + return(-RSBAC_EREADFAILED); + } + *level_p = attr_val.security_level; + } + if(categories_p) + { + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_categories, + &attr_val, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_get_max_level", A_mac_categories); + return(-RSBAC_EREADFAILED); + } + *categories_p = attr_val.mac_categories; + } + return 0; + } + + +int rsbac_mac_get_min_level(rsbac_security_level_t * level_p, + rsbac_mac_category_vector_t * categories_p) + { + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val; + + tid.process = task_pid(current); + if(level_p) + { + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_min_security_level, + &attr_val, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_get_min_level", A_min_security_level); + return(-RSBAC_EREADFAILED); + } + *level_p = attr_val.security_level; + } + if(categories_p) + { + if (rsbac_get_attr(SW_MAC, + T_PROCESS, + tid, + A_mac_min_categories, + &attr_val, + FALSE)) + { /* failed! */ + rsbac_ds_get_error("rsbac_mac_get_min_level", A_mac_min_categories); + return(-RSBAC_EREADFAILED); + } + *categories_p = attr_val.mac_categories; + } + return 0; + } + +int rsbac_mac_add_p_tru( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + rsbac_uid_t uid, + rsbac_time_t ttl) + { +/* check only in non-maint mode */ +#ifdef CONFIG_RSBAC_SWITCH_MAC + if(rsbac_switch_mac) +#endif + { + if(mac_sys_check_role(SR_security_officer)) + { + rsbac_printk(KERN_INFO + "rsbac_mac_add_p_tru(): adding MAC trusted user %u to process %u denied for process %u!\n", + uid, + pid, + current->pid); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MAC] + #endif + ) + #endif + return -EPERM; + } + } + + /* OK, check passed. Add the truability. */ + if(rsbac_mac_add_to_p_truset(ta_number, pid, uid, ttl)) + { + rsbac_printk(KERN_WARNING + "rsbac_mac_add_p_tru(): rsbac_mac_add_to_p_truset() returned error!\n"); + return(-RSBAC_EWRITEFAILED); + } + return 0; + } + +int rsbac_mac_remove_p_tru( + rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + rsbac_uid_t uid) + { +/* check only in non-maint mode */ +#ifdef CONFIG_RSBAC_SWITCH_MAC + if(rsbac_switch_mac) +#endif + { + if(mac_sys_check_role(SR_security_officer)) + { + rsbac_printk(KERN_INFO + "rsbac_mac_remove_p_tru(): removing MAC trusted user %u from process %u denied for process %u!\n", + uid, + pid, + current->pid); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MAC] + #endif + ) + #endif + return -EPERM; + } + } + /* OK, check passed. Try to remove the trusted user */ + return(rsbac_mac_remove_from_p_truset(ta_number, pid, uid)); + } + +int rsbac_mac_add_f_tru( + rsbac_list_ta_number_t ta_number, + rsbac_mac_file_t file, + rsbac_uid_t uid, + rsbac_time_t ttl) + { +#ifdef CONFIG_RSBAC_SWITCH_MAC + if(rsbac_switch_mac) +#endif + { + if(mac_sys_check_role(SR_security_officer)) + { + rsbac_printk(KERN_INFO + "rsbac_mac_add_f_tru(): adding MAC trusted user %u to file %u on device %02u:%02u denied for process %u!\n", + uid, + file.inode, + MAJOR(file.device), + MINOR(file.device), + current->pid); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MAC] + #endif + ) + #endif + return -EPERM; + } + } + + if(rsbac_mac_add_to_f_truset(ta_number, file, uid, ttl)) + { + rsbac_printk(KERN_WARNING + "rsbac_mac_add_f_tru(): rsbac_mac_add_to_f_truset() returned error!\n"); + return(-RSBAC_EWRITEFAILED); + } + return 0; + } + +int rsbac_mac_remove_f_tru( + rsbac_list_ta_number_t ta_number, + rsbac_mac_file_t file, + rsbac_uid_t uid) + { +#ifdef CONFIG_RSBAC_SWITCH_MAC + if(rsbac_switch_mac) +#endif + { + if(mac_sys_check_role(SR_security_officer)) + { + rsbac_printk(KERN_INFO + "rsbac_mac_remove_f_tru(): removing MAC trusted user %u from file %u on device %02u:%02u denied for process %u!\n", + uid, + file.inode, + MAJOR(file.device), + MINOR(file.device), + current->pid); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_MAC] + #endif + ) + #endif + return -EPERM; + } + } + + return(rsbac_mac_remove_from_f_truset(ta_number, file, uid)); + } + + +/* end of rsbac/adf/mac/syscalls.c */ diff --git a/rsbac/adf/pax/Makefile b/rsbac/adf/pax/Makefile new file mode 100644 index 000000000000..14181cfc9eaa --- /dev/null +++ b/rsbac/adf/pax/Makefile @@ -0,0 +1,9 @@ +# +# File: rsbac/adf/pax/Makefile +# +# Makefile for the Linux rsbac pax decision module. +# +# Author and (c) 1999-2012 Amon Ott +# + +obj-y := pax_main.o diff --git a/rsbac/adf/pax/pax_main.c b/rsbac/adf/pax/pax_main.c new file mode 100644 index 000000000000..eb19cb74c850 --- /dev/null +++ b/rsbac/adf/pax/pax_main.c @@ -0,0 +1,244 @@ +/**************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - PAX */ +/* File: rsbac/adf/pax/pax_main.c */ +/* */ +/* Author and (c) 1999-2016: Amon Ott */ +/* */ +/* Last modified: 01/Aug/2016 */ +/**************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +/**** PaX set flags func ****/ +#if defined(CONFIG_RSBAC_PAX) && (defined(CONFIG_PAX_HAVE_ACL_FLAGS) || defined(CONFIG_PAX_HOOK_ACL_FLAGS)) + +#include + +#if defined(CONFIG_PAX_HAVE_ACL_FLAGS) +void pax_set_initial_flags(struct linux_binprm * bprm) +#else +void rsbac_pax_set_flags_func(struct linux_binprm * bprm) +#endif + { + int err; + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val; + + if(!rsbac_is_initialized()) + return; + tid.file.device = bprm->file->f_path.dentry->d_sb->s_dev; + tid.file.inode = bprm->file->f_path.dentry->d_inode->i_ino; + tid.file.dentry_p = bprm->file->f_path.dentry; + err = rsbac_get_attr(SW_PAX, + T_FILE, + tid, + A_pax_flags, + &attr_val, + FALSE); + if(!err) + { + pax_check_flags(&attr_val.pax_flags); +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_adf_pax) + { + rsbac_printk(KERN_DEBUG + "rsbac_pax_set_flags_func(): changing flags for process %u from %lx to %lx from device %02u:%02u inode %lu\n", + current->pid, + current->flags & RSBAC_PAX_ALL_FLAGS, + attr_val.pax_flags, + MAJOR(tid.file.device),MINOR(tid.file.device), + tid.file.inode); + } +#endif + /* Set flags for process */ + current->mm->pax_flags = (current->mm->pax_flags & ~RSBAC_PAX_ALL_FLAGS) | attr_val.pax_flags; + } + else + { + rsbac_printk(KERN_WARNING + "rsbac_pax_set_flags_func(): get_data for device %02u:%02u, inode %lu returned error %i!\n", + MAJOR(tid.file.device), + MINOR(tid.file.device), + tid.file.inode, + err); + } + } +#endif + + +inline enum rsbac_adf_req_ret_t + rsbac_adf_request_pax (enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + switch (request) + { + case R_MODIFY_ATTRIBUTE: + switch(attr) + { + case A_system_role: + case A_pax_role: + case A_pax_flags: + /* All attributes (remove target!) */ + case A_none: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_PAX, + T_USER, + i_tid, + A_pax_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_pax()", A_pax_role); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + default: + return(DO_NOT_CARE); + } + + case R_READ_ATTRIBUTE: + switch(attr) + { + case A_system_role: + case A_pax_role: + case A_pax_flags: + /* All attributes (remove target!) */ + case A_none: + /* Security Officer or Admin? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_PAX, + T_USER, + i_tid, + A_pax_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_pax()", A_pax_role); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if( (i_attr_val1.system_role == SR_security_officer) + || (i_attr_val1.system_role == SR_administrator) + ) + return(GRANTED); + else + return(NOT_GRANTED); + + default: + return(DO_NOT_CARE); + } + + case R_SWITCH_LOG: + switch(target) + { + case T_NONE: + /* test owner's pax_role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_PAX, + T_USER, + i_tid, + A_pax_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_pax()", A_pax_role); + return(NOT_GRANTED); + } + /* security officer? -> grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + /* all other cases are unknown */ + default: return(DO_NOT_CARE); + } + + case R_SWITCH_MODULE: + switch(target) + { + case T_NONE: + /* we need the switch_target */ + if(attr != A_switch_target) + return NOT_GRANTED; + /* do not care for other modules */ + if( (attr_val.switch_target != SW_PAX) + #ifdef CONFIG_RSBAC_SOFTMODE + && (attr_val.switch_target != SW_SOFTMODE) + #endif + #ifdef CONFIG_RSBAC_FREEZE + && (attr_val.switch_target != SW_FREEZE) + #endif + #ifdef CONFIG_RSBAC_MPROTECT + && (attr_val.switch_target != SW_MPROTECT) + #endif + ) + return(DO_NOT_CARE); + /* test owner's pax_role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_PAX, + T_USER, + i_tid, + A_pax_role, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_request_pax()", A_pax_role); + return(NOT_GRANTED); + } + /* security officer? -> grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + /* all other cases are unknown */ + default: return(DO_NOT_CARE); + } + +/*********************/ + default: return DO_NOT_CARE; + } + + return DO_NOT_CARE; + } /* end of rsbac_adf_request_pax() */ + + +/* end of rsbac/adf/pax/pax_main.c */ diff --git a/rsbac/adf/rc/Makefile b/rsbac/adf/rc/Makefile new file mode 100644 index 000000000000..445ecad59336 --- /dev/null +++ b/rsbac/adf/rc/Makefile @@ -0,0 +1,9 @@ +# +# File: rsbac/adf/rc/Makefile +# +# Makefile for the Linux rsbac rc decision module. +# +# Author and (c) 1999-2013 Amon Ott +# + +obj-y := rc_syscalls.o rc_main.o diff --git a/rsbac/adf/rc/rc_main.c b/rsbac/adf/rc/rc_main.c new file mode 100644 index 000000000000..d4629d55400c --- /dev/null +++ b/rsbac/adf/rc/rc_main.c @@ -0,0 +1,3279 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - Role Compatibility */ +/* File: rsbac/adf/rc/main.c */ +/* */ +/* Author and (c) 1999-2017: Amon Ott */ +/* */ +/* Last modified: 21/Mar/2017 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_RSBAC_RC_LEARN) +#ifdef CONFIG_RSBAC_RC_LEARN_TA +rsbac_list_ta_number_t rc_learn_ta = CONFIG_RSBAC_RC_LEARN_TA; +#else +rsbac_list_ta_number_t rc_learn_ta = 0; +#endif +#endif + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +static enum rsbac_adf_req_ret_t +check_comp_rc(enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_adf_request_t request, rsbac_pid_t caller_pid) +{ + int err; + union rsbac_target_id_t i_tid; + enum rsbac_attribute_t i_attr; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_attribute_value_t i_attr_val2; + + union rsbac_rc_target_id_t i_rc_subtid; + enum rsbac_rc_item_t i_rc_item; + + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, + T_PROCESS, + i_tid, + A_rc_role, &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return NOT_GRANTED; + } + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + i_rc_item = RI_type_comp_fd; + i_attr = A_rc_type_fd; + break; + case T_DEV: + i_rc_item = RI_type_comp_dev; + i_attr = A_rc_type; + break; + case T_USER: + i_rc_item = RI_type_comp_user; + i_attr = A_rc_type; + break; + case T_PROCESS: + i_rc_item = RI_type_comp_process; + i_attr = A_rc_type; + break; + case T_IPC: + i_rc_item = RI_type_comp_ipc; + i_attr = A_rc_type; + break; +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case T_GROUP: + i_rc_item = RI_type_comp_group; + i_attr = A_rc_type; + break; +#endif +#if defined(CONFIG_RSBAC_RC_NET_DEV_PROT) + case T_NETDEV: + i_rc_item = RI_type_comp_netdev; + i_attr = A_rc_type; + break; +#endif +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETTEMP: + i_rc_item = RI_type_comp_nettemp; + i_attr = A_rc_type_nt; + break; + case T_NETOBJ: + i_rc_item = RI_type_comp_netobj; + if (rsbac_net_remote_request(request)) + i_attr = A_remote_rc_type; + else + i_attr = A_local_rc_type; + break; +#endif + default: + rsbac_printk(KERN_WARNING "check_comp_rc(): invalid target %i!\n", + target); + return NOT_GRANTED; + } + + /* get rc_type[_fd|_nt] from target */ + if ((err = rsbac_get_attr(SW_RC, + target, + tid, i_attr, &i_attr_val2, TRUE))) { + rsbac_pr_get_error(i_attr); + return NOT_GRANTED; + } + + /* get type_comp_xxx of role */ + i_rc_subtid.type = i_attr_val2.rc_type; + if (rsbac_rc_check_comp(i_attr_val1.rc_role, + i_rc_subtid, i_rc_item, request)) { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_rc && (request <= R_NONE) && (rsbac_log_levels[request][target] == LL_full)) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 = + rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp2) { +#ifdef CONFIG_RSBAC_LOG_PSEUDO + u_int pseudo = 0; + union rsbac_attribute_value_t i_attr_val3; + + /* Get owner's logging pseudo */ + i_tid.user = __kuid_val(current_uid()); + if (!rsbac_get_attr(SW_GEN,T_USER,i_tid,A_pseudo,&i_attr_val3,FALSE)) { + pseudo = i_attr_val3.pseudo; + } + if (pseudo) + rsbac_pr_debug(adf_rc, "pid %u(%s), pseudo %u, rc_role %u, %s rc_type %u, request %s -> GRANTED!\n", + pid_nr(caller_pid), + current->comm, + pseudo, + i_attr_val1.rc_role, + get_target_name_only + (tmp, target), + i_attr_val2.rc_type, + get_rc_special_right_name + (tmp2, request)); + else +#endif + rsbac_pr_debug(adf_rc, "pid %u(%s), owner %u, rc_role %u, %s rc_type %u, request %s -> GRANTED!\n", + pid_nr(caller_pid), + current->comm, + __kuid_val(current_uid()), + i_attr_val1.rc_role, + get_target_name_only + (tmp, target), + i_attr_val2.rc_type, + get_rc_special_right_name + (tmp2, request)); + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp); + } + } +#endif + return GRANTED; + } else { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_rc && ( (request > R_NONE) || (rsbac_log_levels[request][target] != LL_none) ) ) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + char *tmp2 = + rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp2) { +#if defined(CONFIG_RSBAC_RC_LEARN) + if (rsbac_rc_learn) { + union rsbac_rc_target_id_t i_rc_tid; + union rsbac_rc_item_value_t i_rc_value; + + i_rc_tid.role = i_attr_val1.rc_role; +#ifdef CONFIG_RSBAC_RC_LEARN_TA + if (!rsbac_list_ta_exist(rc_learn_ta)) + rsbac_list_ta_begin(CONFIG_RSBAC_LIST_TRANS_MAX_TTL, + &rc_learn_ta, + RSBAC_ALL_USERS, + RSBAC_RC_LEARN_TA_NAME, + NULL); +#endif + err = rsbac_rc_get_item (rc_learn_ta, + RT_ROLE, + i_rc_tid, + i_rc_subtid, + i_rc_item, + &i_rc_value, + NULL); + if (!err) { + i_rc_value.rights |= RSBAC_RC_RIGHTS_VECTOR(request); + err = rsbac_rc_set_item (rc_learn_ta, + RT_ROLE, + i_rc_tid, + i_rc_subtid, + i_rc_item, + i_rc_value, + RSBAC_LIST_TTL_KEEP); + if (!err) { +#ifdef CONFIG_RSBAC_LOG_PSEUDO + u_int pseudo = 0; + union rsbac_attribute_value_t i_attr_val3; + + /* Get owner's logging pseudo */ + i_tid.user = __kuid_val(current_uid()); + if (!rsbac_get_attr(SW_GEN,T_USER,i_tid,A_pseudo,&i_attr_val3,FALSE)) { + pseudo = i_attr_val3.pseudo; + } + if (pseudo) { + rsbac_printk(KERN_INFO "check_comp_rc(): learning mode: pid %u(%s), pseudo %u, rc_role %u, %s rc_type %u, right %s added to transaction %u!\n", + pid_nr(caller_pid), + current->comm, + pseudo, + i_attr_val1.rc_role, + get_target_name_only + (tmp, target), + i_attr_val2.rc_type, + get_rc_special_right_name + (tmp2, request), + rc_learn_ta); + } else +#endif + rsbac_printk(KERN_INFO "check_comp_rc(): learning mode: pid %u(%s), owner %u, rc_role %u, %s rc_type %u, right %s added to transaction %u!\n", + pid_nr(caller_pid), + current->comm, + __kuid_val(current_uid()), + i_attr_val1.rc_role, + get_target_name_only + (tmp, target), + i_attr_val2.rc_type, + get_rc_special_right_name + (tmp2, request), + rc_learn_ta); + rsbac_kfree(tmp2); + rsbac_kfree(tmp); + return GRANTED; + } + } + } +#endif + { +#ifdef CONFIG_RSBAC_LOG_PSEUDO + u_int pseudo = 0; + union rsbac_attribute_value_t i_attr_val3; + + /* Get owner's logging pseudo */ + i_tid.user = __kuid_val(current_uid()); + if (!rsbac_get_attr(SW_GEN,T_USER,i_tid,A_pseudo,&i_attr_val3,FALSE)) { + pseudo = i_attr_val3.pseudo; + } + if (pseudo) { + rsbac_pr_debug(adf_rc, "pid %u(%s), pseudo %u, rc_role %u, %s rc_type %u, request %s -> NOT_GRANTED!\n", + pid_nr(caller_pid), + current->comm, + pseudo, + i_attr_val1.rc_role, + get_target_name_only + (tmp, target), + i_attr_val2.rc_type, + get_rc_special_right_name + (tmp2, request)); + } else +#endif + rsbac_pr_debug(adf_rc, "pid %u(%s), owner %u, rc_role %u, %s rc_type %u, request %s -> NOT_GRANTED!\n", + pid_nr(caller_pid), + current->comm, + __kuid_val(current_uid()), + i_attr_val1.rc_role, + get_target_name_only + (tmp, target), + i_attr_val2.rc_type, + get_rc_special_right_name + (tmp2, request)); + } + rsbac_kfree(tmp2); + } + rsbac_kfree(tmp); + } + } +#endif + return NOT_GRANTED; + } +} + +static enum rsbac_adf_req_ret_t +check_comp_rc_scd(enum rsbac_rc_scd_type_t scd_type, + enum rsbac_adf_request_t request, rsbac_pid_t caller_pid) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + union rsbac_rc_target_id_t i_rc_subtid; + + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, + T_PROCESS, + i_tid, + A_rc_role, &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return NOT_GRANTED; + } + /* get type_comp_scd of role */ + i_rc_subtid.type = scd_type; + if (rsbac_rc_check_comp(i_attr_val1.rc_role, + i_rc_subtid, RI_type_comp_scd, request)) { + return GRANTED; + } else { +#if defined(CONFIG_RSBAC_RC_LEARN) || defined(CONFIG_RSBAC_DEBUG) + char tmp[RSBAC_MAXNAMELEN]; +#endif + +#if defined(CONFIG_RSBAC_RC_LEARN) + if (rsbac_rc_learn) { + union rsbac_rc_target_id_t i_rc_tid; + union rsbac_rc_item_value_t i_rc_value; + + i_rc_tid.role = i_attr_val1.rc_role; +#ifdef CONFIG_RSBAC_RC_LEARN_TA + if (!rsbac_list_ta_exist(rc_learn_ta)) + rsbac_list_ta_begin(CONFIG_RSBAC_LIST_TRANS_MAX_TTL, + &rc_learn_ta, + RSBAC_ALL_USERS, + RSBAC_RC_LEARN_TA_NAME, + NULL); +#endif + err = rsbac_rc_get_item (rc_learn_ta, + RT_ROLE, + i_rc_tid, + i_rc_subtid, + RI_type_comp_scd, + &i_rc_value, + NULL); + if (!err) { + i_rc_value.rights |= RSBAC_RC_RIGHTS_VECTOR(request); + err = rsbac_rc_set_item (rc_learn_ta, + RT_ROLE, + i_rc_tid, + i_rc_subtid, + RI_type_comp_scd, + i_rc_value, + RSBAC_LIST_TTL_KEEP); + if (!err) { +#ifdef CONFIG_RSBAC_LOG_PSEUDO + u_int pseudo = 0; + union rsbac_attribute_value_t i_attr_val3; + + /* Get owner's logging pseudo */ + i_tid.user = __kuid_val(current_uid()); + if (!rsbac_get_attr(SW_GEN,T_USER,i_tid,A_pseudo,&i_attr_val3,FALSE)) { + pseudo = i_attr_val3.pseudo; + } + if (pseudo) { + rsbac_printk(KERN_INFO "check_comp_rc_scd(): learning mode: pid %u(%s), pseudo %u, rc_role %i, scd_type %i, right %s added to transaction %u!\n", + pid_nr(caller_pid), current->comm, pseudo, + i_attr_val1.rc_role, scd_type, + get_request_name(tmp, request), + rc_learn_ta); + } else +#endif + rsbac_printk(KERN_INFO "check_comp_rc_scd(): learning mode: pid %u(%s), owner %u, rc_role %i, scd_type %i, right %s added to transaction %u!\n", + pid_nr(caller_pid), current->comm, __kuid_val(current_uid()), + i_attr_val1.rc_role, scd_type, + get_request_name(tmp, request), + rc_learn_ta); + return GRANTED; + } + } + } +#endif + if (rsbac_debug_adf_rc && ( (request > R_NONE) || (rsbac_log_levels[request][T_SCD] != LL_none) ) ) { +#ifdef CONFIG_RSBAC_LOG_PSEUDO + u_int pseudo = 0; + union rsbac_attribute_value_t i_attr_val3; + + /* Get owner's logging pseudo */ + i_tid.user = __kuid_val(current_uid()); + if (!rsbac_get_attr(SW_GEN,T_USER,i_tid,A_pseudo,&i_attr_val3,FALSE)) { + pseudo = i_attr_val3.pseudo; + } + if (pseudo) { + rsbac_pr_debug(adf_rc, "pid %u(%s), pseudo %u, rc_role %i, scd_type %i, request %s -> NOT_GRANTED!\n", + pid_nr(caller_pid), current->comm, pseudo, + i_attr_val1.rc_role, scd_type, + get_request_name(tmp, request)); + } else +#endif + rsbac_pr_debug(adf_rc, "pid %u(%s), owner %u, rc_role %i, scd_type %i, request %s -> NOT_GRANTED!\n", + pid_nr(caller_pid), current->comm, __kuid_val(current_uid()), + i_attr_val1.rc_role, scd_type, + get_request_name(tmp, request)); + } + return NOT_GRANTED; + } +} + +static enum rsbac_adf_req_ret_t +rc_check_create( + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_rc_target_id_t tid, + union rsbac_rc_target_id_t subtid, + enum rsbac_rc_item_t item) +{ + if (rsbac_rc_check_comp(tid.role, subtid, item, R_CREATE)) + return GRANTED; + else { + char tmp[RSBAC_MAXNAMELEN]; + +#if defined(CONFIG_RSBAC_RC_LEARN) + if (rsbac_rc_learn) { + union rsbac_rc_item_value_t i_rc_value; + int err; + +#ifdef CONFIG_RSBAC_RC_LEARN_TA + if (!rsbac_list_ta_exist(rc_learn_ta)) + rsbac_list_ta_begin(CONFIG_RSBAC_LIST_TRANS_MAX_TTL, + &rc_learn_ta, + RSBAC_ALL_USERS, + RSBAC_RC_LEARN_TA_NAME, + NULL); +#endif + err = rsbac_rc_get_item (rc_learn_ta, + RT_ROLE, + tid, + subtid, + item, + &i_rc_value, + NULL); + if (!err) { + i_rc_value.rights |= RSBAC_RC_RIGHTS_VECTOR(R_CREATE); + err = rsbac_rc_set_item (rc_learn_ta, + RT_ROLE, + tid, + subtid, + item, + i_rc_value, + RSBAC_LIST_TTL_KEEP); + if (!err) { +#ifdef CONFIG_RSBAC_LOG_PSEUDO + u_int pseudo = 0; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val3; + + /* Get owner's logging pseudo */ + i_tid.user = __kuid_val(current_uid()); + if (!rsbac_get_attr(SW_GEN,T_USER,i_tid,A_pseudo,&i_attr_val3,FALSE)) { + pseudo = i_attr_val3.pseudo; + } + if (pseudo) { + rsbac_printk(KERN_INFO "rc_check_create(): learning mode: pid %u(%s), pseudo %u, rc_role %u, %s rc_type %u, right CREATE added to transaction %u!\n", + pid_nr(caller_pid), + current->comm, + pseudo, + tid.role, + get_target_name_only + (tmp, target), + subtid.type, + rc_learn_ta); + } else +#endif + rsbac_printk(KERN_INFO "rc_check_create(): learning mode: pid %u(%s), owner %u, rc_role %u, %s rc_type %u, right CREATE added to transaction %u!\n", + pid_nr(caller_pid), + current->comm, + __kuid_val(current_uid()), + tid.role, + get_target_name_only + (tmp, target), + subtid.type, + rc_learn_ta); + return GRANTED; + } + } + } +#endif + rsbac_printk(KERN_WARNING "rc_check_create(): rc_role %i has no CREATE right on its %s def_create_type %i -> NOT_GRANTED!\n", + tid.role, + get_target_name_only (tmp, target), + subtid.type); + return NOT_GRANTED; + } +} + +/* exported for rc_syscalls.c */ +int rsbac_rc_test_admin_roles(rsbac_rc_role_id_t t_role, + rsbac_boolean_t modify) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_rc_target_id_t i_rc_subtid; + + if (t_role > RC_role_max_value) + return -RSBAC_EINVALIDVALUE; + /* get rc_role of process */ + i_tid.process = task_pid(current); + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, A_rc_role, &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + + i_rc_subtid.role = t_role; + /* read_only? -> assign_roles membership is enough */ + if (!modify) { + if (rsbac_rc_check_comp(i_attr_val1.rc_role, + i_rc_subtid, + RI_assign_roles, R_NONE)) + return 0; + /* fall through */ + } + /* check admin_roles of role */ + if (rsbac_rc_check_comp(i_attr_val1.rc_role, + i_rc_subtid, RI_admin_roles, R_NONE)) + return 0; + + if (t_role <= RC_role_max_value) + rsbac_pr_debug(adf_rc, + "rsbac_rc_test_admin_roles(): role %u not in admin roles of role %u, pid %u, user %u!\n", + t_role, + i_attr_val1.rc_role, + current->pid, + __kuid_val(current_uid())); + return -EPERM; +} + +/* exported for rc_syscalls.c */ +int rsbac_rc_test_assign_roles(enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + rsbac_rc_role_id_t t_role) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_attribute_value_t i_attr_val2; + union rsbac_rc_target_id_t i_rc_subtid; + + if (target >= T_NONE) + return -RSBAC_EINVALIDVALUE; + /* get rc_role of process */ + i_tid.process = task_pid(current); + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, A_rc_role, &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + /* get old role of target */ + if ((err = rsbac_get_attr(SW_RC, + target, + tid, attr, &i_attr_val2, TRUE))) { + rsbac_pr_get_error(attr); + return -RSBAC_EREADFAILED; + } + + i_rc_subtid.role = i_attr_val2.rc_role; + if (!rsbac_rc_check_comp(i_attr_val1.rc_role, + i_rc_subtid, RI_assign_roles, R_NONE)) { + if (i_attr_val2.rc_role <= RC_role_max_value) + rsbac_pr_debug(adf_rc, + "rsbac_rc_test_assign_roles(): old role %u not in assign roles of role %u, pid %u, user %u!\n", + i_attr_val2.rc_role, + i_attr_val1.rc_role, + current->pid, + __kuid_val(current_uid())); + return -EPERM; + } + i_rc_subtid.role = t_role; + if (!rsbac_rc_check_comp(i_attr_val1.rc_role, + i_rc_subtid, + RI_assign_roles, R_NONE)) { + if (t_role <= RC_role_max_value) + rsbac_pr_debug(adf_rc, + "rsbac_rc_test_assign_roles(): new role %u not in assign roles of role %u, pid %u, user %u!\n", + t_role, + i_attr_val1.rc_role, + current->pid, + __kuid_val(current_uid())); + return -EPERM; + } + return 0; +} + +enum rsbac_adf_req_ret_t +rsbac_rc_check_type_comp(enum rsbac_target_t target, + rsbac_rc_type_id_t type, + enum rsbac_rc_special_rights_t request, + rsbac_pid_t caller_pid) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + union rsbac_rc_target_id_t i_rc_subtid; + enum rsbac_rc_item_t i_rc_item; + + if (!caller_pid) + caller_pid = task_pid(current); + /* + * we don't care about tried assignments of special type values, + * but deny other accesses to those + */ + if (type > RC_type_max_value) { + if (request == RCR_ASSIGN) + return GRANTED; + else + return NOT_GRANTED; + } + + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, + T_PROCESS, + i_tid, + A_rc_role, &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return NOT_GRANTED; + } + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_FD: + i_rc_item = RI_type_comp_fd; + break; + case T_DEV: + i_rc_item = RI_type_comp_dev; + break; + case T_USER: + i_rc_item = RI_type_comp_user; + break; + case T_PROCESS: + i_rc_item = RI_type_comp_process; + break; + case T_IPC: + i_rc_item = RI_type_comp_ipc; + break; +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case T_GROUP: + i_rc_item = RI_type_comp_group; + break; +#endif +#if defined(CONFIG_RSBAC_RC_NET_DEV_PROT) + case T_NETDEV: + i_rc_item = RI_type_comp_netdev; + break; +#endif +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETTEMP: + i_rc_item = RI_type_comp_nettemp; + break; + case T_NETOBJ: + i_rc_item = RI_type_comp_netobj; + break; +#endif + + default: + rsbac_printk(KERN_WARNING "rsbac_rc_check_type_comp(): invalid target %i!\n", + target); + return NOT_GRANTED; + } + /* check type_comp_xxx of role */ + i_rc_subtid.type = type; + if (rsbac_rc_check_comp(i_attr_val1.rc_role, + i_rc_subtid, i_rc_item, request)) + return GRANTED; + else { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_adf_rc && ( (request > (enum rsbac_rc_special_rights_t) R_NONE) || (rsbac_log_levels[request][target] != LL_none) ) ) { + char tmp[50]; + char tmp2[RSBAC_MAXNAMELEN]; + + rsbac_pr_debug(adf_rc, "rc_role is %i, %s rc_type is %i, request is %s -> NOT_GRANTED!\n", + i_attr_val1.rc_role, + get_target_name_only(tmp, target), + type, + get_rc_special_right_name(tmp2, request)); + } +#endif + return NOT_GRANTED; + } +} + +/* exported for rc_syscalls.c */ +int rsbac_rc_test_role_admin(rsbac_boolean_t modify) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_rc_target_id_t i_rc_tid; + union rsbac_rc_item_value_t i_rc_item_val1; + + /* get rc_role of process */ + i_tid.process = task_pid(current); + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, A_rc_role, &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + + /* get admin_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, RT_ROLE, i_rc_tid, i_rc_tid, /* dummy */ + RI_admin_type, + &i_rc_item_val1, NULL))) { + rsbac_rc_pr_get_error(RI_admin_type); + return -RSBAC_EREADFAILED; + } + + /* allow, if RC_role_admin or (read_only and RC_system_admin) */ + if ((i_rc_item_val1.admin_type == RC_role_admin) + || (!modify && (i_rc_item_val1.admin_type == RC_system_admin) + ) + ) + return 0; + else + return -EPERM; +} + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +inline enum rsbac_adf_req_ret_t +rsbac_adf_request_rc(enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + int err; + enum rsbac_adf_req_ret_t result = DO_NOT_CARE; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_rc_target_id_t i_rc_tid; + union rsbac_rc_target_id_t i_rc_subtid; + union rsbac_rc_item_value_t i_rc_item_val1; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val2; + + switch (request) { + case R_SEARCH: + switch (target) { + case T_DIR: + case T_FILE: + case T_SYMLINK: + case T_FIFO: + case T_UNIXSOCK: + case T_DEV: +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETOBJ: +#endif +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case T_USER: + case T_GROUP: +#endif + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_CLOSE: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_UNIXSOCK: + case T_DEV: + case T_IPC: +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETOBJ: +#endif + return check_comp_rc + (target, tid, request, caller_pid); + + default: + return DO_NOT_CARE; + } + + case R_GET_STATUS_DATA: + switch (target) { + case T_SCD: + return check_comp_rc_scd + (tid.scd, request, caller_pid); + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: + case T_PROCESS: + case T_DEV: +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case T_USER: + case T_GROUP: +#endif + return check_comp_rc + (target, tid, request, caller_pid); + +#if defined(CONFIG_RSBAC_RC_NET_DEV_PROT) + case T_NETDEV: + return check_comp_rc + (target, tid, request, caller_pid); +#endif +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETOBJ: + return check_comp_rc + (target, tid, request, caller_pid); +#endif + + default: + return DO_NOT_CARE; + } + + case R_SEND: + switch (target) { + case T_DEV: +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETOBJ: +#endif + return check_comp_rc + (target, tid, request, caller_pid); + + case T_UNIXSOCK: + case T_IPC: +#if defined(CONFIG_RSBAC_RC_NET_OBJ_UNIX_PROCESS) + if (attr == A_process) { + enum rsbac_adf_req_ret_t tmp_result; + + i_tid.process = attr_val.process; + tmp_result = check_comp_rc(T_PROCESS, i_tid, + R_SEND, + caller_pid); + if ((tmp_result == NOT_GRANTED) + || (tmp_result == UNDEFINED) + ) + return tmp_result; + } +#endif /* UNIX_PROCESS */ + return check_comp_rc + (target, tid, request, caller_pid); + + + /* all other cases are undefined */ + default: + return DO_NOT_CARE; + } + + case R_LISTEN: + case R_NET_SHUTDOWN: + switch (target) { + case T_UNIXSOCK: + case T_IPC: +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETOBJ: +#endif + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are undefined */ + default: + return DO_NOT_CARE; + } + case R_ACCEPT: + case R_CONNECT: + case R_RECEIVE: + switch (target) { + case T_UNIXSOCK: + case T_IPC: +#if defined(CONFIG_RSBAC_RC_NET_OBJ_UNIX_PROCESS) + if (attr == A_process) { + enum rsbac_adf_req_ret_t tmp_result; + + i_tid.process = attr_val.process; + tmp_result = check_comp_rc(T_PROCESS, i_tid, + request, + caller_pid); + if ((tmp_result == NOT_GRANTED) + || (tmp_result == UNDEFINED) + ) + return tmp_result; + } +#endif /* UNIX_PROCESS */ + return check_comp_rc + (target, tid, request, caller_pid); + +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETOBJ: + return check_comp_rc + (target, tid, request, caller_pid); +#endif + + /* all other cases are undefined */ + default: + return DO_NOT_CARE; + } + + case R_READ: + case R_WRITE: + switch (target) { + case T_DIR: +#ifdef CONFIG_RSBAC_RW + case T_FILE: + case T_FIFO: + case T_DEV: +#endif +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case T_USER: + case T_GROUP: +#endif +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) +#if defined(CONFIG_RSBAC_NET_OBJ_RW) + case T_NETTEMP: +#endif +#endif + return check_comp_rc + (target, tid, request, caller_pid); + +#ifdef CONFIG_RSBAC_RW + case T_IPC: + case T_UNIXSOCK: +#if defined(CONFIG_RSBAC_RC_NET_OBJ_UNIX_PROCESS) + if (attr == A_process) { + enum rsbac_adf_req_ret_t tmp_result; + + i_tid.process = attr_val.process; + if (request == R_READ) + tmp_result = + check_comp_rc(T_PROCESS, i_tid, + R_RECEIVE, + caller_pid); + else + tmp_result = + check_comp_rc(T_PROCESS, i_tid, + R_SEND, + caller_pid); + if ((tmp_result == NOT_GRANTED) + || (tmp_result == UNDEFINED) + ) + return tmp_result; + } +#endif /* UNIX_PROCESS */ + return check_comp_rc + (target, tid, request, caller_pid); +#endif /* RW */ + + case T_SCD: + return check_comp_rc_scd + (tid.scd, request, caller_pid); + +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) +#if defined(CONFIG_RSBAC_NET_OBJ_RW) + case T_NETOBJ: + return check_comp_rc + (target, tid, request, caller_pid); +#endif +#endif + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_MOVETO: + switch (target) { + case T_DIR: + return check_comp_rc + (target, tid, request, caller_pid); + + default: + return DO_NOT_CARE; + } + + case R_APPEND_OPEN: + case R_READ_WRITE_OPEN: + switch (target) { + case T_FILE: + case T_DEV: + case T_FIFO: + case T_IPC: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_MAP_EXEC: + switch (target) { + case T_FILE: + return check_comp_rc + (target, tid, request, caller_pid); + case T_NONE: + /* anonymous mapping */ + return check_comp_rc_scd + (ST_other, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_CHANGE_GROUP: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_IPC: +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case T_USER: +#endif + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_CHANGE_OWNER: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_IPC: + return check_comp_rc + (target, tid, request, caller_pid); + +#ifdef CONFIG_RSBAC_USER_CHOWN + case T_USER: +#if defined(CONFIG_RSBAC_AUTH) + result = check_comp_rc(target, tid, request, caller_pid); + if((result == GRANTED) || (result == DO_NOT_CARE)) + return result; + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_AUTH, T_PROCESS, + i_tid, + A_auth_last_auth, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_auth_last_auth); + return NOT_GRANTED; + } + if(i_attr_val1.auth_last_auth != tid.user) + return NOT_GRANTED; + else + return check_comp_rc(target, tid, RCR_CHANGE_AUTHED_OWNER, caller_pid); +#else + return check_comp_rc(target, tid, request, caller_pid); +#endif +#endif + + case T_PROCESS: + /* get rc_role from process */ + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return NOT_GRANTED; + } + /* get def_process_chown_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, RT_ROLE, i_rc_tid, i_rc_tid, /* dummy */ + RI_def_process_chown_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_process_chown_type); + return NOT_GRANTED; + } + if ((i_rc_item_val1.type_id == RC_type_no_chown) + || (i_rc_item_val1.type_id == + RC_type_no_create) + ) + return NOT_GRANTED; + else + return GRANTED; + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_CHDIR: + switch (target) { + case T_DIR: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_CLONE: + if (target == T_PROCESS) { + /* check, whether we may create process of def_process_create_type */ + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return NOT_GRANTED; + } + /* get def_process_create_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_process_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_process_create_type); + return NOT_GRANTED; + } + switch (i_rc_item_val1.type_id) { + case RC_type_no_create: + if ((request > R_NONE) || (rsbac_log_levels[request][target] != LL_none)) { + rsbac_pr_debug(adf_rc, "pid %u(%s), owner %u, rc_role %u, def_process_create_type no_create, request CLONE -> NOT_GRANTED!\n", + pid_nr(caller_pid), current->comm, + __kuid_val(current_uid()), + i_attr_val1.rc_role); + } + return NOT_GRANTED; + + case RC_type_use_new_role_def_create: + case RC_type_use_fd: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_request_rc(): invalid type use_new_role_def_create in def_process_create_type of role %i!\n", + i_attr_val1.rc_role); + return NOT_GRANTED; + + case RC_type_inherit_parent: + case RC_type_inherit_process: + return GRANTED; + + default: + /* check, whether role has CREATE right to new type */ + /* check type_comp_process of role */ + i_rc_subtid.type = i_rc_item_val1.type_id; + return rc_check_create(caller_pid, + target, + i_rc_tid, + i_rc_subtid, + RI_type_comp_process); + } + } else + return DO_NOT_CARE; + + /* Creating dir or (pseudo) file IN target dir! */ + case R_CREATE: + switch (target) { + case T_DIR: + /* check, whether we may create files/dirs in this dir */ + result = + check_comp_rc(target, tid, request, + caller_pid); + if ((result != GRANTED) && (result != DO_NOT_CARE)) + return result; + + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return NOT_GRANTED; + } + /* Check, whether this process has a preselected type */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_select_type, + &i_attr_val2, FALSE))) { + rsbac_pr_get_error(A_rc_select_type); + return NOT_GRANTED; + } + if (i_attr_val2.rc_select_type == RC_type_use_fd) { + /* get def_fd_create_type of role */ + /* First get target dir's efftype */ + if ((err = rsbac_get_attr(SW_RC, + target, + tid, + A_rc_type_fd, + &i_attr_val2, TRUE))) { + rsbac_pr_get_error(A_rc_type_fd); + return NOT_GRANTED; + } + i_rc_tid.role = i_attr_val1.rc_role; + i_rc_subtid.type = i_attr_val2.rc_type; + if ((err = rsbac_rc_get_item(0, RT_ROLE, i_rc_tid, i_rc_subtid, RI_def_fd_ind_create_type, &i_rc_item_val1, NULL))) { /* No individual create type -> try global */ + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_subtid, + RI_def_fd_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_fd_create_type); + return NOT_GRANTED; + } + } + } else + i_rc_item_val1.type_id = i_attr_val2.rc_select_type; + + switch (i_rc_item_val1.type_id) { + case RC_type_inherit_parent: + return GRANTED; + case RC_type_no_create: + if ((request > R_NONE) || (rsbac_log_levels[request][target] != LL_none)) { + rsbac_pr_debug(adf_rc, "pid %u(%s), owner %u, rc_role %u, def_fd_create_type no_create, request CREATE -> NOT_GRANTED!\n", + pid_nr(caller_pid), current->comm, + __kuid_val(current_uid()), + i_attr_val1.rc_role); + } + return NOT_GRANTED; + + case RC_type_use_new_role_def_create: + case RC_type_inherit_process: + case RC_type_use_fd: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_request_rc(): invalid type use_new_role_def_create in def_fd_create_type of role %i!\n", + i_attr_val1.rc_role); + return NOT_GRANTED; + + default: + /* check, whether role has CREATE right to new type */ + /* get type_comp_fd of role */ + i_rc_tid.role = i_attr_val1.rc_role; + i_rc_subtid.type = i_rc_item_val1.type_id; + return rc_check_create(caller_pid, + target, + i_rc_tid, + i_rc_subtid, + RI_type_comp_fd); + } + + case T_IPC: + /* check, whether we may create IPC of def_ipc_create_type */ + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return NOT_GRANTED; + } + /* get def_ipc_create_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_ipc_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_ipc_create_type); + return NOT_GRANTED; + } + switch (i_rc_item_val1.type_id) { + case RC_type_no_create: + if ((request > R_NONE) || (rsbac_log_levels[request][target] != LL_none)) { + rsbac_pr_debug(adf_rc, "pid %u(%s), owner %u, rc_role %u, def_ipc_create_type no_create, request CREATE -> NOT_GRANTED!\n", + pid_nr(caller_pid), current->comm, + __kuid_val(current_uid()), + i_attr_val1.rc_role); + } + return NOT_GRANTED; + + case RC_type_use_new_role_def_create: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_request_rc(): invalid type use_new_role_def_create in def_ipc_create_type of role %i!\n", + i_attr_val1.rc_role); + return NOT_GRANTED; + + case RC_type_inherit_parent: + case RC_type_inherit_process: + case RC_type_use_fd: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_request_rc(): invalid type inherit_parent in def_ipc_create_type of role %i!\n", + i_attr_val1.rc_role); + return NOT_GRANTED; + + default: + /* check, whether role has CREATE right to new type */ + /* get type_comp_ipc of role */ + i_rc_subtid.type = i_rc_item_val1.type_id; + return rc_check_create(caller_pid, + target, + i_rc_tid, + i_rc_subtid, + RI_type_comp_ipc); + } + +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case T_USER: + /* check, whether we may create USER of def_user_create_type */ + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return NOT_GRANTED; + } + /* get def_user_create_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_user_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_user_create_type); + return NOT_GRANTED; + } + switch (i_rc_item_val1.type_id) { + case RC_type_no_create: + if ((request > R_NONE) || (rsbac_log_levels[request][target] != LL_none)) { + rsbac_pr_debug(adf_rc, "pid %u(%s), owner %u, rc_role %u, def_user_create_type no_create, request CREATE -> NOT_GRANTED!\n", + pid_nr(caller_pid), current->comm, + __kuid_val(current_uid()), + i_attr_val1.rc_role); + } + return NOT_GRANTED; + + case RC_type_use_new_role_def_create: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_request_rc(): invalid type use_new_role_def_create in def_user_create_type of role %i!\n", + i_attr_val1.rc_role); + return NOT_GRANTED; + + case RC_type_inherit_parent: + case RC_type_inherit_process: + case RC_type_use_fd: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_request_rc(): invalid type inherit_parent in def_user_create_type of role %i!\n", + i_attr_val1.rc_role); + return NOT_GRANTED; + + default: + /* check, whether role has CREATE right to new type */ + /* get type_comp_ipc of role */ + i_rc_subtid.type = i_rc_item_val1.type_id; + return rc_check_create(caller_pid, + target, + i_rc_tid, + i_rc_subtid, + RI_type_comp_user); + } + + case T_GROUP: + /* check, whether we may create GROUP of def_group_create_type */ + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return NOT_GRANTED; + } + /* get def_group_create_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_group_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_group_create_type); + return NOT_GRANTED; + } + switch (i_rc_item_val1.type_id) { + case RC_type_no_create: + if ((request > R_NONE) || (rsbac_log_levels[request][target] != LL_none)) { + rsbac_pr_debug(adf_rc, "pid %u(%s), owner %u, rc_role %u, def_group_create_type no_create, request CREATE -> NOT_GRANTED!\n", + pid_nr(caller_pid), current->comm, + __kuid_val(current_uid()), + i_attr_val1.rc_role); + } + return NOT_GRANTED; + + case RC_type_use_new_role_def_create: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_request_rc(): invalid type use_new_role_def_create in def_group_create_type of role %i!\n", + i_attr_val1.rc_role); + return NOT_GRANTED; + + case RC_type_inherit_parent: + case RC_type_inherit_process: + case RC_type_use_fd: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_request_rc(): invalid type inherit_parent in def_group_create_type of role %i!\n", + i_attr_val1.rc_role); + return NOT_GRANTED; + + default: + /* check, whether role has CREATE right to new type */ + /* get type_comp_ipc of role */ + i_rc_subtid.type = i_rc_item_val1.type_id; + return rc_check_create(caller_pid, + target, + i_rc_tid, + i_rc_subtid, + RI_type_comp_group); + } +#endif /* RSBAC_RC_UM_PROT */ + +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETTEMP: + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, + T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return NOT_GRANTED; + } + /* get type_comp_xxx of role - we always use type GENERAL for CREATE */ + i_rc_tid.role = i_attr_val1.rc_role; + i_rc_subtid.type = RSBAC_RC_GENERAL_TYPE; + return rc_check_create(caller_pid, + target, + i_rc_tid, + i_rc_subtid, + RI_type_comp_nettemp); + + case T_NETOBJ: + /* check, whether we may create NETOBJ of this type */ + return(check_comp_rc(target, tid, request, caller_pid)); +#endif + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_DELETE: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETTEMP: + case T_NETOBJ: +#endif +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case T_USER: + case T_GROUP: +#endif + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_EXECUTE: + switch (target) { + case T_FILE: + /* get rc_role from process */ + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return NOT_GRANTED; + } + /* get def_process_execute_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_process_execute_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_process_execute_type); + return NOT_GRANTED; + } + if (i_rc_item_val1.type_id == RC_type_no_execute) + return NOT_GRANTED; + else + return check_comp_rc + (target, tid, request, + caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_GET_PERMISSIONS_DATA: + switch (target) { + case T_SCD: + return check_comp_rc_scd + (tid.scd, request, caller_pid); + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: + case T_DEV: +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETOBJ: +#endif +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case T_USER: + case T_GROUP: +#endif + return check_comp_rc + (target, tid, request, caller_pid); + + default: + return DO_NOT_CARE; + }; + + case R_LINK_HARD: + switch (target) { + case T_FILE: + case T_UNIXSOCK: + case T_FIFO: + case T_SYMLINK: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_MODIFY_ACCESS_DATA: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_AUTHENTICATE: + switch (target) { + case T_USER: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_MODIFY_ATTRIBUTE: + switch (attr) { /* owner must be changed by other request to prevent inconsistency */ + case A_owner: + return NOT_GRANTED; + case A_rc_type: + case A_local_rc_type: + case A_remote_rc_type: + case A_rc_type_fd: + case A_rc_type_nt: + case A_rc_select_type: + /* Granted on target? */ + result = + check_comp_rc(target, tid, request, + caller_pid); + if ((result == GRANTED) + || (result == DO_NOT_CARE) + ) { + /* Granted on type? */ + if ( (target == T_NETTEMP) + && (attr == A_rc_type) + ) + target = T_NETOBJ; + result = + rsbac_rc_check_type_comp(target, + attr_val. + rc_type, + RCR_ASSIGN, + caller_pid); + if ((result == GRANTED) + || (result == DO_NOT_CARE) + ) + return result; + } + /* Classical admin_type check */ + if ((err = rsbac_rc_test_role_admin(TRUE))) + return NOT_GRANTED; + else + return GRANTED; + + case A_rc_force_role: + case A_rc_initial_role: + case A_rc_role: + case A_rc_def_role: + /* Granted on target? */ + result = + check_comp_rc(target, tid, request, + caller_pid); + if ((result == GRANTED) + || (result == DO_NOT_CARE) + ) { + /* test assign_roles of process / modify */ + if (! + (err = + rsbac_rc_test_assign_roles(target, + tid, attr, + attr_val. + rc_role))) + return GRANTED; + } + /* Classical admin_type check */ + if (rsbac_rc_test_role_admin(TRUE)) + return NOT_GRANTED; + else + return GRANTED; + + /* you may only change a user's pseudo, if you also may assign her role */ + case A_pseudo: + if (target != T_USER) + return NOT_GRANTED; + /* test assign_roles of process for user's role only */ + if (rsbac_rc_test_assign_roles + (target, tid, A_rc_def_role, + RC_role_inherit_user)) + return NOT_GRANTED; + else + return GRANTED; + +#ifdef CONFIG_RSBAC_RC_GEN_PROT + case A_log_array_low: + case A_log_array_high: + case A_log_program_based: + case A_log_user_based: + case A_symlink_add_remote_ip: + case A_symlink_add_uid: + case A_symlink_add_rc_role: + case A_allow_write_exec: + case A_fake_root_uid: + case A_audit_uid: + case A_auid_exempt: + case A_remote_ip: + case A_vset: + /* Explicitely granted? */ + result = + check_comp_rc(target, tid, request, + caller_pid); + if ((result == GRANTED) + || (result == DO_NOT_CARE) + ) + return result; + /* Failed -> Classical admin_type check / modify */ + if (rsbac_rc_test_role_admin(TRUE)) + return NOT_GRANTED; + else + return GRANTED; +#endif + + /* All attributes (remove target!) */ + case A_none: + switch (target) { + case T_USER: + /* test assign_roles of process for user's role */ + if ((err = + rsbac_rc_test_assign_roles(target, + tid, + A_rc_def_role, + RC_role_inherit_user))) + return NOT_GRANTED; + else + return GRANTED; + + default: + /* Explicitely granted? */ + return check_comp_rc + (target, tid, request, + caller_pid); + } + +#ifdef CONFIG_RSBAC_RC_AUTH_PROT + case A_auth_may_setuid: + case A_auth_may_set_cap: + case A_auth_start_uid: + case A_auth_start_euid: + case A_auth_start_gid: + case A_auth_start_egid: + case A_auth_learn: + case A_auth_add_f_cap: + case A_auth_remove_f_cap: + case A_auth_last_auth: + /* may manipulate auth capabilities, if allowed in general... */ + result = + check_comp_rc_scd(RST_auth_administration, + request, caller_pid); + if ((result == GRANTED) + || (result == DO_NOT_CARE) + ) { + /* ...and for this target */ + result = + check_comp_rc(target, tid, + RCR_MODIFY_AUTH, + caller_pid); + if ((result == GRANTED) + || (result == DO_NOT_CARE) + ) + return result; + } + /* Last chance: classical admin_type check */ + if ((err = rsbac_rc_test_role_admin(TRUE))) + return NOT_GRANTED; + else + return GRANTED; +#endif +#ifdef CONFIG_RSBAC_RC_UDF_PROT + case A_udf_role: + case A_udf_checker: + case A_udf_checked: + case A_udf_do_check: + /* may manipulate udf attributes, if general... */ + result = + check_comp_rc_scd(RST_udf_administration, + request, caller_pid); + if ((result == GRANTED) + || (result == DO_NOT_CARE) + ) { + /* ...and for this target */ + result = + check_comp_rc(target, tid, + RCR_MODIFY_UDF, + caller_pid); + if ((result == GRANTED) + || (result == DO_NOT_CARE) + ) + return result; + } + /* Last chance: classical admin_type check */ + if ((err = rsbac_rc_test_role_admin(TRUE))) + return NOT_GRANTED; + else + return GRANTED; +#endif +#if defined(CONFIG_RSBAC_RC_LEARN) + case A_rc_learn: + /* Only role admin */ + if ((err = rsbac_rc_test_role_admin(TRUE))) + return NOT_GRANTED; + else + return GRANTED; +#endif + + default: + return DO_NOT_CARE; + } + + case R_MODIFY_PERMISSIONS_DATA: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + case T_IPC: + case T_DEV: +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case T_USER: + case T_GROUP: +#endif +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETOBJ: +#endif + return check_comp_rc + (target, tid, request, caller_pid); + + case T_SCD: + return check_comp_rc_scd + (tid.scd, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_MODIFY_SYSTEM_DATA: + switch (target) { + case T_SCD: + return check_comp_rc_scd + (tid.scd, request, caller_pid); + + case T_DEV: + case T_PROCESS: + case T_IPC: +#if defined(CONFIG_RSBAC_RC_NET_DEV_PROT) + case T_NETDEV: +#endif +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETOBJ: +#endif + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_MOUNT: + switch (target) { + case T_FILE: + case T_DIR: + case T_DEV: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_READ_ATTRIBUTE: + switch (attr) { + case A_rc_type: + case A_rc_type_fd: + case A_rc_type_nt: + case A_rc_force_role: + case A_rc_initial_role: + case A_rc_role: + case A_rc_def_role: + case A_rc_select_type: + case A_pseudo: +#ifdef CONFIG_RSBAC_RC_GEN_PROT + case A_owner: + case A_log_array_low: + case A_log_array_high: + case A_log_program_based: + case A_log_user_based: + case A_symlink_add_remote_ip: + case A_symlink_add_uid: + case A_symlink_add_rc_role: + case A_allow_write_exec: + case A_fake_root_uid: + case A_audit_uid: + case A_auid_exempt: + case A_remote_ip: + case A_vset: +#endif + /* Explicitely granted? */ + result = + check_comp_rc(target, tid, request, + caller_pid); + if ((result == GRANTED) + || (result == DO_NOT_CARE) + ) + return result; + /* Failed -> Classical admin_type check / modify */ + if (rsbac_rc_test_role_admin(FALSE)) + return NOT_GRANTED; + else + return GRANTED; + +#ifdef CONFIG_RSBAC_RC_AUTH_PROT + case A_auth_may_setuid: + case A_auth_may_set_cap: + case A_auth_start_uid: + case A_auth_start_euid: + case A_auth_start_gid: + case A_auth_start_egid: + case A_auth_learn: + case A_auth_add_f_cap: + case A_auth_remove_f_cap: + case A_auth_last_auth: + /* may read auth capabilities, if compatible */ + result = + check_comp_rc_scd(RST_auth_administration, + request, caller_pid); + if ((result == GRANTED) + || (result == DO_NOT_CARE) + ) + return result; + /* Failed -> Classical admin_type check / modify */ + if (rsbac_rc_test_role_admin(FALSE)) + return NOT_GRANTED; + else + return GRANTED; +#endif +#ifdef CONFIG_RSBAC_RC_UDF_PROT + case A_udf_role: + case A_udf_checker: + case A_udf_checked: + case A_udf_do_check: + /* may read UDF attributes, if compatible */ + result = + check_comp_rc_scd(RST_udf_administration, + request, caller_pid); + if ((result == GRANTED) + || (result == DO_NOT_CARE) + ) + return result; + /* Failed -> Classical admin_type check / modify */ + if (rsbac_rc_test_role_admin(FALSE)) + return NOT_GRANTED; + else + return GRANTED; +#endif + + default: + return DO_NOT_CARE; + } + + case R_READ_OPEN: + switch (target) { + case T_FILE: + case T_FIFO: + case T_UNIXSOCK: + case T_DEV: + case T_IPC: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_ADD_TO_KERNEL: + switch (target) { + case T_NONE: + /* may add to kernel, if compatible */ + return check_comp_rc_scd + (ST_other, request, caller_pid); + + case T_FILE: + case T_DEV: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + + case R_ALTER: + /* only for IPC */ + switch (target) { + case T_IPC: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_REMOVE_FROM_KERNEL: + switch (target) { + case T_NONE: + return check_comp_rc_scd + (ST_other, request, caller_pid); + + case T_FILE: + case T_DEV: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_RENAME: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case T_USER: + case T_GROUP: +#endif + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_SEND_SIGNAL: + case R_TRACE: + if (target == T_PROCESS) + return check_comp_rc + (target, tid, request, caller_pid); + else + return DO_NOT_CARE; + + case R_SHUTDOWN: + switch (target) { + case T_NONE: + return check_comp_rc_scd + (ST_other, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_SWITCH_LOG: + switch (target) { + case T_NONE: + return check_comp_rc_scd + (ST_other, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_SWITCH_MODULE: + switch (target) { + case T_NONE: + /* we need the switch_target */ + if (attr != A_switch_target) + return NOT_GRANTED; + switch(attr_val.switch_target) { + case SW_RC: +#ifdef CONFIG_RSBAC_SOFTMODE + case SW_SOFTMODE: +#endif +#ifdef CONFIG_RSBAC_FREEZE + case SW_FREEZE: +#endif +#ifdef CONFIG_RSBAC_MPROTECT + case SW_MPROTECT: +#endif + return check_comp_rc_scd (ST_other, request, caller_pid); +#ifdef CONFIG_RSBAC_RC_AUTH_PROT + case SW_AUTH: + if (check_comp_rc_scd (ST_other, request, caller_pid) == GRANTED) + return GRANTED; + return check_comp_rc_scd (RST_auth_administration, request, caller_pid); +#endif +#ifdef CONFIG_RSBAC_RC_UDF_PROT + case SW_UDF: + return check_comp_rc_scd (RST_udf_administration, request, caller_pid); +#endif + + default: + return DO_NOT_CARE; + } + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_TERMINATE: + return DO_NOT_CARE; + + case R_TRUNCATE: + switch (target) { + case T_FILE: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_WRITE_OPEN: + switch (target) { + case T_FILE: + case T_DEV: + case T_FIFO: + case T_UNIXSOCK: + case T_IPC: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + case R_UMOUNT: + switch (target) { + case T_FILE: + case T_DIR: + case T_DEV: + return check_comp_rc + (target, tid, request, caller_pid); + + /* all other cases are unknown */ + default: + return DO_NOT_CARE; + } + + + case R_BIND: + switch (target) { + case T_IPC: + /* check, whether we may create IPC of def_ipc_create_type */ + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return NOT_GRANTED; + } + /* get def_ipc_create_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_ipc_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_ipc_create_type); + return NOT_GRANTED; + } + switch (i_rc_item_val1.type_id) { + case RC_type_no_create: + if ((request > R_NONE) || (rsbac_log_levels[request][target] != LL_none)) { + rsbac_pr_debug(adf_rc, "pid %u(%s), owner %u, rc_role %u, def_ipc_create_type no_create, request CREATE -> NOT_GRANTED!\n", + pid_nr(caller_pid), current->comm, + __kuid_val(current_uid()), + i_attr_val1.rc_role); + } + return NOT_GRANTED; + + case RC_type_use_new_role_def_create: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_request_rc(): invalid type use_new_role_def_create in def_ipc_create_type of role %i!\n", + i_attr_val1.rc_role); + return NOT_GRANTED; + + case RC_type_inherit_parent: + case RC_type_inherit_process: + case RC_type_use_fd: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_request_rc(): invalid type inherit_parent in def_ipc_create_type of role %i!\n", + i_attr_val1.rc_role); + return NOT_GRANTED; + + default: + /* check, whether role has CREATE right to new type */ + /* get type_comp_ipc of role */ + i_rc_subtid.type = i_rc_item_val1.type_id; + return rc_check_create(caller_pid, + target, + i_rc_tid, + i_rc_subtid, + RI_type_comp_ipc); + } +#if defined(CONFIG_RSBAC_RC_NET_DEV_PROT) + case T_NETDEV: + return check_comp_rc + (target, tid, request, caller_pid); +#endif + +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETOBJ: + return check_comp_rc + (target, tid, request, caller_pid); +#endif + + /* all other cases are undefined */ + default: + return DO_NOT_CARE; + } + + case R_IOCTL: + switch (target) { + case T_DEV: + case T_UNIXSOCK: + case T_IPC: + return check_comp_rc + (target, tid, request, caller_pid); +#if defined(CONFIG_RSBAC_RC_NET_OBJ_PROT) + case T_NETOBJ: +#endif + return check_comp_rc + (target, tid, request, caller_pid); + + default: + return DO_NOT_CARE; + } + + case R_LOCK: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + return check_comp_rc + (target, tid, request, caller_pid); + + default: + return DO_NOT_CARE; + } + case RCR_SELECT: + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + return check_comp_rc + (target, tid, request, caller_pid); + default: + return DO_NOT_CARE; + } + default: + return DO_NOT_CARE; + } + + return result; +} + +/*****************************************************************************/ +/* If the request returned granted and the operation is performed, */ +/* the following function can be called by the AEF to get all aci set */ +/* correctly. For write accesses that are performed fully within the kernel, */ +/* this is usually not done to prevent extra calls, including R_CLOSE for */ +/* cleaning up. Because of this, the write boundary is not adjusted - there */ +/* is no user-level writing anyway... */ +/* The second instance of target specification is the new target, if one has */ +/* been created, otherwise its values are ignored. */ +/* On success, 0 is returned, and an error from rsbac/error.h otherwise. */ + +inline int rsbac_adf_set_attr_rc(enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_attribute_value_t i_attr_val2; + union rsbac_rc_target_id_t i_rc_tid; + union rsbac_rc_target_id_t i_rc_subtid; + union rsbac_rc_item_value_t i_rc_item_val1; + + switch (request) { + case R_CLOSE: + case R_ACCEPT: + case R_READ: + return 0; + case R_CHANGE_OWNER: + switch (target) { + case T_PROCESS: + /* setting owner for process is done in main dispatcher */ + /* Here we have to adjust the rc_type and set the rc_role */ + /* to the new owner's rc_def_role */ + if (attr != A_owner) + return -RSBAC_EINVALIDATTR; + + /* get old rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + /* get def_process_chown_type of old role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_process_chown_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_process_chown_type); + return -RSBAC_EREADFAILED; + } + + /* get rc_force_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_force_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_force_role); + return -RSBAC_EREADFAILED; + } + /* only set to user's rc_def_role, if indicated by force_role, otherwise keep */ + if ((i_attr_val1.rc_force_role == + RC_role_inherit_user) + || (i_attr_val1.rc_force_role == + RC_role_inherit_up_mixed) + ) { + /* get rc_def_role from new owner */ + i_tid.user = attr_val.owner; + if ((err = rsbac_get_attr(SW_RC, T_USER, + i_tid, + A_rc_def_role, + &i_attr_val1, + FALSE))) { + rsbac_pr_get_error(A_rc_def_role); + return -RSBAC_EREADFAILED; + } + /* check rc_def_role, warn, if unusable */ + if (i_attr_val1.rc_def_role > + RC_role_max_value) { + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): rc_def_role %u of user %u is higher than MAX_ROLE %u, setting role of process %u to GENERAL_ROLE %u!\n", + i_attr_val1. + rc_def_role, + attr_val.owner, + RC_role_max_value, + pid_nr(caller_pid), + RSBAC_RC_GENERAL_ROLE); + i_attr_val1.rc_def_role = + RSBAC_RC_GENERAL_ROLE; + } + /* set new rc_role for process */ + i_tid.process = caller_pid; + if ((err = rsbac_set_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + i_attr_val1))) { + rsbac_pr_set_error(A_rc_role); + return -RSBAC_EWRITEFAILED; + } + } else + /* set it to the force_role, if real role) */ + if ((i_attr_val1.rc_force_role <= RC_role_max_value) + ) { + /* set new rc_role for process */ + i_tid.process = caller_pid; + if ((err = rsbac_set_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + i_attr_val1))) { + rsbac_pr_set_error(A_rc_role); + return -RSBAC_EWRITEFAILED; + } + } + + /* adjust type: switch on def_process_chown_type of old role */ + switch (i_rc_item_val1.type_id) { + case RC_type_inherit_parent: + case RC_type_inherit_process: + /* keep old type */ + break; + case RC_type_use_new_role_def_create: + /* get new rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + /* Cannot adjust, if new role is no real role */ + if (i_attr_val1.rc_role > + RC_role_max_value) + break; + /* get def_process_create_type of new role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_process_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_process_create_type); + return -RSBAC_EREADFAILED; + } + switch (i_rc_item_val1.type_id) { + case RC_type_inherit_parent: + case RC_type_inherit_process: + /* keep old type */ + break; + case RC_type_use_new_role_def_create: + /* error - complain, but keep type (inherit) */ + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): invalid type use_new_role_def_create in def_process_create_type of role %i!\n", + i_attr_val1.rc_role); + break; + case RC_type_no_create: + /* set rc_type for process to general */ + i_rc_item_val1.type_id = + RSBAC_RC_GENERAL_TYPE; + /* fall through */ + default: + /* set rc_type for process */ + i_attr_val1.rc_type = + i_rc_item_val1.type_id; + if ((err = + rsbac_set_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_type, + i_attr_val1))) + { + rsbac_pr_set_error(A_rc_type); + return -RSBAC_EWRITEFAILED; + } + } + break; + case RC_type_no_create: + case RC_type_no_chown: + /* set rc_type for process to general */ + i_rc_item_val1.type_id = + RSBAC_RC_GENERAL_TYPE; + /* fall through */ + default: + /* set rc_type for process */ + i_attr_val1.rc_type = + i_rc_item_val1.type_id; + if ((err = + rsbac_set_attr(SW_RC, T_PROCESS, i_tid, + A_rc_type, + i_attr_val1))) { + rsbac_pr_set_error(A_rc_type); + return -RSBAC_EWRITEFAILED; + } + } + + return 0; + + /* all other cases */ + default: + return 0; + } + + case R_CLONE: + if (target == T_PROCESS) { + /* get rc_role from process */ + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + + /* get rc_force_role from process */ + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + tid, + A_rc_force_role, + &i_attr_val2, FALSE))) { + rsbac_pr_get_error(A_rc_force_role); + return -RSBAC_EREADFAILED; + } + + /* set rc_role for new process */ + if ((i_attr_val1.rc_role != RSBAC_RC_GENERAL_ROLE) && (err = rsbac_set_attr(SW_RC, T_PROCESS, + new_tid, + A_rc_role, + i_attr_val1))) { + rsbac_pr_set_error(A_rc_role); + return -RSBAC_EWRITEFAILED; + } + + /* set rc_force_role for new process */ + if ((i_attr_val2.rc_force_role != RC_default_force_role) && (err = rsbac_set_attr(SW_RC, T_PROCESS, + new_tid, + A_rc_force_role, + i_attr_val2))) { + rsbac_pr_set_error(A_rc_force_role); + return -RSBAC_EWRITEFAILED; + } + + /* get def_process_create_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_process_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_process_create_type); + return -RSBAC_EREADFAILED; + } + switch (i_rc_item_val1.type_id) { + case RC_type_inherit_parent: + case RC_type_inherit_process: + /* copy old type */ + /* get rc_type from old process */ + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + tid, + A_rc_type, + &i_attr_val1, + FALSE))) { + rsbac_pr_get_error(A_rc_type); + return -RSBAC_EREADFAILED; + } + /* set rc_type for new process */ + if ((i_attr_val1.rc_type != RSBAC_RC_GENERAL_TYPE) && (err = rsbac_set_attr(SW_RC, T_PROCESS, + new_tid, + A_rc_type, + i_attr_val1))) { + rsbac_pr_set_error(A_rc_type); + return -RSBAC_EWRITEFAILED; + } + break; + case RC_type_no_create: + return -RSBAC_EDECISIONMISMATCH; + case RC_type_use_new_role_def_create: + /* error - complain, but keep type (inherit) */ + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): invalid type use_new_role_def_create in def_process_create_type of role %i!\n", + i_attr_val1.rc_role); + return -RSBAC_EINVALIDVALUE; + default: + /* set rc_type for new process */ + i_attr_val1.rc_type = + i_rc_item_val1.type_id; + if ((i_attr_val1.rc_type != RSBAC_RC_GENERAL_TYPE) && (err = + rsbac_set_attr(SW_RC, T_PROCESS, new_tid, + A_rc_type, + i_attr_val1))) { + rsbac_pr_set_error(A_rc_type); + return -RSBAC_EWRITEFAILED; + } + } + return 0; + } else + return 0; + + case R_CREATE: + switch (target) { + /* Creating dir or (pseudo) file IN target dir! */ + case T_DIR: + /* Mode of created item is ignored! */ + /* check for select_fd_type being set for calling + * process and enforce it if set. */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_select_type, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_select_type); + return -RSBAC_EREADFAILED; + } + if (i_attr_val1.rc_select_type != RC_type_use_fd) { + i_attr_val2.rc_type_fd = i_attr_val1.rc_select_type; + /* rc_select_type is one use only so we reset it + * to default value first. + * value to be set already backup'ed. */ + i_attr_val1.rc_select_type = RC_type_use_fd; + if ((err = rsbac_set_attr(SW_RC, T_PROCESS, + i_tid, A_rc_select_type, + i_attr_val1))) + { + rsbac_printk("rsbac_adf_set_attr_rc(): unable to reset rc_select_type to default value!\n"); + } + if ((err = rsbac_set_attr(SW_RC, new_target, + new_tid, A_rc_type_fd, + i_attr_val2))) + { + rsbac_pr_set_error(A_rc_type_fd); + return -RSBAC_EWRITEFAILED; + } + return 0; + + } + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + /* get def_fd_create_type of role */ + /* First get target dir's efftype */ + if ((err = rsbac_get_attr(SW_RC, + target, + tid, + A_rc_type_fd, + &i_attr_val2, TRUE))) { + rsbac_pr_get_error(A_rc_type_fd); + return -RSBAC_EREADFAILED; + } + i_rc_tid.role = i_attr_val1.rc_role; + switch(new_target) { + case T_UNIXSOCK: + i_rc_subtid.type = i_attr_val2.rc_type; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_subtid, + RI_def_unixsock_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_unixsock_create_type); + return -RSBAC_EREADFAILED; + } + if(i_rc_item_val1.type_id != RC_type_use_fd) + break; + /* fall through */ + default: + i_rc_subtid.type = i_attr_val2.rc_type; + if ((err = rsbac_rc_get_item(0, RT_ROLE, i_rc_tid, i_rc_subtid, RI_def_fd_ind_create_type, &i_rc_item_val1, NULL))) { /* No individual create type -> try global */ + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_subtid, + RI_def_fd_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_fd_create_type); + return -RSBAC_EREADFAILED; + } + } + } + switch (i_rc_item_val1.type_id) { + case RC_type_no_create: + return -RSBAC_EDECISIONMISMATCH; + break; + + case RC_type_use_new_role_def_create: + case RC_type_inherit_process: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): invalid type inherit_process or use_new_role_def_create in def_fd_create_type or def_unixsock_create_type of role %i!\n", + i_attr_val1.rc_role); + return -RSBAC_EINVALIDVALUE; + + case RC_type_inherit_parent: + default: + /* get type from new target */ + if ((err = rsbac_get_attr(SW_RC, new_target, + new_tid, + A_rc_type_fd, + &i_attr_val1, + FALSE))) { + rsbac_pr_get_error(A_rc_type_fd); + return -RSBAC_EREADFAILED; + } + /* set it for new target, if different */ + if (i_attr_val1.rc_type_fd != + i_rc_item_val1.type_id) { + i_attr_val1.rc_type_fd = + i_rc_item_val1.type_id; + if ((err = + rsbac_set_attr(SW_RC, new_target, + new_tid, + A_rc_type_fd, + i_attr_val1))) + { + rsbac_pr_set_error(A_rc_type_fd); + return -RSBAC_EWRITEFAILED; + } + } + } + return 0; + + case T_IPC: + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + /* get def_ipc_create_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_ipc_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_ipc_create_type); + return -RSBAC_EREADFAILED; + } + switch (i_rc_item_val1.type_id) { + case RC_type_no_create: + return -RSBAC_EDECISIONMISMATCH; + break; + + case RC_type_use_new_role_def_create: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): invalid type use_new_role_def_create in def_ipc_create_type of role %i!\n", + i_attr_val1.rc_role); + return -RSBAC_EINVALIDVALUE; + + case RC_type_inherit_parent: + case RC_type_inherit_process: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): invalid type inherit_parent in def_ipc_create_type of role %i!\n", + i_attr_val1.rc_role); + return -RSBAC_EINVALIDVALUE; + + default: + /* set rc_type for ipc target */ + i_attr_val1.rc_type = + i_rc_item_val1.type_id; + /* get type from target */ + if ((err = rsbac_get_attr(SW_RC, + target, + tid, + A_rc_type, + &i_attr_val2, + FALSE))) { + rsbac_pr_get_error(A_rc_type); + return -RSBAC_EREADFAILED; + } + /* set it for new target, if different */ + if (i_attr_val1.rc_type != + i_attr_val2.rc_type) { + if ((err = + rsbac_set_attr(SW_RC, target, + tid, A_rc_type, + i_attr_val1))) + { + rsbac_pr_set_error + (A_rc_type); + return -RSBAC_EWRITEFAILED; + } + } + } + return 0; + + case T_USER: + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + /* get def_user_create_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_user_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_user_create_type); + return -RSBAC_EREADFAILED; + } + switch (i_rc_item_val1.type_id) { + case RC_type_no_create: + if ((request > R_NONE) || (rsbac_log_levels[request][target] != LL_none)) { + rsbac_pr_debug(adf_rc, "pid %u(%s), owner %u, rc_role %u, def_user_create_type no_create, request CREATE -> NOT_GRANTED!\n", + pid_nr(caller_pid), current->comm, + __kuid_val(current_uid()), + i_attr_val1.rc_role); + } + return -RSBAC_EDECISIONMISMATCH; + + case RC_type_use_new_role_def_create: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): invalid type use_new_role_def_create in def_user_create_type of role %i!\n", + i_attr_val1.rc_role); + return -RSBAC_EINVALIDVALUE; + + case RC_type_inherit_parent: + case RC_type_inherit_process: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): invalid type inherit_parent in def_user_create_type of role %i!\n", + i_attr_val1.rc_role); + return -RSBAC_EINVALIDVALUE; + + default: + /* set rc_type for user target */ + i_attr_val1.rc_type = + i_rc_item_val1.type_id; + /* get type from target */ + if ((err = rsbac_get_attr(SW_RC, + target, + tid, + A_rc_type, + &i_attr_val2, + FALSE))) { + rsbac_pr_get_error(A_rc_type); + return -RSBAC_EREADFAILED; + } + /* set it for new target, if different */ + if (i_attr_val1.rc_type != + i_attr_val2.rc_type) { + if ((err = + rsbac_set_attr(SW_RC, target, + tid, A_rc_type, + i_attr_val1))) + { + rsbac_pr_set_error + (A_rc_type); + return -RSBAC_EWRITEFAILED; + } + } + } + return 0; + + case T_GROUP: + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + /* get def_group_create_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_group_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_group_create_type); + return -RSBAC_EREADFAILED; + } + switch (i_rc_item_val1.type_id) { + case RC_type_no_create: + if ((request > R_NONE) || (rsbac_log_levels[request][target] != LL_none)) { + rsbac_pr_debug(adf_rc, "pid %u(%s), owner %u, rc_role %u, def_group_create_type no_create, request CREATE -> NOT_GRANTED!\n", + pid_nr(caller_pid), current->comm, + __kuid_val(current_uid()), + i_attr_val1.rc_role); + } + return -RSBAC_EDECISIONMISMATCH; + + case RC_type_use_new_role_def_create: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): invalid type use_new_role_def_create in def_group_create_type of role %i!\n", + i_attr_val1.rc_role); + return -RSBAC_EINVALIDVALUE; + + case RC_type_inherit_parent: + case RC_type_inherit_process: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): invalid type inherit_parent in def_group_create_type of role %i!\n", + i_attr_val1.rc_role); + return -RSBAC_EINVALIDVALUE; + + default: + /* set rc_type for group target */ + i_attr_val1.rc_type = + i_rc_item_val1.type_id; + /* get type from target */ + if ((err = rsbac_get_attr(SW_RC, + target, + tid, + A_rc_type, + &i_attr_val2, + FALSE))) { + rsbac_pr_get_error(A_rc_type); + return -RSBAC_EREADFAILED; + } + /* set it for new target, if different */ + if (i_attr_val1.rc_type != + i_attr_val2.rc_type) { + if ((err = + rsbac_set_attr(SW_RC, target, + tid, A_rc_type, + i_attr_val1))) + { + rsbac_pr_set_error + (A_rc_type); + return -RSBAC_EWRITEFAILED; + } + } + } + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + + case R_EXECUTE: + switch (target) { + case T_FILE: + /* get rc_force_role from target file */ + if ((err = rsbac_get_attr(SW_RC, T_FILE, + tid, + A_rc_force_role, + &i_attr_val1, TRUE))) { + rsbac_pr_get_error(A_rc_force_role); + return -RSBAC_EREADFAILED; + } + /* check rc_force_role, warn, if unusable */ + if ((i_attr_val1.rc_force_role > RC_role_max_value) + && (i_attr_val1.rc_force_role < + RC_role_min_special) + ) { + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): rc_force_role %u of file %u on device %02u:%02u is higher than MAX_ROLE %u, setting forced role of process %u to default value %u!\n", + i_attr_val1.rc_force_role, + tid.file.inode, + MAJOR(tid.file.device), + MINOR(tid.file.device), + RC_role_max_value, pid_nr(caller_pid), + RC_default_root_dir_force_role); + i_attr_val1.rc_force_role = + RC_default_root_dir_force_role; + } + /* set rc_force_role for this process to keep track of it later */ + i_tid.process = caller_pid; + if ((err = rsbac_set_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_force_role, + i_attr_val1))) { + rsbac_pr_set_error(A_rc_force_role); + return -RSBAC_EWRITEFAILED; + } + /* get rc_initial_role from target file */ + if ((err = rsbac_get_attr(SW_RC, T_FILE, + tid, + A_rc_initial_role, + &i_attr_val2, TRUE))) { + rsbac_pr_get_error(A_rc_initial_role); + return -RSBAC_EREADFAILED; + } + /* check rc_initial_role, warn, if unusable */ + if ((i_attr_val2.rc_initial_role > + RC_role_max_value) + && (i_attr_val2.rc_initial_role != + RC_role_use_force_role) + ) { + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): rc_initial_role %u of file %u on device %02u:%02u is higher than MAX_ROLE %u, setting initial role of process %u to default value %u!\n", + i_attr_val2.rc_initial_role, + tid.file.inode, + MAJOR(tid.file.device), + MINOR(tid.file.device), + RC_role_max_value, pid_nr(caller_pid), + RC_default_root_dir_initial_role); + i_attr_val2.rc_initial_role = + RC_default_root_dir_initial_role; + } + if (i_attr_val2.rc_initial_role == + RC_role_use_force_role) { + switch (i_attr_val1.rc_force_role) { + case RC_role_inherit_user: + /* get rc_def_role from process owner */ + i_tid.user = owner; + if ((err = + rsbac_get_attr(SW_RC, T_USER, + i_tid, + A_rc_def_role, + &i_attr_val1, + FALSE))) { + rsbac_pr_get_error + (A_rc_def_role); + return -RSBAC_EREADFAILED; + } + /* set it for this process */ + i_tid.process = caller_pid; + if ((err = + rsbac_set_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + i_attr_val1))) + { + rsbac_pr_set_error + (A_rc_role); + return -RSBAC_EWRITEFAILED; + } + break; + + case RC_role_inherit_parent: + case RC_role_inherit_process: + case RC_role_inherit_up_mixed: + /* keep current role */ + break; + + default: + /* set forced role for this process */ + i_tid.process = caller_pid; + if ((err = + rsbac_set_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + i_attr_val1))) + { + rsbac_pr_set_error + (A_rc_role); + return -RSBAC_EWRITEFAILED; + } + } + } else { /* use initial_role */ + + /* set initial role for this process */ + i_tid.process = caller_pid; + if ((err = rsbac_set_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + i_attr_val2))) { + rsbac_pr_set_error + (A_rc_role); + return -RSBAC_EWRITEFAILED; + } + } + /* Get role of process. */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + /* get def_process_execute_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_process_execute_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_process_execute_type); + return -RSBAC_EREADFAILED; + } + switch (i_rc_item_val1.type_id) { + case RC_type_no_create: + case RC_type_use_new_role_def_create: + /* Cannot reset, because of unusable default -> warn and keep */ + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): invalid type in def_process_execute_type of role %i!\n", + i_attr_val1.rc_role); + return -RSBAC_EINVALIDVALUE; + case RC_type_inherit_parent: + case RC_type_inherit_process: + break; + case RC_type_no_execute: + return -RSBAC_EDECISIONMISMATCH; + default: + /* set rc_type for process */ + i_attr_val1.rc_type = + i_rc_item_val1.type_id; + i_tid.process = caller_pid; + if ((err = + rsbac_set_attr(SW_RC, T_PROCESS, i_tid, + A_rc_type, + i_attr_val1))) { + rsbac_pr_set_error(A_rc_type); + return -RSBAC_EWRITEFAILED; + } + } + /* type and role are set - ready. */ + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + case R_BIND: + switch (target) { + case T_IPC: + /* get rc_role from process */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + /* get def_ipc_create_type of role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_ROLE, + i_rc_tid, + i_rc_tid, + RI_def_ipc_create_type, + &i_rc_item_val1, + NULL))) { + rsbac_rc_pr_get_error + (RI_def_ipc_create_type); + return -RSBAC_EREADFAILED; + } + switch (i_rc_item_val1.type_id) { + case RC_type_no_create: + return -RSBAC_EDECISIONMISMATCH; + break; + + case RC_type_use_new_role_def_create: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): invalid type use_new_role_def_create in def_ipc_create_type of role %i!\n", + i_attr_val1.rc_role); + return -RSBAC_EINVALIDVALUE; + + case RC_type_inherit_parent: + case RC_type_inherit_process: + /* error - complain and return error */ + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_rc(): invalid type inherit_parent in def_ipc_create_type of role %i!\n", + i_attr_val1.rc_role); + return -RSBAC_EINVALIDVALUE; + + default: + /* set rc_type for ipc target */ + i_attr_val1.rc_type = + i_rc_item_val1.type_id; + /* get type from target */ + if ((err = rsbac_get_attr(SW_RC, + target, + tid, + A_rc_type, + &i_attr_val2, + FALSE))) { + rsbac_pr_get_error(A_rc_type); + return -RSBAC_EREADFAILED; + } + /* set it for new target, if different */ + if (i_attr_val1.rc_type != + i_attr_val2.rc_type) { + if ((err = + rsbac_set_attr(SW_RC, target, + tid, A_rc_type, + i_attr_val1))) + { + rsbac_pr_set_error + (A_rc_type); + return -RSBAC_EWRITEFAILED; + } + } + } + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + + case R_CONNECT: + switch (target) { + case T_IPC: + if (new_target == T_IPC) { + /* get type from old target */ + i_tid.process = caller_pid; + if ((err = rsbac_get_attr(SW_RC, T_IPC, + tid, + A_rc_type, + &i_attr_val1, FALSE))) { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + /* set rc_type for new ipc target, if not 0 */ + if (i_attr_val1.rc_type) { + if ((err = rsbac_set_attr(SW_RC, T_IPC, + new_tid, A_rc_type, + i_attr_val1))) { + rsbac_pr_set_error(A_rc_type); + return -RSBAC_EWRITEFAILED; + } + } + } + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + + default: + return 0; + } + + return 0; +} + +#ifdef CONFIG_RSBAC_SECDEL +inline rsbac_boolean_t rsbac_need_overwrite_rc(struct dentry * dentry_p) +{ + int err = 0; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_rc_target_id_t i_rc_tid; + union rsbac_rc_item_value_t i_rc_item_val1; + + if (!dentry_p || !dentry_p->d_inode) + return FALSE; + + i_tid.file.device = dentry_p->d_sb->s_dev; + i_tid.file.inode = dentry_p->d_inode->i_ino; + i_tid.file.dentry_p = dentry_p; + /* get target's rc_type_fd */ + if (rsbac_get_attr(SW_RC, T_FILE, + i_tid, A_rc_type_fd, &i_attr_val1, TRUE)) { + rsbac_pr_get_error(A_rc_type_fd); + return FALSE; + } + /* get type_fd_need_secdel of target's rc_type_fd */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err = rsbac_rc_get_item(0, + RT_TYPE, + i_rc_tid, + i_rc_tid, + RI_type_fd_need_secdel, + &i_rc_item_val1, NULL))) { + rsbac_rc_pr_get_error(RI_type_fd_need_secdel); + return FALSE; + } + + /* return need_overwrite */ + return i_rc_item_val1.need_secdel; +} +#endif diff --git a/rsbac/adf/rc/rc_syscalls.c b/rsbac/adf/rc/rc_syscalls.c new file mode 100644 index 000000000000..422392a88eb2 --- /dev/null +++ b/rsbac/adf/rc/rc_syscalls.c @@ -0,0 +1,1683 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - Role Compatibility */ +/* File: rsbac/adf/rc/syscalls.c */ +/* */ +/* Author and (c) 1999-2016: Amon Ott */ +/* */ +/* Last modified: 26/Mar/2016 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +/************************************************* */ +/* Declarations */ +/************************************************* */ + +/* from rsbac/adf/rc/main.c */ +int rsbac_rc_test_role_admin(rsbac_boolean_t modify); + +int rsbac_rc_test_admin_roles(rsbac_rc_role_id_t t_role, rsbac_boolean_t modify); + +enum rsbac_adf_req_ret_t + rsbac_rc_check_type_comp(enum rsbac_target_t target, + rsbac_rc_type_id_t type, + enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid); + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +/* Here we only check access rights and pass on to rc_data_structures */ +int rsbac_rc_sys_copy_role( + rsbac_list_ta_number_t ta_number, + rsbac_rc_role_id_t from_role, + rsbac_rc_role_id_t to_role) + { +#ifdef CONFIG_RSBAC_SWITCH_RC + if(rsbac_switch_rc) +#endif + { + int err; + /* source role must be in admin roles or caller must be role_admin */ + if ( (err=rsbac_rc_test_admin_roles(from_role, TRUE)) + && rsbac_rc_test_role_admin(TRUE) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_copy_role(): copying of role %u denied for pid %u, user %u - not in admin_roles!\n", + from_role, + current->pid, + user); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + else + return err; + } + /* only role_admins may copy to existing targets */ + if ( rsbac_rc_role_exists(ta_number, to_role) + && rsbac_rc_test_role_admin(TRUE) + ) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_copy_role(): overwriting of existing role %u denied for pid %u, user %u - no role_admin!\n", + to_role, + current->pid, + user); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return -EPERM; + } + } + + /* pass on */ + return(rsbac_rc_copy_role(ta_number, from_role, to_role)); + } + +/* Here we only check access rights and pass on to rc_data_structures */ +int rsbac_rc_sys_copy_type ( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + rsbac_rc_type_id_t from_type, + rsbac_rc_type_id_t to_type) + { +#ifdef CONFIG_RSBAC_SWITCH_RC + if(rsbac_switch_rc) +#endif + { + int err; + + switch(target) + { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + target = T_FD; + break; + case T_FD: + case T_DEV: + case T_USER: + case T_PROCESS: + case T_IPC: + case T_GROUP: + case T_NETDEV: + case T_NETTEMP: + case T_NETOBJ: + break; + + default: + return -RSBAC_EINVALIDTARGET; + } + /* need ADMIN right to source type or caller must be role_admin */ + if( (rsbac_rc_check_type_comp(target, from_type, RCR_ADMIN, 0) != GRANTED) + && (err=rsbac_rc_test_role_admin(FALSE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_copy_type(): copying of %s type %u denied for pid %u, user %u - not in admin_roles!\n", + get_target_name_only(tmp, target), + from_type, + current->pid, + user); + rsbac_kfree(tmp); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + else + return err; + } + /* only role_admins may copy to existing targets */ + if ( rsbac_rc_type_exists(ta_number, target, to_type) + && rsbac_rc_test_role_admin(TRUE) + ) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_copy_type(): overwriting of existing %s type %u denied for pid %u, user %u - no role_admin!\n", + get_target_name_only(tmp, target), + to_type, + current->pid, + user); + rsbac_kfree(tmp); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return -EPERM; + } + } + + /* pass on */ + return(rsbac_rc_copy_type(ta_number, target, from_type, to_type)); + } + +/* Getting values */ +int rsbac_rc_sys_get_item( + rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t tid, + union rsbac_rc_target_id_t subtid, + enum rsbac_rc_item_t item, + union rsbac_rc_item_value_t * value_p, + rsbac_time_t * ttl_p) + { +#ifdef CONFIG_RSBAC_SWITCH_RC + if(rsbac_switch_rc) +#endif + { + int err; + + switch(item) + { + case RI_name: + case RI_type_fd_name: + case RI_type_dev_name: + case RI_type_ipc_name: + case RI_type_user_name: + case RI_type_process_name: + case RI_type_scd_name: + case RI_type_group_name: + case RI_type_netdev_name: + case RI_type_nettemp_name: + case RI_type_netobj_name: + /* getting names is always allowed */ + break; + + case RI_type_fd_need_secdel: + if(target != RT_TYPE) + return -RSBAC_EINVALIDTARGET; + if( (err=rsbac_rc_check_type_comp(T_FILE, tid.type, RCR_ADMIN, 0)) + && (err=rsbac_rc_test_role_admin(FALSE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_get_item(): reading fd_need_secdel of type %u denied for pid %u, user %u - no ADMIN right!\n", + tid.type, + current->pid, + user); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + else + return err; + } + break; + + default: + if(target != RT_ROLE) + return -RSBAC_EINVALIDATTR; + /* test admin_roles or admin_type of process' role / no modify */ + if ( (err=rsbac_rc_test_admin_roles(tid.role, FALSE)) + && (err=rsbac_rc_test_role_admin(FALSE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_get_item(): getting item of role %u denied for pid %u, user %u - not in admin_roles!\n", + tid.role, + current->pid, + user); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + else + return err; + } + } + } + + /* pass on */ + return(rsbac_rc_get_item(ta_number,target, tid, subtid, item, value_p, ttl_p)); + } + +/* Setting values */ +int rsbac_rc_sys_set_item( + rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t tid, + union rsbac_rc_target_id_t subtid, + enum rsbac_rc_item_t item, + union rsbac_rc_item_value_t value, + rsbac_time_t ttl) + { +#ifdef CONFIG_RSBAC_SWITCH_RC + if(rsbac_switch_rc) +#endif + { + int err; + + switch(item) + { + /* type targets */ + case RI_type_fd_name: + case RI_type_fd_need_secdel: + case RI_type_fd_remove: + if(target != RT_TYPE) + return -RSBAC_EINVALIDTARGET; + if( (rsbac_rc_check_type_comp(T_FILE, tid.type, RCR_ADMIN, 0) == NOT_GRANTED) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + char tmp[80]; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing %s of FD type %u denied for pid %u, user %u - no ADMIN right!\n", + get_rc_item_name(tmp, item), + tid.type, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + case RI_type_dev_name: + case RI_type_dev_remove: + if(target != RT_TYPE) + return -RSBAC_EINVALIDTARGET; + if( (rsbac_rc_check_type_comp(T_DEV, tid.type, RCR_ADMIN, 0) == NOT_GRANTED) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing name or removing of DEV type %u denied for pid %u, user %u - no ADMIN right!\n", + tid.type, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + case RI_type_ipc_name: + case RI_type_ipc_remove: + if(target != RT_TYPE) + return -RSBAC_EINVALIDTARGET; + if( (rsbac_rc_check_type_comp(T_IPC, tid.type, RCR_ADMIN, 0) == NOT_GRANTED) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing name or removing of IPC type %u denied for pid %u, user %u - no ADMIN right!\n", + tid.type, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + case RI_type_user_name: + case RI_type_user_remove: + if(target != RT_TYPE) + return -RSBAC_EINVALIDTARGET; + if( (rsbac_rc_check_type_comp(T_USER, tid.type, RCR_ADMIN, 0) == NOT_GRANTED) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing name or removing of USER type %u denied for pid %u, user %u - no ADMIN right!\n", + tid.type, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + case RI_type_process_name: + case RI_type_process_remove: + if(target != RT_TYPE) + return -RSBAC_EINVALIDTARGET; + if( (rsbac_rc_check_type_comp(T_PROCESS, tid.type, RCR_ADMIN, 0) == NOT_GRANTED) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing name or removing of process type %u denied for pid %u, user %u - no ADMIN right!\n", + tid.type, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + case RI_type_scd_name: + if(target != RT_TYPE) + return -RSBAC_EINVALIDTARGET; + if( (rsbac_rc_check_type_comp(T_SCD, tid.type, RCR_ADMIN, 0) == NOT_GRANTED) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing name or removing of SCD type %u denied for pid %u, user %u - no ADMIN right!\n", + tid.type, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + case RI_type_group_name: + case RI_type_group_remove: + if(target != RT_TYPE) + return -RSBAC_EINVALIDTARGET; + if( (rsbac_rc_check_type_comp(T_GROUP, tid.type, RCR_ADMIN, 0) == NOT_GRANTED) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing name or removing of GROUP type %u denied for pid %u, user %u - no ADMIN right!\n", + tid.type, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + case RI_type_netdev_name: + case RI_type_netdev_remove: + if(target != RT_TYPE) + return -RSBAC_EINVALIDTARGET; + if( (rsbac_rc_check_type_comp(T_NETDEV, tid.type, RCR_ADMIN, 0) == NOT_GRANTED) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing name or removing of NETDEV type %u denied for pid %u, user %u - no ADMIN right!\n", + tid.type, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + case RI_type_nettemp_name: + case RI_type_nettemp_remove: + if(target != RT_TYPE) + return -RSBAC_EINVALIDTARGET; + if( (rsbac_rc_check_type_comp(T_NETTEMP, tid.type, RCR_ADMIN, 0) == NOT_GRANTED) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing name or removing of NETTEMP type %u denied for pid %u, user %u - no ADMIN right!\n", + tid.type, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + case RI_type_netobj_name: + case RI_type_netobj_remove: + if(target != RT_TYPE) + return -RSBAC_EINVALIDTARGET; + if( (rsbac_rc_check_type_comp(T_NETOBJ, tid.type, RCR_ADMIN, 0) == NOT_GRANTED) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing name or removing of NETOBJ type %u denied for pid %u, user %u - no ADMIN right!\n", + tid.type, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + + /* roles only from here */ + case RI_role_comp: + /* need admin for this role, assign for changed compatible roles */ + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + if(target != RT_ROLE) + return -RSBAC_EINVALIDATTR; + if(!rsbac_rc_test_role_admin(TRUE)) + break; + /* test admin_role of process / modify */ + if((err=rsbac_rc_test_admin_roles(tid.role, TRUE))) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing role_comp of role %u denied for pid %u, user %u - not in admin_roles!\n", + tid.role, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + /* now check assign for changed comp role. */ + /* get rc_role of process */ + i_tid.process = task_pid(current); + if ((err=rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, + FALSE))) + { + rsbac_pr_get_error(A_rc_role); + return -RSBAC_EREADFAILED; + } + /* check assign_roles of role */ + if (!rsbac_rc_check_comp(i_attr_val1.rc_role, + tid, + RI_assign_roles, + R_NONE)) + { + rsbac_uid_t user; + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing role_comp for role %u denied for user %u, role %u - not in assign_roles!\n", + tid.role, + user, + i_attr_val1.rc_role); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return -EPERM; + } + } + break; + + case RI_admin_type: + case RI_admin_roles: + case RI_assign_roles: + case RI_boot_role: + case RI_req_reauth: + /* admin_type role_admin */ + if((err=rsbac_rc_test_role_admin(TRUE))) + { + if(err == -EPERM) + { + rsbac_uid_t user; + char tmp[80]; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing %s of role %u denied for pid %u, user %u - no Role Admin!\n", + get_rc_item_name(tmp, item), + tid.role, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + case RI_name: + /* admin for this role */ + /* test admin_role of process / modify */ + if( (err=rsbac_rc_test_admin_roles(tid.role, TRUE)) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing name of role %u denied for pid %u, user %u - not in admin_roles!\n", + tid.role, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + + case RI_remove_role: + /* test admin_role of process role / modify */ + if((err=rsbac_rc_test_role_admin(TRUE))) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): removing of role %u denied for pid %u, user %u - not in admin_roles!\n", + tid.role, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + + case RI_def_fd_create_type: + case RI_def_fd_ind_create_type: + /* admin for this role and assign for target type */ + /* test admin_role of process / modify */ + if( (err=rsbac_rc_test_admin_roles(tid.role, TRUE)) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing def_fd_[ind_]create_type of role %u denied for pid %u, user %u - not in admin_roles!\n", + tid.role, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + else + { + enum rsbac_adf_req_ret_t result; + + result = rsbac_rc_check_type_comp(T_FILE, value.type_id, RCR_ASSIGN, 0); + if( ( (result == NOT_GRANTED) + || (result == UNDEFINED) + ) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing def_fd_[ind_]create_type for role %u to %u denied for user %u - no ASSIGN right for type!\n", + tid.role, + value.type_id, + user); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return -EPERM; + } + } + break; + + case RI_def_fd_ind_create_type_remove: + /* test admin_role of process / modify */ + if( (err=rsbac_rc_test_admin_roles(tid.role, TRUE)) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing def_fd_[ind_]create_type of role %u denied for pid %u, user %u - not in admin_roles!\n", + tid.role, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + break; + + case RI_def_user_create_type: + /* admin for this role and assign for target type */ + /* test admin_role of process / modify */ + if( (err=rsbac_rc_test_admin_roles(tid.role, TRUE)) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing def_user_create_type of role %u denied for pid %u, user %u - not in admin_roles!\n", + tid.role, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + else + { + enum rsbac_adf_req_ret_t result; + + result = rsbac_rc_check_type_comp(T_USER, value.type_id, RCR_ASSIGN, 0); + if( ( (result == NOT_GRANTED) + || (result == UNDEFINED) + ) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing def_user_create_type for role %u to %u denied for user %u - no ASSIGN right for type!\n", + tid.role, + value.type_id, + user); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return -EPERM; + } + } + break; + + case RI_def_process_create_type: + case RI_def_process_chown_type: + case RI_def_process_execute_type: + /* admin for this role and assign for target type */ + /* test admin_role of process / modify */ + if( (err=rsbac_rc_test_admin_roles(tid.role, TRUE)) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + char tmp[80]; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing %s of role %u denied for pid %u, user %u - not in admin_roles!\n", + get_rc_item_name(tmp, item), + tid.role, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + else + { + enum rsbac_adf_req_ret_t result; + + result = rsbac_rc_check_type_comp(T_PROCESS, value.type_id, RCR_ASSIGN, 0); + if( ( (result == NOT_GRANTED) + || (result == UNDEFINED) + ) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing def_process_*_type for role %u to %u denied for user %u - no ASSIGN right for type!\n", + tid.role, + value.type_id, + user); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return -EPERM; + } + } + break; + case RI_def_ipc_create_type: + /* admin for this role and assign for target type */ + /* test admin_role of process / modify */ + if( (err=rsbac_rc_test_admin_roles(tid.role, TRUE)) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing def_ipc_create_type of role %u denied for pid %u, user %u - not in admin_roles!\n", + tid.role, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + else + { + enum rsbac_adf_req_ret_t result; + + result = rsbac_rc_check_type_comp(T_IPC, value.type_id, RCR_ASSIGN, 0); + if( ( (result == NOT_GRANTED) + || (result == UNDEFINED) + ) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing def_ipc_create_type for role %u to %u denied for user %u - no ASSIGN right for type!\n", + tid.role, + value.type_id, + user); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return -EPERM; + } + } + break; + case RI_def_group_create_type: + /* admin for this role and assign for target type */ + /* test admin_role of process / modify */ + if( (err=rsbac_rc_test_admin_roles(tid.role, TRUE)) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + if(err == -EPERM) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing def_group_create_type of role %u denied for pid %u, user %u - not in admin_roles!\n", + tid.role, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + else + { + enum rsbac_adf_req_ret_t result; + + result = rsbac_rc_check_type_comp(T_GROUP, value.type_id, RCR_ASSIGN, 0); + if( ( (result == NOT_GRANTED) + || (result == UNDEFINED) + ) + && (err=rsbac_rc_test_role_admin(TRUE)) + ) + { + rsbac_uid_t user; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing def_group_create_type for role %u to %u denied for user %u - no ASSIGN right for type!\n", + tid.role, + value.type_id, + user); + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return -EPERM; + } + } + break; + case RI_def_unixsock_create_type: + /* admin for this role and assign for target type */ + /* test admin_role of process / modify */ + if ((err = + rsbac_rc_test_admin_roles(tid.role, TRUE)) + && (err = rsbac_rc_test_role_admin(TRUE)) + ) { + if (err == -EPERM) { + rsbac_uid_t user; + + if (!rsbac_get_owner(&user)) { + rsbac_printk(KERN_INFO "rsbac_rc_sys_set_item(): changing def_unixsock_create_type of role %u denied for pid %u, user %u - not in admin_roles\n", + tid.role, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } else { + enum rsbac_adf_req_ret_t result; + + result = + rsbac_rc_check_type_comp(T_UNIXSOCK, + value.type_id, + RCR_ASSIGN, + 0); + if (((result == NOT_GRANTED) + || (result == UNDEFINED) + ) + && (err = + rsbac_rc_test_role_admin(TRUE)) + ) { + rsbac_uid_t user; + + if (!rsbac_get_owner(&user)) { + rsbac_printk(KERN_INFO "rsbac_rc_sys_set_item(): changing def_unixsock_create_type for role %u to %u denied for user %u - no ASSIGN right for type\n", + tid.role, + value.type_id, + user); + } +#ifdef CONFIG_RSBAC_SOFTMODE + if (!rsbac_softmode +#ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] +#endif + ) +#endif + return -EPERM; + } + } + break; + + + case RI_type_comp_fd: + case RI_type_comp_dev: + case RI_type_comp_user: + case RI_type_comp_process: + case RI_type_comp_ipc: + case RI_type_comp_scd: + case RI_type_comp_group: + case RI_type_comp_netdev: + case RI_type_comp_nettemp: + case RI_type_comp_netobj: + { + union rsbac_rc_item_value_t old_value, my_value; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_rc_target_id_t i_rc_tid; + + if(target != RT_ROLE) + return -RSBAC_EINVALIDATTR; + if(!rsbac_rc_test_role_admin(TRUE)) + break; + /* test admin_role of process / modify */ + if((err=rsbac_rc_test_admin_roles(tid.role, TRUE))) + { + if(err == -EPERM) + { + rsbac_uid_t user; + char tmp[80]; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing %s of role %u denied for pid %u, user %u - not in admin_roles!\n", + get_rc_item_name(tmp, item), + tid.role, + current->pid, + user); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + /* test caller's RCR_ACCESS_CONTROL for the type, if we change normal access */ + /* and caller's RCR_SUPERVISOR for the type, if we change special rights */ + /* first get old setting */ + err = rsbac_rc_get_item(ta_number, target, tid, subtid, item, &old_value, NULL); + if(err) { + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + + /* get rc_role of process */ + i_tid.process = task_pid(current); + if ((err=rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, + FALSE))) + { + rsbac_pr_get_error(A_rc_role); + return err; + } + /* get item of process role */ + i_rc_tid.role = i_attr_val1.rc_role; + if ((err=rsbac_rc_get_item(ta_number, + RT_ROLE, + i_rc_tid, + subtid, + item, + &my_value, + NULL))) + { + rsbac_rc_pr_get_error(item); + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + + /* check planned changes for type */ + if( /* Want to change normal rights to this type? Need RCR_ACCESS_CONTROL. */ + ( ( (old_value.rights & RSBAC_ALL_REQUEST_VECTOR) + != (value.rights & RSBAC_ALL_REQUEST_VECTOR) + ) + && (!(my_value.rights & RSBAC_RC_RIGHTS_VECTOR(RCR_ACCESS_CONTROL))) + ) + || + /* Want to change special rights to this type? Need RCR_SUPERVISOR. */ + ( ( (old_value.rights & RSBAC_RC_SPECIAL_RIGHTS_VECTOR) + != (value.rights & RSBAC_RC_SPECIAL_RIGHTS_VECTOR) + ) + && (!(my_value.rights & RSBAC_RC_RIGHTS_VECTOR(RCR_SUPERVISOR))) + ) + ) + { + /* check failed. Last resort: Classical admin_type. */ + if((err=rsbac_rc_test_role_admin(TRUE))) + { + if(err == -EPERM) + { + rsbac_uid_t user; + char tmp[80]; + + if(!rsbac_get_owner(&user)) + { + rsbac_printk(KERN_INFO + "rsbac_rc_sys_set_item(): changing %s of role %u denied for pid %u, user %u, role %u - insufficent rights!\n", + get_rc_item_name(tmp, item), + tid.role, + current->pid, + user, + i_attr_val1.rc_role); + } + } + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] + #endif + ) + #endif + return err; + } + } + } + break; + + default: + return -RSBAC_EINVALIDATTR; + } + } + + /* pass on */ + return(rsbac_rc_set_item(ta_number, target, tid, subtid, item, value, ttl)); + } + +/* Set own role, if allowed ( = in role_comp vector of current role) */ +int rsbac_rc_sys_change_role(rsbac_rc_role_id_t role, char __user * pass) +{ + int err; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; +#ifdef CONFIG_RSBAC_UM + union rsbac_rc_item_value_t i_rc_item_val1; + char *k_pass; +#endif + +#ifdef CONFIG_RSBAC_SWITCH_RC + if (rsbac_switch_rc) +#endif + { + union rsbac_rc_target_id_t i_rc_subtid; + + i_tid.process = task_pid(current); + /* get rc_role of process */ + if ((err = rsbac_get_attr(SW_RC, + T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, FALSE))) { + rsbac_printk(KERN_WARNING "rsbac_rc_sys_change_role(): rsbac_get_attr() returned error %i\n", + err); + goto out; + } + + /* check role_comp of role */ + i_rc_subtid.role = role; + if (!rsbac_rc_check_comp(i_attr_val1.rc_role, + i_rc_subtid, RI_role_comp, 0)) { + rsbac_uid_t user; + + if (!rsbac_get_owner(&user)) { + rsbac_printk(KERN_INFO "rsbac_rc_sys_change_role(): changing from role %u to %u denied for pid %u, user %u, role %u - roles not compatible\n", + i_attr_val1.rc_role, + role, + pid_nr(i_tid.process), + user, i_attr_val1.rc_role); + } +#ifdef CONFIG_RSBAC_SOFTMODE + if (!rsbac_softmode +#ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] +#endif + ) +#endif + { + err = -EPERM; + goto out; + } + } +#ifdef CONFIG_RSBAC_UM + /* need to make sure UM is compilled in and active + * XXX what to do about softmode here + */ + if ((err = rsbac_rc_get_item(0, RT_ROLE, i_rc_subtid, i_rc_subtid, + RI_req_reauth, + &i_rc_item_val1, NULL))) { + rsbac_printk(KERN_WARNING "rsbac_rc_sys_change_role(): rsbac_rc_get_item() returned error %i\n", + err); + err = -EPERM; + goto out; + } + if (i_rc_item_val1.req_reauth) { + rsbac_uid_t user; + + if (!pass) { + rsbac_printk(KERN_WARNING "rsbac_rc_sys_change_role(): password required for switching to role %u\n", + role); + err = -EPERM; + goto out; + } + k_pass = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (!k_pass) { + err = -RSBAC_ENOMEM; + goto out; + } + err = strncpy_from_user(k_pass, pass, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + goto out_free; + k_pass[RSBAC_MAXNAMELEN - 1] = 0; + err = rsbac_get_owner(&user); + if (err) { + rsbac_printk(KERN_WARNING "rsbac_rc_sys_change_role(): rsbac_rc_get_item() returned error %i\n", + err); + goto out_free; + } + err = rsbac_um_check_pass(user, k_pass); + if (err) { + goto out_free; + } + } +#endif + + } + + /* OK, check passed. Set role. */ + i_tid.process = task_pid(current); + i_attr_val1.rc_role = role; + if (rsbac_set_attr(SW_RC, T_PROCESS, i_tid, A_rc_role, i_attr_val1)) { /* failed! */ + rsbac_printk(KERN_WARNING "rsbac_rc_sys_change_role(): rsbac_set_attr() returned error\n"); + err = -RSBAC_EWRITEFAILED; + } + else + err = 0; + +out: + return err; + +#ifdef CONFIG_RSBAC_UM +out_free: + memset(k_pass, 0, RSBAC_MAXNAMELEN); + rsbac_kfree(k_pass); + goto out; +#endif +} + +/* Getting own effective rights */ +int rsbac_rc_sys_get_eff_rights( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_rc_request_vector_t * request_vector, + rsbac_time_t * ttl_p) + { + union rsbac_target_id_t i_tid; + enum rsbac_attribute_t i_attr = A_none; + union rsbac_attribute_value_t i_attr_val1; + union rsbac_attribute_value_t i_attr_val2; + int err; + enum rsbac_rc_item_t i_rc_item; + union rsbac_rc_target_id_t i_rc_tid; + union rsbac_rc_target_id_t i_rc_subtid; + union rsbac_rc_item_value_t i_rc_item_val1; + + i_tid.process = task_pid(current); + /* get rc_role of process */ + if ((err=rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, + FALSE))) + { + rsbac_printk(KERN_WARNING + "rsbac_rc_sys_get_eff_rights(): rsbac_get_attr() returned error %i!\n",err); + return -RSBAC_EREADFAILED; + } + + switch(target) + { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + i_attr = A_rc_type_fd; + i_rc_item = RI_type_comp_fd; + break; + case T_DEV: + i_attr = A_rc_type; + i_rc_item = RI_type_comp_dev; + break; + case T_IPC: + i_attr = A_rc_type; + i_rc_item = RI_type_comp_ipc; + break; + case T_PROCESS: + i_attr = A_rc_type; + i_rc_item = RI_type_comp_process; + break; + case T_SCD: /* special case! */ + if(tid.scd >= RST_none) + return -RSBAC_EINVALIDTARGET; + i_rc_item = RI_type_comp_scd; + break; + case T_GROUP: + i_attr = A_rc_type; + i_rc_item = RI_type_comp_group; + break; + case T_NETDEV: + i_attr = A_rc_type; + i_rc_item = RI_type_comp_netdev; + break; + case T_NETTEMP: + i_attr = A_rc_type_nt; + i_rc_item = RI_type_comp_nettemp; + break; + case T_NETOBJ: + i_attr = A_rc_type; + i_rc_item = RI_type_comp_netobj; + break; + default: + return -RSBAC_EINVALIDTARGET; + } + /* get rc_type of target */ + if(target == T_SCD) + { + i_attr_val2.rc_type = tid.scd; + } + else + { + if ((err=rsbac_get_attr(SW_RC, + target, + tid, + i_attr, + &i_attr_val2, + TRUE))) + { + rsbac_printk(KERN_WARNING + "rsbac_rc_sys_get_eff_rights(): rsbac_get_attr() returned error %i!\n",err); + return -RSBAC_EREADFAILED; + } + } + /* get type_comp_xxx of role for type and target */ + i_rc_tid.role = i_attr_val1.rc_role; + i_rc_subtid.type = i_attr_val2.rc_type; + if ((err=rsbac_rc_get_item(ta_number, + RT_ROLE, + i_rc_tid, + i_rc_subtid, + i_rc_item, + &i_rc_item_val1, + ttl_p))) + { + rsbac_printk(KERN_WARNING + "rsbac_rc_sys_get_eff_rights(): rsbac_rc_get_item() returned error %i!\n",err); + return -RSBAC_EREADFAILED; + } + /* extract value */ + *request_vector = i_rc_item_val1.rights; + /* Ready. */ + return 0; + } + +int rsbac_rc_sys_get_current_role(rsbac_rc_role_id_t * role_p) + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + int err; + + /* get rc_role of process */ + i_tid.process = task_pid(current); + if ((err=rsbac_get_attr(SW_RC, T_PROCESS, + i_tid, + A_rc_role, + &i_attr_val1, + FALSE))) + { + rsbac_printk(KERN_WARNING + "rsbac_rc_sys_get_current_role(): rsbac_get_attr() returned error %i!\n",err); + return -RSBAC_EREADFAILED; + } + *role_p = i_attr_val1.rc_role; + /* Ready. */ + return 0; + } + +int rsbac_rc_select_fd_create_type(rsbac_rc_type_id_t type) +{ + + int res; + + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val; + + /* sanity checks */ + if (type != RC_type_use_fd) { + if (!rsbac_rc_type_exists(0, T_FILE, type)) + return -RSBAC_EINVALIDVALUE; + if (!rsbac_rc_check_type_comp(T_FILE, type, RCR_SELECT, task_pid(current))) { +#ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode +#ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RC] +#endif + ) +#endif + return -EPERM; + } + } + + tid.process = task_pid(current); + attr_val.rc_select_type = type; + if ((res = rsbac_set_attr(SW_RC, + T_PROCESS, + tid, + A_rc_select_type, + attr_val))) { + rsbac_printk(KERN_WARNING "rsbac_rc_select_fd_create_type(): rsbac_set_attr() returned error %i\n", res); + return -EPERM; + } + + return 0; +} + +/* end of rsbac/adf/rc/syscalls.c */ diff --git a/rsbac/adf/reg/Makefile b/rsbac/adf/reg/Makefile new file mode 100644 index 000000000000..2e6fac064b78 --- /dev/null +++ b/rsbac/adf/reg/Makefile @@ -0,0 +1,13 @@ +# +# File: rsbac/adf/reg/Makefile +# +# Makefile for the Linux rsbac REG / registration of decision modules +# +# Author and (c) 1999-2012 Amon Ott +# + +obj-y := reg_main.o +ifeq ($(CONFIG_RSBAC_REG_SAMPLES),y) +obj-m += reg_sample1.o reg_sample3.o kproc_hide.o modules_off.o +endif + diff --git a/rsbac/adf/reg/kproc_hide.c b/rsbac/adf/reg/kproc_hide.c new file mode 100644 index 000000000000..93d03282d821 --- /dev/null +++ b/rsbac/adf/reg/kproc_hide.c @@ -0,0 +1,121 @@ +/* + * RSBAC REG decision module kproc_hide. Hiding kernel processes. + * + * Author and (c) 2004 Michal Purzynski + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Michal Purzynski"); +MODULE_DESCRIPTION("RSBAC REG kproc_hide decision module"); +MODULE_LICENSE("GPL"); + +static long handle = 9999992; + +/**** Helper Functions ****/ + +/********************************************************************** +Description: Checks if process is a kernel process. +Parameters: Pid of checking process. +Return value: 1 if is, 0 otherwise. +**********************************************************************/ + +int is_kproc(struct pid *pid) +{ + struct task_struct *tid_task; + + tid_task = pid_task(pid, PIDTYPE_PID); + + if (tid_task->mm == NULL) + return 1; + else + return 0; +} + +/**** Decision Functions ****/ + +static int request_func(enum rsbac_adf_request_t request, + rsbac_pid_t owner_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + + switch (request) { + case R_GET_STATUS_DATA: + switch (target) { + case T_PROCESS: + if (is_kproc(tid.process)) + return NOT_GRANTED; + default: + return DO_NOT_CARE; + } + default: + return DO_NOT_CARE; + } + +/* + if (request == R_GET_STATUS_DATA && target == T_PROCESS && is_kproc(tid.process)) + return NOT_GRANTED; + else + return GRANTED; +*/ +} + +/**** Init ****/ + +int init_module(void) +{ + struct rsbac_reg_entry_t entry; + + rsbac_printk(KERN_INFO "RSBAC REG decision module kproc_hide: Initializing.\n"); + + /* clearing registration entries */ + memset(&entry, 0, sizeof(entry)); + + strcpy(entry.name, "RSBAC REG kproc_hide ADF module"); + rsbac_printk(KERN_INFO "RSBAC REG decision module kproc_hide: REG Version: %u, Name: %s, Handle: %li\n", + RSBAC_REG_VERSION, entry.name, handle); + + entry.handle = handle; + entry.request_func = request_func; + entry.switch_on = TRUE; + rsbac_printk(KERN_INFO "RSBAC REG decision module kproc_hide: Registering to ADF.\n"); + + if(rsbac_reg_register(RSBAC_REG_VERSION, entry) < 0) { + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 1: Registering failed. Unloading.\n"); + return -ENOEXEC; + } + + rsbac_printk(KERN_INFO "RSBAC REG decision module kproc_hide: Loaded.\n"); + + return 0; +} + +void cleanup_module(void) +{ + rsbac_printk(KERN_INFO "RSBAC REG decision module kproc_hide: Unregistering.\n"); + + if(rsbac_reg_unregister(handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module kproc_hide: Unregistering failed - beware of possible system failure!\n"); + } + + rsbac_printk(KERN_INFO "RSBAC REG decision module kproc_hide: Unloaded.\n"); +} + diff --git a/rsbac/adf/reg/modules_off.c b/rsbac/adf/reg/modules_off.c new file mode 100644 index 000000000000..e19a488011f2 --- /dev/null +++ b/rsbac/adf/reg/modules_off.c @@ -0,0 +1,90 @@ +/* + * RSBAC REG decision module kproc_hide. Disabling kernel modules support. + * + * Author and (c) 2004 Michal Purzynski + * Adjusted 2011 Amon Ott + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Michal Purzynski"); +MODULE_DESCRIPTION("RSBAC REG modules_off decision module"); +MODULE_LICENSE("GPL"); + +static long handle = 9999991; + +/**** Decision Functions ****/ + +static int request_func (enum rsbac_adf_request_t request, + rsbac_pid_t owner_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + switch (request) { + case R_ADD_TO_KERNEL: + case R_REMOVE_FROM_KERNEL: + return NOT_GRANTED; + default: + return DO_NOT_CARE; + } +} + +/**** Init ****/ + +int init_module(void) +{ + + struct rsbac_reg_entry_t entry; + + rsbac_printk(KERN_INFO "RSBAC REG decision module modules_off: Initializing.\n"); + + /* clearing registration entries */ + memset(&entry, 0, sizeof(entry)); + + strcpy(entry.name, "RSBAC REG modules_off ADF module"); + rsbac_printk(KERN_INFO "RSBAC REG decision module modules_off: REG Version: %u, Name: %s, Handle: %li\n",RSBAC_REG_VERSION, entry.name, handle); + + entry.handle = handle; + entry.request_func = request_func; + entry.switch_on = TRUE; + + rsbac_printk(KERN_INFO "RSBAC REG decision module modules_off: Registering to ADF.\n"); + + if(rsbac_reg_register(RSBAC_REG_VERSION, entry) < 0) + { + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 1: Registering failed. Unloading.\n"); + return -ENOEXEC; + } + + rsbac_printk(KERN_INFO "RSBAC REG decision module modules_off: Loaded.\n"); + + return 0; +} + +void cleanup_module(void) +{ + rsbac_printk(KERN_INFO "RSBAC REG decision module modules_off: Unregistering.\n"); + + if(rsbac_reg_unregister(handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module modules_off: Unregistering failed - beware of possible system failure!\n"); + } + + rsbac_printk(KERN_INFO "RSBAC REG decision module modules_off: Unloaded.\n"); +} + diff --git a/rsbac/adf/reg/reg_main.c b/rsbac/adf/reg/reg_main.c new file mode 100644 index 000000000000..de803a463356 --- /dev/null +++ b/rsbac/adf/reg/reg_main.c @@ -0,0 +1,928 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - REG / Decision Module Registration */ +/* File: rsbac/adf/reg/main.c */ +/* */ +/* Author and (c) 1999-2011: Amon Ott */ +/* */ +/* Last modified: 12/Jul/2011 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +static struct rsbac_reg_list_head_t list_head; +static struct rsbac_reg_sc_list_head_t sc_list_head; + +/************************************************* */ +/* Internal functions */ +/************************************************* */ + +static void reg_read_lock(void) + { + spin_lock(&list_head.lock); + while(list_head.readers < 0) + { + spin_unlock(&list_head.lock); + spin_lock(&list_head.lock); + } + list_head.readers++; + spin_unlock(&list_head.lock); + } + +static void reg_read_unlock(void) + { + spin_lock(&list_head.lock); + list_head.readers--; + spin_unlock(&list_head.lock); + } + +static void reg_write_lock(void) + { + spin_lock(&list_head.lock); + while(list_head.readers != 0) + { + spin_unlock(&list_head.lock); + spin_lock(&list_head.lock); + } + list_head.readers = -1; + spin_unlock(&list_head.lock); + } + +static void reg_write_unlock(void) + { + spin_lock(&list_head.lock); + list_head.readers = 0; + spin_unlock(&list_head.lock); + } + +static void reg_sc_read_lock(void) + { + spin_lock(&sc_list_head.lock); + while(sc_list_head.readers < 0) + { + spin_unlock(&sc_list_head.lock); + spin_lock(&sc_list_head.lock); + } + sc_list_head.readers++; + spin_unlock(&sc_list_head.lock); + } + +static void reg_sc_read_unlock(void) + { + spin_lock(&sc_list_head.lock); + sc_list_head.readers--; + spin_unlock(&sc_list_head.lock); + } + +static void reg_sc_write_lock(void) + { + spin_lock(&sc_list_head.lock); + while(sc_list_head.readers != 0) + { + spin_unlock(&sc_list_head.lock); + spin_lock(&sc_list_head.lock); + } + sc_list_head.readers = -1; + spin_unlock(&sc_list_head.lock); + } + +static void reg_sc_write_unlock(void) + { + spin_lock(&sc_list_head.lock); + sc_list_head.readers = 0; + spin_unlock(&sc_list_head.lock); + } + +/* lookup_item() */ +static struct rsbac_reg_list_item_t * lookup_item(rsbac_reg_handle_t handle) + { + struct rsbac_reg_list_item_t * curr = list_head.curr; + + /* is the current item the one we look for? yes -> return, else search */ + if (curr && (curr->entry.handle == handle)) + return (curr); + + curr = list_head.head; + while (curr && (curr->entry.handle != handle)) + curr = curr->next; + if (curr) + list_head.curr=curr; + return (curr); + }; + +/* lookup_sc_item_reg() */ +static struct rsbac_reg_sc_list_item_t * lookup_sc_item_reg(rsbac_reg_handle_t handle) + { + struct rsbac_reg_sc_list_item_t * curr = sc_list_head.curr; + + /* is the current item the one we look for? yes -> return, else search */ + if (curr && (curr->entry.registration_handle == handle)) + return (curr); + + curr = sc_list_head.head; + while (curr && (curr->entry.registration_handle != handle)) + curr = curr->next; + if (curr) + sc_list_head.curr=curr; + return (curr); + }; + +/* lookup_sc_item_dis() */ +static struct rsbac_reg_sc_list_item_t * lookup_sc_item_dis(rsbac_reg_handle_t handle) + { + struct rsbac_reg_sc_list_item_t * curr = sc_list_head.curr; + + /* is the current item the one we look for? yes -> return, else search */ + if (curr && (curr->entry.dispatcher_handle == handle)) + return (curr); + + curr = sc_list_head.head; + while (curr && (curr->entry.dispatcher_handle != handle)) + curr = curr->next; + if (curr) + sc_list_head.curr=curr; + return (curr); + }; + +static struct rsbac_reg_list_item_t* + add_item(struct rsbac_reg_entry_t entry) + { + struct rsbac_reg_list_item_t * new_item_p = NULL; + + if ( !(new_item_p = (struct rsbac_reg_list_item_t *) + rsbac_kmalloc(sizeof(*new_item_p))) ) + return(NULL); + new_item_p->entry.handle = entry.handle; + strncpy(new_item_p->entry.name, entry.name, RSBAC_REG_NAME_LEN); + new_item_p->entry.name[RSBAC_REG_NAME_LEN] = 0; + new_item_p->entry.request_func = entry.request_func; + new_item_p->entry.set_attr_func = entry.set_attr_func; + new_item_p->entry.need_overwrite_func = entry.need_overwrite_func; + new_item_p->entry.write_func = entry.write_func; + new_item_p->entry.mount_func = entry.mount_func; + new_item_p->entry.umount_func = entry.umount_func; + new_item_p->entry.check_func = entry.check_func; + new_item_p->entry.switch_on = entry.switch_on; + + if (!list_head.head) + { + list_head.head=new_item_p; + list_head.tail=new_item_p; + list_head.curr=new_item_p; + list_head.count = 1; + new_item_p->prev=NULL; + new_item_p->next=NULL; + } + else + { + new_item_p->prev=list_head.tail; + new_item_p->next=NULL; + list_head.tail->next=new_item_p; + list_head.tail=new_item_p; + list_head.curr=new_item_p; + list_head.count++; + }; + return(new_item_p); + }; + +static struct rsbac_reg_sc_list_item_t* + add_sc_item(struct rsbac_reg_syscall_entry_t entry) + { + struct rsbac_reg_sc_list_item_t * new_item_p = NULL; + + if ( !(new_item_p = (struct rsbac_reg_sc_list_item_t *) + rsbac_kmalloc(sizeof(*new_item_p))) ) + return(NULL); + new_item_p->entry.registration_handle = entry.registration_handle; + new_item_p->entry.dispatcher_handle = entry.dispatcher_handle; + strncpy(new_item_p->entry.name, entry.name, RSBAC_REG_NAME_LEN); + new_item_p->entry.name[RSBAC_REG_NAME_LEN] = 0; + new_item_p->entry.syscall_func = entry.syscall_func; + + if (!sc_list_head.head) + { + sc_list_head.head=new_item_p; + sc_list_head.tail=new_item_p; + sc_list_head.curr=new_item_p; + sc_list_head.count = 1; + new_item_p->prev=NULL; + new_item_p->next=NULL; + } + else + { + new_item_p->prev=sc_list_head.tail; + new_item_p->next=NULL; + sc_list_head.tail->next=new_item_p; + sc_list_head.tail=new_item_p; + sc_list_head.curr=new_item_p; + sc_list_head.count++; + }; + return(new_item_p); + }; + +static void remove_item(rsbac_reg_handle_t handle) + { + struct rsbac_reg_list_item_t * item_p; + + /* first we must locate the item. */ + if ( (item_p = lookup_item(handle)) ) + { /* ok, item was found */ + if ( (list_head.head == item_p) ) + { /* item is head */ + if ( (list_head.tail == item_p) ) + { /* item is head and tail = only item -> list will be empty*/ + list_head.head = NULL; + list_head.tail = NULL; + } + else + { /* item is head, but not tail -> next item becomes head */ + item_p->next->prev = NULL; + list_head.head = item_p->next; + }; + } + else + { /* item is not head */ + if ( (list_head.tail == item_p) ) + { /*item is not head, but tail -> previous item becomes tail*/ + item_p->prev->next = NULL; + list_head.tail = item_p->prev; + } + else + { /* item is neither head nor tail -> item is cut out */ + item_p->prev->next = item_p->next; + item_p->next->prev = item_p->prev; + }; + }; + + /* curr is no longer valid -> reset */ + list_head.curr=NULL; + /* adjust counter */ + list_head.count--; + /* now we can remove the item from memory */ + rsbac_kfree(item_p); + }; /* end of if: item was found */ + }; /* end of remove_item() */ + +static void remove_sc_item(rsbac_reg_handle_t handle) + { + struct rsbac_reg_sc_list_item_t * item_p; + + /* first we must locate the item. */ + if ( (item_p = lookup_sc_item_reg(handle)) ) + { /* ok, item was found */ + if ( (sc_list_head.head == item_p) ) + { /* item is head */ + if ( (sc_list_head.tail == item_p) ) + { /* item is head and tail = only item -> sc_list will be empty*/ + sc_list_head.head = NULL; + sc_list_head.tail = NULL; + } + else + { /* item is head, but not tail -> next item becomes head */ + item_p->next->prev = NULL; + sc_list_head.head = item_p->next; + }; + } + else + { /* item is not head */ + if ( (sc_list_head.tail == item_p) ) + { /*item is not head, but tail -> previous item becomes tail*/ + item_p->prev->next = NULL; + sc_list_head.tail = item_p->prev; + } + else + { /* item is neither head nor tail -> item is cut out */ + item_p->prev->next = item_p->next; + item_p->next->prev = item_p->prev; + }; + }; + + /* curr is no longer valid -> reset */ + sc_list_head.curr=NULL; + /* adjust counter */ + sc_list_head.count--; + /* now we can remove the item from memory */ + rsbac_kfree(item_p); + }; /* end of if: item was found */ + }; /* end of remove_item() */ + + +/************************************************* */ +/* PROC support */ +/************************************************* */ + +#if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS) +static int +reg_modules_proc_show(struct seq_file *m, void *v) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + struct rsbac_reg_list_item_t * item_p; + struct rsbac_reg_sc_list_item_t * sc_item_p; + + if (!rsbac_is_initialized()) + return (-ENOSYS); + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "reg_modules_proc_info(): calling ADF\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + seq_printf(m, "RSBAC REG registered decision modules\n-------------------------------------\n"); + + reg_read_lock(); + item_p=list_head.head; + while(item_p) + { + if(item_p->entry.name[0] == 0) + seq_printf(m, "(no name)\n"); + else + seq_printf(m, "%s\n", + item_p->entry.name); + item_p = item_p->next; + } + reg_read_unlock(); + + seq_printf(m, "\n %i module entries used.\n", + list_head.count); + seq_printf(m, "\nRSBAC REG registered system calls\n---------------------------------\n"); + + reg_sc_read_lock(); + sc_item_p=sc_list_head.head; + while(sc_item_p) + { + if(sc_item_p->entry.name[0] == 0) + seq_printf(m, "%u: (no name)\n", + sc_item_p->entry.dispatcher_handle); + else + seq_printf(m, "%u: %s\n", + sc_item_p->entry.dispatcher_handle, + sc_item_p->entry.name); + sc_item_p = sc_item_p->next; + } + reg_sc_read_unlock(); + + seq_printf(m, "\n %i syscall entries used.\n", + sc_list_head.count); + return 0; +} + +static int reg_modules_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, reg_modules_proc_show, NULL); +} + +static const struct file_operations reg_modules_proc_fops = { + .owner = THIS_MODULE, + .open = reg_modules_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *reg_modules; + +#endif /* PROC */ + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +void rsbac_reg_init(void) +#else +void __init rsbac_reg_init(void) +#endif + { + if (rsbac_is_initialized()) + { + rsbac_printk(KERN_WARNING "rsbac_reg_init(): RSBAC already initialized\n"); + return; + } + /* init data structures */ + rsbac_printk(KERN_INFO "rsbac_reg_init(): Initializing RSBAC: REG module and syscall registration\n"); + + spin_lock_init(&list_head.lock); + list_head.readers = 0; + list_head.head = NULL; + list_head.tail = NULL; + list_head.curr = NULL; + list_head.count = 0; + spin_lock_init(&sc_list_head.lock); + sc_list_head.readers = 0; + sc_list_head.head = NULL; + sc_list_head.tail = NULL; + sc_list_head.curr = NULL; + sc_list_head.count = 0; + + /* init proc entry */ + #if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS) + { + reg_modules = proc_create(RSBAC_REG_PROC_NAME, + S_IFREG | S_IRUGO, + proc_rsbac_root_p, ®_modules_proc_fops); + } + #endif + } + + +inline enum rsbac_adf_req_ret_t + rsbac_adf_request_reg (enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + enum rsbac_adf_req_ret_t result = DO_NOT_CARE; + struct rsbac_reg_list_item_t * item_p; + + reg_read_lock(); + item_p=list_head.head; + while(item_p) + { + if( item_p->entry.request_func + #ifdef CONFIG_RSBAC_SWITCH_REG + && item_p->entry.switch_on + #endif + ) + result = adf_and_plus(result, + item_p->entry.request_func (request, + caller_pid, + target, + tid, + attr, + attr_val, + owner) ); + item_p=item_p->next; + } + reg_read_unlock(); + return result; + } + +inline int rsbac_adf_set_attr_reg( + enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + int error = 0; + int suberror; + struct rsbac_reg_list_item_t * item_p; + + reg_read_lock(); + item_p=list_head.head; + while(item_p) + { + if( item_p->entry.set_attr_func + #ifdef CONFIG_RSBAC_SWITCH_REG + && item_p->entry.switch_on + #endif + ) + { + suberror = item_p->entry.set_attr_func (request, + caller_pid, + target, + tid, + new_target, + new_tid, + attr, + attr_val, + owner); + if(suberror) + error = suberror; + } + item_p = item_p->next; + } + reg_read_unlock(); + return error; + } + + +#ifdef CONFIG_RSBAC_SECDEL +inline rsbac_boolean_t rsbac_need_overwrite_reg(struct dentry * dentry_p) + { + rsbac_boolean_t need_overwrite = FALSE; + struct rsbac_reg_list_item_t * item_p; + + reg_read_lock(); + item_p=list_head.head; + while(item_p) + { + if( item_p->entry.need_overwrite_func + #ifdef CONFIG_RSBAC_SWITCH_REG + && item_p->entry.switch_on + #endif + ) + if(!need_overwrite) + need_overwrite = item_p->entry.need_overwrite_func(dentry_p); + item_p=item_p->next; + } + reg_read_unlock(); + return need_overwrite; + } +#endif + +/* mounting and umounting */ +inline int rsbac_mount_reg(kdev_t kdev) + { + int error = 0; + int suberror; + struct rsbac_reg_list_item_t * item_p; + + reg_read_lock(); + item_p=list_head.head; + while(item_p) + { + if( item_p->entry.mount_func + ) + { + suberror = item_p->entry.mount_func(kdev); + if(suberror < 0) + error = suberror; + } + item_p=item_p->next; + } + reg_read_unlock(); + return error; + } + +inline int rsbac_umount_reg(kdev_t kdev) + { + int error = 0; + int suberror; + struct rsbac_reg_list_item_t * item_p; + + reg_read_lock(); + item_p=list_head.head; + while(item_p) + { + if( item_p->entry.umount_func + ) + { + suberror = item_p->entry.umount_func(kdev); + if(suberror < 0) + error = suberror; + } + item_p=item_p->next; + } + reg_read_unlock(); + return error; + } + +#if defined(CONFIG_RSBAC_AUTO_WRITE) +inline int rsbac_write_reg(void) + { + int count = 0; + int subcount = 0; + struct rsbac_reg_list_item_t * item_p; + + reg_read_lock(); + item_p=list_head.head; + while(item_p) + { + if(item_p->entry.write_func) + { + subcount = item_p->entry.write_func(FALSE); + if(subcount > 0) + { + count += subcount; + } + else + if(subcount < 0) + { + if(subcount != -RSBAC_ENOTWRITABLE) + { + rsbac_printk(KERN_WARNING + "rsbac_write_reg(): write_func() for REG module %s returned error %i\n", + item_p->entry.name, subcount); + } + } + } + item_p=item_p->next; + } + reg_read_unlock(); +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_write) + { + rsbac_printk(KERN_DEBUG "rsbac_write_reg(): %u lists written.\n", + count); + } +#endif + return count; + } +#endif /* CONFIG_RSBAC_AUTO_WRITE */ + +/* Status checking */ +inline int rsbac_check_reg(int correct, int check_inode) + { + int error = 0; + int suberror; + struct rsbac_reg_list_item_t * item_p; + + reg_read_lock(); + item_p=list_head.head; + while(item_p) + { + if( item_p->entry.check_func + ) + { + suberror = item_p->entry.check_func(correct, check_inode); + if(suberror < 0) + error = suberror; + } + item_p=item_p->next; + } + reg_read_unlock(); + return error; + } + + +/* + * Register an ADF decision module + * Returns given positive handle or negative error code + */ + +EXPORT_SYMBOL(rsbac_reg_register); + +rsbac_reg_handle_t rsbac_reg_register( rsbac_version_t version, + struct rsbac_reg_entry_t entry) + { + if(version != RSBAC_REG_VERSION) + return(-RSBAC_EINVALIDVERSION); + + /* check entry */ + if( ( !entry.request_func + && !entry.set_attr_func + && !entry.need_overwrite_func + && !entry.write_func + && !entry.mount_func + && !entry.umount_func + ) + || (entry.handle <= 0) + ) + return -RSBAC_EINVALIDVALUE; + + reg_write_lock(); + if(lookup_item(entry.handle)) + { + rsbac_printk(KERN_INFO "rsbac_reg_register: Handle in use, registering failed: %s.\n", + entry.name); + entry.handle = -RSBAC_EEXISTS; + } + else + { + if(!add_item(entry)) + { + entry.name[RSBAC_REG_NAME_LEN] = 0; + rsbac_printk(KERN_INFO "rsbac_reg_register: registering failed for %s.\n", + entry.name); + entry.handle = -RSBAC_ECOULDNOTADDITEM; + } +#ifdef CONFIG_RSBAC_DEBUG + else + if(rsbac_debug_reg) + { + rsbac_printk(KERN_DEBUG "rsbac_reg_register: module %s registered.\n", + entry.name); + } +#endif + } + reg_write_unlock(); + return entry.handle; + } + +/* + * Switch module on or off - for 'normal' modules this is done by general + * function. This is a dummy, if module switching is disabled. + */ + +EXPORT_SYMBOL(rsbac_reg_switch); + +int rsbac_reg_switch (rsbac_reg_handle_t handle, rsbac_boolean_t value) + { +#ifdef CONFIG_RSBAC_SWITCH_REG + struct rsbac_reg_list_item_t * item_p; + int err=0; + + if((value != FALSE) && (value != TRUE)) + return -RSBAC_EINVALIDVALUE; + reg_read_lock(); + item_p = lookup_item(handle); + if(item_p) + { + item_p->entry.switch_on = value; +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_reg) + { + rsbac_printk(KERN_DEBUG "rsbac_reg_switch: module %s switched to %i.\n", + item_p->entry.name, + value); + } +#endif + } + else + err = -RSBAC_EINVALIDTARGET; + reg_read_unlock(); + return err; +#else + return(-RSBAC_EINVALIDTARGET); +#endif + }; + +/* + * Unregister an ADF decision module + * Returns 0 on success or negative error code. Be careful not to unregister + * modules you did not register yourself. + */ + +EXPORT_SYMBOL(rsbac_reg_unregister); + +int rsbac_reg_unregister(rsbac_reg_handle_t handle) + { + int err=0; + + if(handle <= 0) + return -RSBAC_EINVALIDVALUE; + + reg_write_lock(); + if(lookup_item(handle)) + { + remove_item(handle); +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_reg) + { + rsbac_printk(KERN_DEBUG "rsbac_reg_unregister: module unregistered.\n"); + } +#endif + } + else + { + err = -RSBAC_EINVALIDTARGET; +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_reg) + { + rsbac_printk(KERN_DEBUG "rsbac_reg_unregister: module unregistering failed.\n"); + } +#endif + } + reg_write_unlock(); + return err; + } + + +/* + * Register a system call + * Returns given positive handle or negative error code + */ + +EXPORT_SYMBOL(rsbac_reg_register_syscall); + +rsbac_reg_handle_t rsbac_reg_register_syscall( rsbac_version_t version, + struct rsbac_reg_syscall_entry_t entry) + { + if(version != RSBAC_REG_VERSION) + return(-RSBAC_EINVALIDVERSION); + + /* check entry */ + if( !entry.syscall_func + || (entry.registration_handle <= 0) + || (entry.dispatcher_handle <= 0) + ) + return -RSBAC_EINVALIDVALUE; + + reg_sc_write_lock(); + if(lookup_sc_item_reg(entry.registration_handle)) + { + rsbac_printk(KERN_INFO "rsbac_reg_register_syscall: Registration handle in use, registering failed: %s.\n", + entry.name); + entry.registration_handle = -RSBAC_EEXISTS; + } + else + if(lookup_sc_item_dis(entry.dispatcher_handle)) + { + rsbac_printk(KERN_INFO "rsbac_reg_register_syscall: Dispatcher handle in use, registering failed: %s.\n", + entry.name); + entry.registration_handle = -RSBAC_EEXISTS; + } + else + { + entry.name[RSBAC_REG_NAME_LEN] = 0; + if(!add_sc_item(entry)) + { + rsbac_printk(KERN_INFO "rsbac_reg_register_syscall: registering failed for %s.\n", + entry.name); + entry.registration_handle = -RSBAC_ECOULDNOTADDITEM; + } +#ifdef CONFIG_RSBAC_DEBUG + else + if(rsbac_debug_reg) + { + rsbac_printk(KERN_DEBUG "rsbac_reg_register_syscall: syscall %s registered.\n", + entry.name); + } +#endif + } + reg_sc_write_unlock(); + return entry.registration_handle; + } + +/* + * Unregister a system call + * Returns 0 on success or negative error code. Be careful not to unregister + * syscalls you did not register yourself. + */ + +EXPORT_SYMBOL(rsbac_reg_unregister_syscall); + +int rsbac_reg_unregister_syscall(rsbac_reg_handle_t handle) + { + int err=0; + + if(handle <= 0) + return -RSBAC_EINVALIDVALUE; + + reg_sc_write_lock(); + if(lookup_sc_item_reg(handle)) + { + remove_sc_item(handle); +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_reg) + { + rsbac_printk(KERN_DEBUG "rsbac_reg_unregister_syscall: syscall unregistered.\n"); + } +#endif + } + else + { + err = -RSBAC_EINVALIDTARGET; + rsbac_printk(KERN_INFO "rsbac_reg_unregister_syscall: syscall unregistering failed for invalid handle!\n"); + } + reg_sc_write_unlock(); + return err; + } + +int rsbac_reg_syscall(rsbac_reg_handle_t handle, + void __user * arg) + { + int err = 0; + struct rsbac_reg_sc_list_item_t * item_p; + + reg_sc_read_lock(); + item_p=lookup_sc_item_dis(handle); + if(item_p && item_p->entry.syscall_func) + { + err = item_p->entry.syscall_func(arg); + } + else + { + err = -RSBAC_EINVALIDTARGET; + } + reg_sc_read_unlock(); + return err; + } + +/* end of rsbac/adf/reg/reg_main.c */ diff --git a/rsbac/adf/reg/reg_sample1.c b/rsbac/adf/reg/reg_sample1.c new file mode 100644 index 000000000000..e005603110d9 --- /dev/null +++ b/rsbac/adf/reg/reg_sample1.c @@ -0,0 +1,254 @@ +/* + * RSBAC REG decision module sample 1 + * + * Author and (c) 1999-2009 Amon Ott + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static u_long nr_request_calls = 0; +static u_long nr_set_attr_calls = 0; +static u_long nr_need_overwrite_calls = 0; +static u_long nr_system_calls = 0; +static void * system_call_arg = NULL; + +MODULE_AUTHOR("Amon Ott"); +MODULE_DESCRIPTION("RSBAC REG sample decision module 1"); +MODULE_LICENSE("GPL"); + +static char * name = NULL; +static char * syscall_name = NULL; +static long handle = 123456; +static long syscall_registration_handle = 654321; +static long syscall_dispatcher_handle = 1; + +module_param(name, charp, 0000); +MODULE_PARM_DESC(name, "Name"); +module_param(syscall_name, charp, 0000); +MODULE_PARM_DESC(syscall_name, "Syscall name"); +module_param(handle, long, S_IRUSR); +MODULE_PARM_DESC(handle, "Handle"); +module_param(syscall_registration_handle, long, S_IRUSR); +MODULE_PARM_DESC(syscall_registration_handle, "Syscall registration handle"); +module_param(syscall_dispatcher_handle, long, S_IRUSR); +MODULE_PARM_DESC(syscall_dispatcher_handle, "Syscall dispatcher"); + + +/* PROC functions */ + +#if defined(CONFIG_RSBAC_PROC) +#define PROC_NAME "reg_sample1" + +static struct proc_dir_entry * reg_sample_proc_p; + +static int +reg_sample_proc_show(struct seq_file *m, void *v) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) + return -ENOSYS; + + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + seq_puts(m, "RSBAC REG decision module sample 1\n----------------------------------\n"); + seq_printf(m, "%lu calls to request function.\n", + nr_request_calls); + seq_printf(m, "%lu calls to set_attr function.\n", + nr_set_attr_calls); + seq_printf(m, "%lu calls to need_overwrite function.\n", + nr_need_overwrite_calls); + seq_printf(m, "%lu calls to system_call function %lu, last arg was %p.\n", + nr_system_calls, + syscall_dispatcher_handle, + system_call_arg); + return 0; +} + +static int reg_sample_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, reg_sample_proc_show, NULL); +} + +static const struct file_operations reg_sample_proc_fops = { + .owner = THIS_MODULE, + .open = reg_sample_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#endif /* CONFIG_RSBAC_PROC */ + +/**** Decision Functions ****/ + +static int request_func ( enum rsbac_adf_request_t request, + rsbac_pid_t owner_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + /* count call, but not for SEARCH request */ + if(request != R_SEARCH) + nr_request_calls++; + return GRANTED; + } + +static int set_attr_func ( enum rsbac_adf_request_t request, + rsbac_pid_t owner_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + /* count call, but not for SEARCH request */ + if(request != R_SEARCH) + nr_set_attr_calls++; + return 0; + } + +static rsbac_boolean_t need_overwrite_func (struct dentry * dentry_p) + { + nr_need_overwrite_calls++; + return FALSE; + } + +static int syscall_func (void * arg) + { + nr_system_calls++; + system_call_arg = arg; + return nr_system_calls; + } + +/**** Init ****/ + +int init_module(void) +{ + struct rsbac_reg_entry_t entry; + struct rsbac_reg_syscall_entry_t syscall_entry; + + if(!handle) + handle = 123456; + if(!syscall_registration_handle) + syscall_registration_handle = 654321; + if(!syscall_dispatcher_handle) + syscall_dispatcher_handle = 1; + + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 1: Initializing.\n"); + + /* clearing registration entries */ + memset(&entry, 0, sizeof(entry)); + memset(&syscall_entry, 0, sizeof(syscall_entry)); + + if(name) + { + strncpy(entry.name, name, RSBAC_REG_NAME_LEN); + entry.name[RSBAC_REG_NAME_LEN] = 0; + } + else + strcpy(entry.name, "RSBAC REG sample 1 ADF module"); + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 1: REG Version: %u, Name: %s, Handle: %li\n", + RSBAC_REG_VERSION, entry.name, handle); + + entry.handle = handle; + entry.request_func = request_func; + entry.set_attr_func = set_attr_func; + entry.need_overwrite_func = need_overwrite_func; + entry.switch_on = TRUE; + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 1: Registering to ADF.\n"); + if(rsbac_reg_register(RSBAC_REG_VERSION, entry) < 0) + { + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 1: Registering failed. Unloading.\n"); + return -ENOEXEC; + } + + if(syscall_name) + { + strncpy(syscall_entry.name, syscall_name, RSBAC_REG_NAME_LEN); + syscall_entry.name[RSBAC_REG_NAME_LEN] = 0; + } + else + strcpy(syscall_entry.name, "RSBAC REG sample 1 syscall"); + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 1: REG Version: %u, Name: %s, Dispatcher Handle: %li\n", + RSBAC_REG_VERSION, syscall_entry.name, syscall_dispatcher_handle); + + syscall_entry.registration_handle = syscall_registration_handle; + syscall_entry.dispatcher_handle = syscall_dispatcher_handle; + syscall_entry.syscall_func = syscall_func; + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 1: Registering syscall.\n"); + syscall_registration_handle = rsbac_reg_register_syscall(RSBAC_REG_VERSION, syscall_entry); + if(syscall_registration_handle < 0) + { + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 1: Registering syscall failed. Unloading.\n"); + if(rsbac_reg_unregister(handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 1: Unregistering failed - beware of possible system failure!\n"); + } + return -ENOEXEC; + } + + #if defined(CONFIG_RSBAC_PROC) + reg_sample_proc_p = proc_create(PROC_NAME, S_IFREG | S_IRUGO, proc_rsbac_root_p, ®_sample_proc_fops); + if(!reg_sample_proc_p) + { + rsbac_printk(KERN_WARNING "%s: Not loaded due to failed proc entry registering.\n", name); + if(rsbac_reg_unregister(handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 1: Unregistering failed - beware of possible system failure!\n"); + } + if(rsbac_reg_unregister_syscall(syscall_registration_handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 1: Unregistering syscall failed - beware of possible system failure!\n"); + } + return -ENOEXEC; + } + #endif + + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 1: Loaded.\n"); + + return 0; +} + +void cleanup_module(void) +{ + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 1: Unregistering.\n"); + #if defined(CONFIG_RSBAC_PROC) + remove_proc_entry(PROC_NAME, proc_rsbac_root_p); + #endif + if(rsbac_reg_unregister_syscall(syscall_registration_handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 1: Unregistering syscall failed - beware of possible system failure!\n"); + } + if(rsbac_reg_unregister(handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 1: Unregistering failed - beware of possible system failure!\n"); + } + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 1: Unloaded.\n"); +} diff --git a/rsbac/adf/reg/reg_sample2.c b/rsbac/adf/reg/reg_sample2.c new file mode 100644 index 000000000000..c350e70549d1 --- /dev/null +++ b/rsbac/adf/reg/reg_sample2.c @@ -0,0 +1,548 @@ +/* + * RSBAC REG decision module sample2 + * (not working any more, kept for reference) + * + * Author and (c) 1999-2015 Amon Ott + */ + +/* general stuff */ +#include +#include +#include +#include +/* for file access */ +#include +#include +/* rsbac */ +#include +#include +#include +#include +#include +#include +#include +#include + +static u_long nr_request_calls = 0; +static u_long nr_set_attr_calls = 0; +static u_long nr_need_overwrite_calls = 0; +static rsbac_boolean_t no_write = FALSE; +static u_long nr_system_calls = 0; +static void * system_call_arg = 0; + +MODULE_AUTHOR("Amon Ott"); +MODULE_DESCRIPTION("RSBAC REG sample decision module 2"); + +MODULE_PARM(name, "s"); +static char * name = NULL; +static char dummy_buf[70]="To protect against wrong insmod params"; + +MODULE_PARM(syscall_name, "s"); +static char * syscall_name = NULL; +static char dummy_buf2[70]="To protect against wrong insmod params"; + +MODULE_PARM(handle, "l"); +static long handle = 123457; + +MODULE_PARM(syscall_registration_handle, "l"); +static long syscall_registration_handle = 754321; +MODULE_PARM(syscall_dispatcher_handle, "l"); +static long syscall_dispatcher_handle = 2; + +/* Filename for persistent data in /rsbac dir of ROOT_DEV (max 7 chars) */ +#define FILENAME "regsmp2" + +/* Version number for on disk data structures */ +#define FILE_VERSION 1 + +/* PROC functions */ + +#if defined(CONFIG_RSBAC_PROC) +#define PROC_NAME "reg_sample2" +static struct proc_dir_entry * proc_reg_sample_p; + +static int +adf_sample_proc_info(char *buffer, char **start, off_t offset, int length) +{ + int len = 0; + off_t pos = 0; + off_t begin = 0; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) + return (-ENOSYS); + + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + len += sprintf(buffer, "RSBAC REG decision module sample 2\n----------------------------------\n"); + pos = begin + len; + if (pos < offset) + { + len = 0; + begin = pos; + } + if (pos > offset+length) + goto out; + + len += sprintf(buffer + len, "%lu calls to request function.\n", + nr_request_calls); + pos = begin + len; + if (pos < offset) + { + len = 0; + begin = pos; + } + if (pos > offset+length) + goto out; + + len += sprintf(buffer + len, "%lu calls to set_attr function.\n", + nr_set_attr_calls); + pos = begin + len; + if (pos < offset) + { + len = 0; + begin = pos; + } + if (pos > offset+length) + goto out; + + len += sprintf(buffer + len, "%lu calls to need_overwrite function.\n", + nr_need_overwrite_calls); + pos = begin + len; + if (pos < offset) + { + len = 0; + begin = pos; + } + if (pos > offset+length) + goto out; + + len += sprintf(buffer + len, "%lu calls to system_call function %lu, last arg was %p.\n", + nr_system_calls, + syscall_dispatcher_handle, + system_call_arg); + pos = begin + len; + if (pos < offset) + { + len = 0; + begin = pos; + } + if (pos > offset+length) + goto out; + +out: + *start = buffer + (offset - begin); + len -= (offset - begin); + + if (len > length) + len = length; + return len; +} +#endif /* CONFIG_RSBAC_PROC */ + + +/**** Read/Write Functions ****/ + +/* read_info() */ +/* reading the system wide adf_sample2 data */ + +static int read_info(void) + { + struct file file; + char name[RSBAC_MAXNAMELEN]; + int err = 0; + int tmperr; + mm_segment_t oldfs; + u_int version; + u_long tmpval; + + /* copy name from base name */ + strcpy(name, FILENAME); + + /* open file */ + if ((err = rsbac_read_open(name, + &file, + rsbac_root_dev) )) + return(err); + + /* OK, now we can start reading */ + + /* There is a read function for this file, so read data from + * previous module load. + * A positive read return value means a read success, + * 0 end of file and a negative value an error. + */ + + /* Set current user space to kernel space, because read() writes */ + /* to user space */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + + tmperr = __vfs_read(&file, + (char *) &version, + sizeof(version), + &file.f_pos); + /* error? */ + if (tmperr < sizeof(version)) + { + rsbac_printk(KERN_WARNING + "read_info(): read error from file!\n"); + err = -RSBAC_EREADFAILED; + goto end_read; + } + /* if wrong version, warn and skip */ + if (version != FILE_VERSION) + { + rsbac_printk(KERN_WARNING + "read_info(): wrong version %u, expected %u - skipping file and setting no_write!\n", + version, FILE_VERSION); + no_write = TRUE; + err = -RSBAC_EREADFAILED; + goto end_read; + } + + /* read nr_request_calls */ + tmperr = __vfs_read(&file, + (char *) &tmpval, + sizeof(tmpval), + &file.f_pos); + if (tmperr < sizeof(tmpval)) + { + rsbac_printk(KERN_WARNING "%s\n", + "read_info(): read error from file!"); + err = -RSBAC_EREADFAILED; + goto end_read; + } + nr_request_calls = tmpval; + + /* read nr_set_attr_calls */ + tmperr = __vfs_read(&file, + (char *) &tmpval, + sizeof(tmpval), + &file.f_pos); + if (tmperr < sizeof(tmpval)) + { + rsbac_printk(KERN_WARNING "%s\n", + "read_info(): read error from file!"); + err = -RSBAC_EREADFAILED; + goto end_read; + } + nr_set_attr_calls = tmpval; + + /* read nr_need_overwrite_calls */ + tmperr = __vfs_read(&file, + (char *) &tmpval, + sizeof(tmpval), + &file.f_pos); + if (tmperr < sizeof(tmpval)) + { + rsbac_printk(KERN_WARNING "%s\n", + "read_info(): read error from file!"); + err = -RSBAC_EREADFAILED; + goto end_read; + } + nr_need_overwrite_calls = tmpval; + +end_read: + /* Set current user space back to user space, because read() writes */ + /* to user space */ + set_fs(oldfs); + + /* We do not need this file dentry any more */ + rsbac_read_close(&file); + + /* ready */ + return(err); + }; /* end of read_info() */ + +static int write_info(void) + { + struct file file; + char name[RSBAC_MAXNAMELEN]; + int err = 0; + int tmperr; + mm_segment_t oldfs; + u_int version = FILE_VERSION; + + /* copy name from base name */ + strcpy(name, FILENAME); + + /* get rsbac write-to-disk semaphore */ + down(&rsbac_write_sem); + + /* open file */ + if ((err = rsbac_write_open(name, + &file, + rsbac_root_dev) )) + { + up(&rsbac_write_sem); + return(err); + } + + /* OK, now we can start writing all sample items. + * A positive return value means a write success, + * 0 end of file and a negative value an error. + */ + + /* Set current user space to kernel space, because write() reads + * from user space */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + + tmperr = __vfs_write(&file, + (char *) &version, + sizeof(version), + &file.f_pos); + if (tmperr < sizeof(version)) + { + rsbac_printk(KERN_WARNING + "write_info(): write error %i on file!\n", + tmperr); + err = -RSBAC_EWRITEFAILED; + goto end_write; + } + + tmperr = __vfs_write(&file, + (char *) &nr_request_calls, + sizeof(nr_request_calls), + &file.f_pos); + if (tmperr < sizeof(nr_request_calls)) + { + rsbac_printk(KERN_WARNING + "write_info(): write error %i on file!\n", + tmperr); + err = -RSBAC_EWRITEFAILED; + goto end_write; + } + + tmperr = __vfs_write(&file, + (char *) &nr_set_attr_calls, + sizeof(nr_set_attr_calls), + &file.f_pos); + if (tmperr < sizeof(nr_set_attr_calls)) + { + rsbac_printk(KERN_WARNING + "write_info(): write error %i on file!\n", + tmperr); + err = -RSBAC_EWRITEFAILED; + goto end_write; + } + + tmperr = __vfs_write(&file, + (char *) &nr_need_overwrite_calls, + sizeof(nr_need_overwrite_calls), + &file.f_pos); + if (tmperr < sizeof(nr_need_overwrite_calls)) + { + rsbac_printk(KERN_WARNING + "write_info(): write error %i on file!\n", + tmperr); + err = -RSBAC_EWRITEFAILED; + goto end_write; + } + +end_write: + /* Set current user space back to user space, because write() reads */ + /* from user space */ + set_fs(oldfs); + + /* End of write access */ + rsbac_write_close(&file); + up(&rsbac_write_sem); + return(err); + }; /* end of write_info() */ + + +/**** Decision Functions ****/ + +static int request_func ( enum rsbac_adf_request_t request, + rsbac_pid_t owner_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + /* count call, but not for SEARCH request */ + if(request != R_SEARCH) + nr_request_calls++; + return GRANTED; + } + +static int set_attr_func ( enum rsbac_adf_request_t request, + rsbac_pid_t owner_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + /* count call, but not for SEARCH request */ + if(request != R_SEARCH) + nr_set_attr_calls++; + return 0; + } + +static rsbac_boolean_t need_overwrite_func (struct dentry * dentry_p) + { + nr_need_overwrite_calls++; + return FALSE; + } + +static int write_func(rsbac_boolean_t need_lock) + { + int res=0; + + if(!write_info()) + res = 1; + + return(res); + } + +static int syscall_func (void * arg) + { + nr_system_calls++; + system_call_arg = arg; + return nr_system_calls; + } + +/**** Init ****/ + +int init_module(void) +{ + struct rsbac_reg_entry_t entry; + struct rsbac_reg_syscall_entry_t syscall_entry; + + if(!handle) + handle = 123457; + if(!syscall_registration_handle) + syscall_registration_handle = 754321; + if(!syscall_dispatcher_handle) + syscall_dispatcher_handle = 2; + + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 2: Initializing.\n"); + + /* clearing registration entries */ + memset(&entry, 0, sizeof(entry)); + memset(&syscall_entry, 0, sizeof(syscall_entry)); + + if((dummy_buf[0] != 'T') || (dummy_buf2[0] != 'T')) + { + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 2: Not loaded due to invalid param string.\n"); + return -ENOEXEC; + } + if(name) + { + strncpy(entry.name, name, RSBAC_REG_NAME_LEN); + entry.name[RSBAC_REG_NAME_LEN] = 0; + } + else + strcpy(entry.name, "RSBAC REG sample 2 ADF module"); + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 2: REG Version: %u, Name: %s, Handle: %li\n", + RSBAC_REG_VERSION, entry.name, handle); + + entry.handle = handle; + entry.request_func = request_func; + entry.set_attr_func = set_attr_func; + entry.need_overwrite_func = need_overwrite_func; + entry.write_func = write_func; + entry.switch_on = TRUE; + + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 2: Registering to ADF.\n"); + if(rsbac_reg_register(RSBAC_REG_VERSION, entry) < 0) + { + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 2: Registering failed. Unloading.\n"); + return -ENOEXEC; + } + + if(syscall_name) + { + strncpy(syscall_entry.name, syscall_name, RSBAC_REG_NAME_LEN); + syscall_entry.name[RSBAC_REG_NAME_LEN] = 0; + } + else + strcpy(syscall_entry.name, "RSBAC REG sample 2 syscall"); + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 2: REG Version: %u, Name: %s, Dispatcher Handle: %li\n", + RSBAC_REG_VERSION, syscall_entry.name, syscall_dispatcher_handle); + + syscall_entry.registration_handle = syscall_registration_handle; + syscall_entry.dispatcher_handle = syscall_dispatcher_handle; + syscall_entry.syscall_func = syscall_func; + + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 2: Registering syscall.\n"); + syscall_registration_handle = rsbac_reg_register_syscall(RSBAC_REG_VERSION, syscall_entry); + if(syscall_registration_handle < 0) + { + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 2: Registering syscall failed. Unloading.\n"); + if(rsbac_reg_unregister(handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 2: Unregistering failed - beware of possible system failure!\n"); + } + return -ENOEXEC; + } + + if(read_info()) + { + rsbac_printk(KERN_WARNING + "RSBAC REG decision module sample 2: Could not read info from previous session.\n"); + } + + #if defined(CONFIG_RSBAC_PROC) + proc_reg_sample_p = create_proc_entry(PROC_NAME, + S_IFREG | S_IRUGO, + proc_rsbac_root_p); + if(!proc_reg_sample_p) + { + rsbac_printk(KERN_WARNING "%s: Not loaded due to failed proc entry registering.\n", name); + if(rsbac_reg_unregister_syscall(syscall_registration_handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 2: Unregistering syscall failed - beware of possible system failure!\n"); + } + if(rsbac_reg_unregister(handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 2: Unregistering from ADF failed - beware of possible system failure!\n"); + } + return -ENOEXEC; + } + proc_reg_sample_p->get_info = adf_sample_proc_info; + #endif + + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 2: Loaded.\n"); + + return 0; +} + +void cleanup_module(void) +{ + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 2: Unregistering.\n"); + #if defined(CONFIG_RSBAC_PROC) + remove_proc_entry(PROC_NAME, proc_rsbac_root_p); + #endif + if(write_info()) + { + rsbac_printk(KERN_WARNING + "RSBAC REG decision module sample 2: Could not save info for next session.\n"); + } + if(rsbac_reg_unregister_syscall(syscall_registration_handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 2: Unregistering syscall failed - beware of possible system failure!\n"); + } + if(rsbac_reg_unregister(handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 2: Unregistering module failed - beware of possible system failure!\n"); + } + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 2: Unloaded.\n"); +} diff --git a/rsbac/adf/reg/reg_sample3.c b/rsbac/adf/reg/reg_sample3.c new file mode 100644 index 000000000000..2fef23d4f0bc --- /dev/null +++ b/rsbac/adf/reg/reg_sample3.c @@ -0,0 +1,369 @@ +/* + * RSBAC REG decision module sample + * + * Author and (c) 1999-2009 Amon Ott + */ + +/* general stuff */ +#include +#include +#include +#include +/* for file access */ +#include +#include +#include +/* rsbac */ +#include +#include +#include +#include +#include +#include +#include +#include + +static u_long nr_request_calls = 0; +#define ORD_request 1 +static u_long nr_set_attr_calls = 0; +#define ORD_set_attr 2 +static u_long nr_need_overwrite_calls = 0; +#define ORD_overwrite 3 +static u_long nr_write_calls = 0; +#define ORD_write 4 +static u_long nr_system_calls = 0; +#define ORD_syscall 5 +static void * system_call_arg = 0; + +MODULE_AUTHOR("Amon Ott"); +MODULE_DESCRIPTION("RSBAC REG sample decision module 3"); +MODULE_LICENSE("GPL"); + +static char * name = NULL; +static char * syscall_name = NULL; +static u_int listkey = 133457; +static long handle = 133457; +static long syscall_registration_handle = 754331; +static long syscall_dispatcher_handle = 3; + +module_param(name, charp, 0000); +MODULE_PARM_DESC(name, "Name"); +module_param(syscall_name, charp, 0000); +MODULE_PARM_DESC(syscall_name, "Syscall name"); +module_param(listkey, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(listkey, "List key"); +module_param(handle, long, S_IRUSR); +MODULE_PARM_DESC(handle, "Handle"); +module_param(syscall_registration_handle, long, S_IRUSR); +MODULE_PARM_DESC(syscall_registration_handle, "Syscall registration handle"); +module_param(syscall_dispatcher_handle, long, S_IRUSR); +MODULE_PARM_DESC(syscall_dispatcher_handle, "Syscall dispatcher handle"); + +/* Filename for persistent data in /rsbac dir of ROOT_DEV (max 7 chars) */ +#define FILENAME "regsmp3" + +/* Version number for on disk data structures */ +#define LIST_VERSION 1 + +static rsbac_list_handle_t list_handle; + +/* PROC functions */ + +#if defined(CONFIG_RSBAC_PROC) +#define PROC_NAME "reg_sample3" +static struct proc_dir_entry * reg_sample_proc_p; + +static int +reg_sample_proc_show(struct seq_file *m, void *v) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) + return -ENOSYS; + + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + seq_puts(m, "RSBAC REG decision module sample 3\n----------------------------------\n"); + seq_printf(m, "%lu calls to request function.\n", + nr_request_calls); + seq_printf(m, "%lu calls to set_attr function.\n", + nr_set_attr_calls); + seq_printf(m, "%lu calls to need_overwrite function.\n", + nr_need_overwrite_calls); + seq_printf(m, "%lu calls to write function.\n", + nr_write_calls); + seq_printf(m, "%lu calls to system_call function %lu, last arg was %p.\n", + nr_system_calls, + syscall_dispatcher_handle, + system_call_arg); + seq_printf(m, "%li list items.\n", + rsbac_list_count(list_handle)); + return 0; +} + +static int reg_sample_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, reg_sample_proc_show, NULL); +} + +static const struct file_operations reg_sample_proc_fops = { + .owner = THIS_MODULE, + .open = reg_sample_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#endif /* CONFIG_RSBAC_PROC */ + +/**** List helper functions ****/ + +static int compare(void * desc1, void * desc2) + { + return memcmp((u_int *) desc1, (u_int *) desc2, sizeof(u_int) ); + } + +/* +static rsbac_list_conv_function_t * get_conv(rsbac_version_t version) + { + return compare; + } +*/ + +/**** Decision Functions ****/ + +static int request_func ( enum rsbac_adf_request_t request, + rsbac_pid_t owner_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + /* count call, but not for SEARCH request */ + if(request != R_SEARCH) + { + __u32 ord = ORD_request; + + nr_request_calls++; + rsbac_list_add(list_handle, &ord, &nr_request_calls); + } + return GRANTED; + } + +static int set_attr_func ( enum rsbac_adf_request_t request, + rsbac_pid_t owner_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + __u32 ord = ORD_set_attr; + + /* count call, but not for SEARCH request */ + if(request != R_SEARCH) + { + nr_set_attr_calls++; + rsbac_list_add(list_handle, &ord, &nr_set_attr_calls); + } + return 0; + } + +static rsbac_boolean_t need_overwrite_func (struct dentry * dentry_p) + { + __u32 ord = ORD_overwrite; + + nr_need_overwrite_calls++; + rsbac_list_add(list_handle, &ord, &nr_need_overwrite_calls); + return FALSE; + } + +static int write_func(rsbac_boolean_t need_lock) + { + __u32 ord = ORD_write; + + nr_write_calls++; + rsbac_list_add(list_handle, &ord, &nr_write_calls); + return(0); + } + +static int syscall_func (void * arg) + { + __u32 ord = ORD_syscall; + + nr_system_calls++; + system_call_arg = arg; + rsbac_list_add(list_handle, &ord, &nr_system_calls); + return nr_system_calls; + } + +/**** Init ****/ + +int init_module(void) +{ + struct rsbac_reg_entry_t entry; + struct rsbac_reg_syscall_entry_t syscall_entry; + struct rsbac_list_info_t list_info; + __u32 ord; + + if(!listkey) + listkey = 133457; + if(!handle) + handle = 133457; + if(!syscall_registration_handle) + syscall_registration_handle = 754331; + if(!syscall_dispatcher_handle) + syscall_dispatcher_handle = 3; + + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 3: Initializing.\n"); + + /* clearing registration entries */ + memset(&entry, 0, sizeof(entry)); + memset(&syscall_entry, 0, sizeof(syscall_entry)); + /* Register a generic list */ + list_info.version = LIST_VERSION; + list_info.key = listkey; + list_info.desc_size = sizeof(__u32); + list_info.data_size = sizeof(nr_request_calls); + list_info.max_age = 3600; /* 1h */ + if(rsbac_list_register(RSBAC_LIST_VERSION, + &list_handle, + &list_info, + RSBAC_LIST_PERSIST | RSBAC_LIST_BACKUP, + compare, + NULL, + NULL, + FILENAME, + 0)) + { + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 3: Registering list failed. Unloading.\n"); + return -ENOEXEC; + } + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 3: List Version: %u, Name: %s, Handle: %p, Key: %u\n", + RSBAC_LIST_VERSION, FILENAME, list_handle, listkey); + ord = ORD_request; + if(rsbac_list_exist(list_handle, &ord)) + rsbac_list_get_data(list_handle, &ord, &nr_request_calls); + ord = ORD_set_attr; + if(rsbac_list_exist(list_handle, &ord)) + rsbac_list_get_data(list_handle, &ord, &nr_set_attr_calls); + ord = ORD_overwrite; + if(rsbac_list_exist(list_handle, &ord)) + rsbac_list_get_data(list_handle, &ord, &nr_need_overwrite_calls); + ord = ORD_write; + if(rsbac_list_exist(list_handle, &ord)) + rsbac_list_get_data(list_handle, &ord, &nr_write_calls); + ord = ORD_syscall; + if(rsbac_list_exist(list_handle, &ord)) + rsbac_list_get_data(list_handle, &ord, &nr_system_calls); + + /* Register to ADF */ + if(name) + { + strncpy(entry.name, name, RSBAC_REG_NAME_LEN); + entry.name[RSBAC_REG_NAME_LEN] = 0; + } + else + strcpy(entry.name, "RSBAC REG sample 3 ADF module"); + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 3: REG Version: %u, Name: %s, Handle: %li\n", + RSBAC_REG_VERSION, entry.name, handle); + + entry.handle = handle; + entry.request_func = request_func; + entry.set_attr_func = set_attr_func; + entry.need_overwrite_func = need_overwrite_func; + entry.write_func = write_func; + entry.switch_on = TRUE; + + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 3: Registering to ADF.\n"); + if(rsbac_reg_register(RSBAC_REG_VERSION, entry) < 0) + { + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 3: Registering failed. Unloading.\n"); + if(rsbac_list_detach(&list_handle, listkey)) + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 3: Unregistering list failed - beware!\n"); + return -ENOEXEC; + } + + if(syscall_name) + { + strncpy(syscall_entry.name, syscall_name, RSBAC_REG_NAME_LEN); + syscall_entry.name[RSBAC_REG_NAME_LEN] = 0; + } + else + strcpy(syscall_entry.name, "RSBAC REG sample 3 syscall"); + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 3: REG Version: %u, Name: %s, Dispatcher Handle: %li\n", + RSBAC_REG_VERSION, syscall_entry.name, syscall_dispatcher_handle); + + syscall_entry.registration_handle = syscall_registration_handle; + syscall_entry.dispatcher_handle = syscall_dispatcher_handle; + syscall_entry.syscall_func = syscall_func; + + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 3: Registering syscall.\n"); + syscall_registration_handle = rsbac_reg_register_syscall(RSBAC_REG_VERSION, syscall_entry); + if(syscall_registration_handle < 0) + { + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 3: Registering syscall failed. Unloading.\n"); + if(rsbac_reg_unregister(handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 3: Unregistering failed - beware of possible system failure!\n"); + } + if(rsbac_list_detach(&list_handle, listkey)) + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 3: Unregistering list failed - beware!\n"); + return -ENOEXEC; + } + + #if defined(CONFIG_RSBAC_PROC) + reg_sample_proc_p = proc_create(PROC_NAME, S_IFREG | S_IRUGO, proc_rsbac_root_p, ®_sample_proc_fops); + if(!reg_sample_proc_p) + { + rsbac_printk(KERN_WARNING "%s: Not loaded due to failed proc entry registering.\n", name); + if(rsbac_reg_unregister_syscall(syscall_registration_handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 3: Unregistering syscall failed - beware of possible system failure!\n"); + } + if(rsbac_reg_unregister(handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 3: Unregistering from ADF failed - beware of possible system failure!\n"); + } + if(rsbac_list_detach(&list_handle, listkey)) + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 3: Unregistering list failed - beware!\n"); + return -ENOEXEC; + } + #endif + + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 3: Loaded.\n"); + + return 0; +} + +void cleanup_module(void) +{ + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 3: Unregistering.\n"); + #if defined(CONFIG_RSBAC_PROC) + remove_proc_entry(PROC_NAME, proc_rsbac_root_p); + #endif + if(rsbac_reg_unregister_syscall(syscall_registration_handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 3: Unregistering syscall failed - beware of possible system failure!\n"); + } + if(rsbac_reg_unregister(handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module sample 3: Unregistering module failed - beware of possible system failure!\n"); + } + if(rsbac_list_detach(&list_handle, listkey)) + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 3: Unregistering list failed - beware!\n"); + rsbac_printk(KERN_INFO "RSBAC REG decision module sample 3: Unloaded.\n"); +} diff --git a/rsbac/adf/reg/root_plug.c b/rsbac/adf/reg/root_plug.c new file mode 100644 index 000000000000..4679d5f55774 --- /dev/null +++ b/rsbac/adf/reg/root_plug.c @@ -0,0 +1,138 @@ +/* + * RSBAC REG decision module kproc_hide. + * + * Originally written for a Linux Journal as LSM sample module. + * Rewriten for RSBAC by Michal Purzynski + * + * Copyright (C) 2002 Greg Kroah-Hartman + * + * Prevents any programs running with egid == 0 if a specific USB device + * is not present in the system. Yes, it can be gotten around, but is a + * nice starting point for people to play with, and learn the LSM interface. + * + * See http://www.linuxjournal.com/article.php?sid=6279 for more information about this code. + * + * This program 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, version 2 of the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Michal Purzynski"); +MODULE_DESCRIPTION("RSBAC REG root_plug decision module"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_USB +/* default is a generic type of usb to serial converter */ +static int vendor_id = 0x0557; +static int product_id = 0x2008; + +module_param(vendor_id, uint, 0400); +module_param(product_id, uint, 0400); +#endif + +static long handle = 999999; + +/**** Decision Functions ****/ + +static int request_func (enum rsbac_adf_request_t request, + rsbac_pid_t owner_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + struct usb_device *dev = NULL; +#ifdef CONFIG_USB + dev = usb_find_device(vendor_id, product_id); +#endif + + if (!dev) { + + switch (request) { + case R_CHANGE_OWNER: + case R_CHANGE_GROUP: + case R_CLONE: + switch (target) { + case T_PROCESS: + switch (attr) { + case A_owner: + switch (attr_val.owner) { + case 0: + return NOT_GRANTED; + default: + return DO_NOT_CARE; + } + default: + return DO_NOT_CARE; + } + default: + return DO_NOT_CARE; + } + default: + return DO_NOT_CARE; + } + } + + return DO_NOT_CARE; +} + +/**** Init ****/ + +int init_module(void) +{ + struct rsbac_reg_entry_t entry; + + rsbac_printk(KERN_INFO "RSBAC REG decision module root_plug: Initializing.\n"); + + /* clearing registration entries */ + memset(&entry, 0, sizeof(entry)); + + strcpy(entry.name, "RSBAC REG root_plug ADF module"); + rsbac_printk(KERN_INFO "RSBAC REG decision module root_plug: REG Version: %u, Name: %s, Handle: %li\n", + RSBAC_REG_VERSION, entry.name, handle); + + entry.handle = handle; + entry.request_func = request_func; + entry.switch_on = TRUE; + + rsbac_printk(KERN_INFO "RSBAC REG decision module root_plug: Registering to ADF.\n"); + + if(rsbac_reg_register(RSBAC_REG_VERSION, entry) < 0) { + rsbac_printk(KERN_WARNING "RSBAC REG decision module sample 1: Registering failed. Unloading.\n"); + return -ENOEXEC; + } + + rsbac_printk(KERN_INFO "RSBAC REG decision module root_plug: Loaded.\n"); + + return 0; +} + +void cleanup_module(void) +{ + rsbac_printk(KERN_INFO "RSBAC REG decision module root_plug: Unregistering.\n"); + + if(rsbac_reg_unregister(handle)) + { + rsbac_printk(KERN_ERR "RSBAC REG decision module root_plug: Unregistering failed - beware of possible system failure!\n"); + } + + rsbac_printk(KERN_INFO "RSBAC REG decision module root_plug: Unloaded.\n"); +} + diff --git a/rsbac/adf/res/Makefile b/rsbac/adf/res/Makefile new file mode 100644 index 000000000000..bcf8e21ebebf --- /dev/null +++ b/rsbac/adf/res/Makefile @@ -0,0 +1,10 @@ +# +# File: rsbac/adf/res/Makefile +# +# Makefile for the Linux rsbac RES decision module. +# +# Author and (c) 1999-2012 Amon Ott +# + +# 2.6.x +obj-y := res_main.o diff --git a/rsbac/adf/res/res_main.c b/rsbac/adf/res/res_main.c new file mode 100644 index 000000000000..09c1325102ed --- /dev/null +++ b/rsbac/adf/res/res_main.c @@ -0,0 +1,435 @@ +/**************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - System Resources (RES) */ +/* File: rsbac/adf/res/main.c */ +/* */ +/* Author and (c) 2002-2016: Amon Ott */ +/* */ +/* Last modified: 01/Aug/2016 */ +/**************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +enum rsbac_adf_req_ret_t + rsbac_adf_request_res (enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + switch (request) + { + case R_MODIFY_ATTRIBUTE: + switch(attr) + { + case A_system_role: + case A_res_role: + case A_res_min: + case A_res_max: + /* All attributes (remove target!) */ + case A_none: + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_RES, + T_USER, + i_tid, + A_res_role, + &i_attr_val1, + TRUE)) + { + rsbac_ds_get_error("rsbac_adf_request_res()", A_res_role); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + default: + return(DO_NOT_CARE); + } + + case R_READ_ATTRIBUTE: + switch(attr) + { + case A_system_role: + case A_res_role: + case A_res_min: + case A_res_max: + /* All attributes (remove target!) */ + case A_none: + /* Security Officer or Admin? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_RES, + T_USER, + i_tid, + A_res_role, + &i_attr_val1, + TRUE)) + { + rsbac_ds_get_error("rsbac_adf_request_res()", A_res_role); + return(NOT_GRANTED); + } + /* if sec_officer, then grant */ + if( (i_attr_val1.system_role == SR_security_officer) + || (i_attr_val1.system_role == SR_administrator) + ) + return(GRANTED); + else + return(NOT_GRANTED); + + default: + return(DO_NOT_CARE); + } + + case R_SWITCH_LOG: + switch(target) + { + case T_NONE: + /* test owner's res_role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_RES, + T_USER, + i_tid, + A_res_role, + &i_attr_val1, + TRUE)) + { + rsbac_ds_get_error("rsbac_adf_request_res()", A_res_role); + return(NOT_GRANTED); + } + /* security officer? -> grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + /* all other cases are unknown */ + default: return(DO_NOT_CARE); + } + + case R_SWITCH_MODULE: + switch(target) + { + case T_NONE: + /* we need the switch_target */ + if(attr != A_switch_target) + return NOT_GRANTED; + /* do not care for other modules */ + if( (attr_val.switch_target != SW_RES) + #ifdef CONFIG_RSBAC_SOFTMODE + && (attr_val.switch_target != SW_SOFTMODE) + #endif + #ifdef CONFIG_RSBAC_FREEZE + && (attr_val.switch_target != SW_FREEZE) + #endif + #ifdef CONFIG_RSBAC_MPROTECT + && (attr_val.switch_target != SW_MPROTECT) + #endif + ) + return(DO_NOT_CARE); + /* test owner's res_role */ + i_tid.user = owner; + if (rsbac_get_attr(SW_RES, + T_USER, + i_tid, + A_res_role, + &i_attr_val1, + TRUE)) + { + rsbac_ds_get_error("rsbac_adf_request_res()", A_res_role); + return(NOT_GRANTED); + } + /* security officer? -> grant */ + if (i_attr_val1.system_role == SR_security_officer) + return(GRANTED); + else + return(NOT_GRANTED); + + /* all other cases are unknown */ + default: return(DO_NOT_CARE); + } + + +/*********************/ + default: return DO_NOT_CARE; + } + + return DO_NOT_CARE; + } /* end of rsbac_adf_request_res() */ + + +/*****************************************************************************/ +/* If the request returned granted and the operation is performed, */ +/* the following function can be called by the AEF to get all aci set */ +/* correctly. For write accesses that are performed fully within the kernel, */ +/* this is usually not done to prevent extra calls, including R_CLOSE for */ +/* cleaning up. */ +/* The second instance of target specification is the new target, if one has */ +/* been created, otherwise its values are ignored. */ +/* On success, 0 is returned, and an error from rsbac/error.h otherwise. */ + +int rsbac_adf_set_attr_res( + enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + switch (request) + { + case R_CHANGE_OWNER: + switch(target) + { + case T_PROCESS: + if(attr != A_owner) + return(-RSBAC_EINVALIDATTR); + /* Adjust Linux resources */ + i_tid.user = attr_val.owner; +#ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode +#ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RES] +#endif + ) +#endif + { + int maxval = rsbac_min(RLIM_NLIMITS - 1, RSBAC_RES_MAX); + int i; + + if (rsbac_get_attr(SW_RES, + T_USER, + i_tid, + A_res_max, + &i_attr_val1, + TRUE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_res()", A_res_max); + return -RSBAC_EREADFAILED; + } + for(i = 0; i <= maxval ; i++) + { + if(i_attr_val1.res_array[i]) + { + task_lock(current->group_leader); + if(current->signal->rlim[i].rlim_max > i_attr_val1.res_array[i]) + current->signal->rlim[i].rlim_max = i_attr_val1.res_array[i]; + if(current->signal->rlim[i].rlim_cur > i_attr_val1.res_array[i]) + current->signal->rlim[i].rlim_cur = i_attr_val1.res_array[i]; + task_unlock(current->group_leader); + } + } + if (rsbac_get_attr(SW_RES, + T_USER, + i_tid, + A_res_min, + &i_attr_val1, + TRUE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_res()", A_res_min); + return -RSBAC_EREADFAILED; + } + if(i_attr_val1.res_array[RLIMIT_NOFILE] > sysctl_nr_open) + i_attr_val1.res_array[RLIMIT_NOFILE] = sysctl_nr_open; + for(i = 0; i <= maxval ; i++) + { + if(i_attr_val1.res_array[i]) + { + task_lock(current->group_leader); + if(current->signal->rlim[i].rlim_max < i_attr_val1.res_array[i]) + current->signal->rlim[i].rlim_max = i_attr_val1.res_array[i]; + if(current->signal->rlim[i].rlim_cur < i_attr_val1.res_array[i]) + current->signal->rlim[i].rlim_cur = i_attr_val1.res_array[i]; + task_unlock(current->group_leader); + } + } + } + return 0; + + /* all other cases are unknown */ + default: + return(0); + } + break; + + case R_EXECUTE: + switch(target) + { + case T_FILE: +#ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode +#ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RES] +#endif + ) +#endif + { + int maxval = rsbac_min(RLIM_NLIMITS - 1, RSBAC_RES_MAX); + int i; + + if (rsbac_get_attr(SW_RES, + target, + tid, + A_res_max, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_res()", A_res_max); + return -RSBAC_EREADFAILED; + } + for(i = 0; i <= maxval ; i++) + { + if(i_attr_val1.res_array[i]) + { + task_lock(current->group_leader); + if(current->signal->rlim[i].rlim_max > i_attr_val1.res_array[i]) + current->signal->rlim[i].rlim_max = i_attr_val1.res_array[i]; + if(current->signal->rlim[i].rlim_cur > i_attr_val1.res_array[i]) + current->signal->rlim[i].rlim_cur = i_attr_val1.res_array[i]; + task_unlock(current->group_leader); + } + } + if (rsbac_get_attr(SW_RES, + target, + tid, + A_res_min, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_res()", A_res_min); + return -RSBAC_EREADFAILED; + } + for(i = 0; i <= maxval ; i++) + { + if(i_attr_val1.res_array[i]) + { + task_lock(current->group_leader); + if(current->signal->rlim[i].rlim_max < i_attr_val1.res_array[i]) + current->signal->rlim[i].rlim_max = i_attr_val1.res_array[i]; + if(current->signal->rlim[i].rlim_cur < i_attr_val1.res_array[i]) + current->signal->rlim[i].rlim_cur = i_attr_val1.res_array[i]; + task_unlock(current->group_leader); + } + } + } + return 0; + + /* all other cases are unknown */ + default: + return 0; + } + break; + + case R_MODIFY_SYSTEM_DATA: + if ( (target == T_SCD) + && (tid.scd == ST_rlimit) + ) + { + /* Adjust Linux resources */ + i_tid.user = owner; +#ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode +#ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_RES] +#endif + ) +#endif + { + int maxval = rsbac_min(RLIM_NLIMITS - 1, RSBAC_RES_MAX); + int i; + + if (rsbac_get_attr(SW_RES, + T_USER, + i_tid, + A_res_max, + &i_attr_val1, + TRUE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_res()", A_res_max); + return -RSBAC_EREADFAILED; + } + for(i = 0; i <= maxval ; i++) + { + if(i_attr_val1.res_array[i]) + { + task_lock(current->group_leader); + if(current->signal->rlim[i].rlim_max > i_attr_val1.res_array[i]) + current->signal->rlim[i].rlim_max = i_attr_val1.res_array[i]; + if(current->signal->rlim[i].rlim_cur > i_attr_val1.res_array[i]) + current->signal->rlim[i].rlim_cur = i_attr_val1.res_array[i]; + task_unlock(current->group_leader); + } + } + if (rsbac_get_attr(SW_RES, + T_USER, + i_tid, + A_res_min, + &i_attr_val1, + TRUE)) + { + rsbac_ds_get_error("rsbac_adf_set_attr_res()", A_res_min); + return -RSBAC_EREADFAILED; + } + if(i_attr_val1.res_array[RLIMIT_NOFILE] > sysctl_nr_open) + i_attr_val1.res_array[RLIMIT_NOFILE] = sysctl_nr_open; + for(i = 0; i <= maxval ; i++) + { + if(i_attr_val1.res_array[i]) + { + task_lock(current->group_leader); + if(current->signal->rlim[i].rlim_max < i_attr_val1.res_array[i]) + current->signal->rlim[i].rlim_max = i_attr_val1.res_array[i]; + if(current->signal->rlim[i].rlim_cur < i_attr_val1.res_array[i]) + current->signal->rlim[i].rlim_cur = i_attr_val1.res_array[i]; + task_unlock(current->group_leader); + } + } + } + return 0; + } + break; + +/*********************/ + default: return 0; + } + + return 0; + } /* end of rsbac_adf_set_attr_res() */ + +/* end of rsbac/adf/res/main.c */ diff --git a/rsbac/adf/udf/Makefile b/rsbac/adf/udf/Makefile new file mode 100644 index 000000000000..ee7b3f7cc8ae --- /dev/null +++ b/rsbac/adf/udf/Makefile @@ -0,0 +1,10 @@ +# +# File: rsbac/adf/udf/Makefile +# +# Makefile for the Linux rsbac UDF decision module. +# +# Author and (c) 1999-2013 Amon Ott +# + +# 2.6.x +obj-y := udf_main.o diff --git a/rsbac/adf/udf/udf_main.c b/rsbac/adf/udf/udf_main.c new file mode 100644 index 000000000000..ecc9d466603b --- /dev/null +++ b/rsbac/adf/udf/udf_main.c @@ -0,0 +1,782 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of the Access Control Decision */ +/* Facility (ADF) - User Space Decision Facility */ +/* File: rsbac/adf/udf/udf_main.c */ +/* */ +/* Author and (c) 1999-2016: Amon Ott */ +/* */ +/* Last modified: 01/Aug/2016 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************* */ +/* Global Variables */ +/************************************************* */ + +#define UDF_MAX_PROGNAME PATH_MAX + +static char udf_checker_prog[RSBAC_MAXNAMELEN] = ""; + +static int R_INIT udf_checker_setup(char *line) + { + strncpy(udf_checker_prog, line, RSBAC_MAXNAMELEN - 1); + udf_checker_prog[RSBAC_MAXNAMELEN - 1] = 0; + return 1; + } +__setup("rsbac_udf_checker=", udf_checker_setup); + +static int udf_checker_wait = UMH_WAIT_PROC | UMH_KILLABLE; + +static int R_INIT udf_checker_wait_setup(char *line) + { + udf_checker_wait = UMH_WAIT_PROC; + return 1; + } +__setup("rsbac_udf_nokill", udf_checker_wait_setup); + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +#if defined(CONFIG_RSBAC_PROC) +#ifndef PROC_BLOCK_SIZE +#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ +#endif + +static int +udf_checker_proc_show(struct seq_file *m, void *v) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) + return (-ENOSYS); + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "udf_checker_proc_info(): calling ADF.\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + seq_printf(m, "%s\n", udf_checker_prog); + + return 0; +} + +static ssize_t udf_checker_proc_write(struct file * file, const char __user * buf, + size_t count, loff_t *ppos) +{ + ssize_t err; + char * k_buf; + char * p; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(count > RSBAC_MAXNAMELEN - 1) { + return -EOVERFLOW; + } + + if (!rsbac_is_initialized()) { + return -ENOSYS; + } + + if (!(k_buf = (char *) __get_free_page(GFP_KERNEL))) + return -ENOMEM; + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) { + rsbac_printk(KERN_DEBUG "udf_checker_proc_write(): calling ADF.\n"); + } +#endif + rsbac_target_id.dummy = 0; + rsbac_attribute_value.switch_target = SW_UDF; + if (!rsbac_adf_request(R_SWITCH_MODULE, + task_pid(current), + T_NONE, + rsbac_target_id, + A_switch_target, + rsbac_attribute_value)) { + err = -EPERM; + goto out; + } + + /* + * Usage: echo "/path/to/program" > /proc/rsbac_info/udf_checker + * to set checker program to given value and enable checking + * Program gets called with single parameter "path to file" + * and must exit with either 0 (allowed) or another value (denied) + */ + err = copy_from_user(k_buf, buf, count); + if(err < 0) + return err; + k_buf[RSBAC_MAXNAMELEN - 1] = 0; + p = k_buf; + if (*p && (*p != '/') && (*p != '\n')) { + err = -EINVAL; + goto out; + } + while (*p && (*p != '\n')) { + if (! ( ((*p >= 'A') && (*p <= 'Z')) + || ((*p >= 'a') && (*p <= 'z')) + || ((*p >= '0') && (*p <= '9')) + || (*p == '/') + || (*p == '_') + || (*p == '-') + || (*p == '.') + ) + ) { + rsbac_printk(KERN_INFO + "udf_checker_proc_write(): setting UDF checker denied, invalid character detected.\n"); + err = -EINVAL; + goto out; + } + p++; + } + if (*p) + *p = 0; + + strncpy(udf_checker_prog, k_buf, RSBAC_MAXNAMELEN - 1); + udf_checker_prog[RSBAC_MAXNAMELEN - 1] = 0; + if (udf_checker_prog[0]) + rsbac_printk(KERN_INFO + "udf_checker_proc_write(): setting UDF checker to %s, checking is now enabled\n", + udf_checker_prog); + else + rsbac_printk(KERN_INFO + "udf_checker_proc_write(): UDF checker set to empty, checking is now disabled\n", + udf_checker_prog); + err = count; + +out: + free_page((ulong) k_buf); + return err; + } + +static int udf_checker_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, udf_checker_proc_show, NULL); +} + +static const struct file_operations udf_checker_proc_fops = { + .owner = THIS_MODULE, + .open = udf_checker_proc_open, + .read = seq_read, + .write = udf_checker_proc_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *udf_checker; + +#endif /* CONFIG_RSBAC_PROC */ + +#if defined(CONFIG_RSBAC_UDF_CACHE) +static int udf_reset_checked(struct rsbac_fs_file_t file) +{ + union rsbac_attribute_value_t i_attr_val1; + union rsbac_target_id_t i_tid; + + /* reset checked status for file */ + rsbac_pr_debug(adf_udf, "pid %u(%s), resetting checked status.\n", + current->pid, current->comm); + i_tid.file=file; + i_attr_val1.udf_checked = UDF_unchecked; + if(rsbac_set_attr(SW_UDF, + T_FILE, + i_tid, + A_udf_checked, + i_attr_val1)) + { + rsbac_printk(KERN_WARNING "udf_reset_checked(): rsbac_set_attr() for udf_checked on device %02u:%02u inode %lu returned error!\n", + MAJOR(file.device), MINOR(file.device), file.inode); + return -RSBAC_EWRITEFAILED; + } + if (rsbac_get_attr(SW_UDF, + T_FILE, + i_tid, + A_udf_checker, + &i_attr_val1, + TRUE)) { + rsbac_printk(KERN_WARNING + "udf_reset_checked(): rsbac_get_attr() for udf_checker returned error!\n"); + return -RSBAC_EREADFAILED; + } + if (i_attr_val1.udf_checker) { + /* reset checker flag for file */ + i_attr_val1.udf_checker = FALSE; + if(rsbac_set_attr(SW_UDF, + T_FILE, + i_tid, + A_udf_checker, + i_attr_val1)) + { + rsbac_printk(KERN_WARNING "udf_reset_checked(): rsbac_set_attr() for udf_checker on device %02u:%02u inode %lu returned error!\n", + MAJOR(file.device), MINOR(file.device), file.inode); + return -RSBAC_EWRITEFAILED; + } + } + return 0; +} +#else +static inline int udf_reset_checked(struct rsbac_fs_file_t file) +{ + return 0; +} +#endif + +enum rsbac_adf_req_ret_t udf_do_check(union rsbac_target_id_t tid) +{ + char *envp[] = { "HOME=/", + "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + NULL }; + char *argv[] = {udf_checker_prog, NULL, NULL }; + char * progname; + int err; + u_int result; + + progname = rsbac_kmalloc_unlocked(RSBAC_UDF_PATH_MAX); + if (!progname) { + rsbac_printk(KERN_WARNING + "udf_do_check(): cannot allocate memory!\n"); + return NOT_GRANTED; + } + + err = rsbac_lookup_full_path(tid.file.dentry_p, progname, RSBAC_UDF_PATH_MAX, 0); + if (err < 0) { + char * tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING + "udf_do_check(): rsbac_lookup_full_path() returned error %s!\n", get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + return NOT_GRANTED; + } + rsbac_pr_debug(adf_udf, "udf_do_check(): calling %s for path %s.\n", udf_checker_prog, progname); + + argv[1] = progname; + err = call_usermodehelper(argv[0], argv, envp, udf_checker_wait); + rsbac_kfree(progname); + result = err >> 8; + + if (err < 0) { + if (err != -ERESTARTSYS) + rsbac_printk(KERN_WARNING "udf_do_check(): call_usermodehelper() could not execute %s, error %i.\n", udf_checker_prog, err); +#if defined(CONFIG_RSBAC_DEBUG) + else + rsbac_pr_debug(adf_udf, "udf_do_check(): call_usermodehelper() returned -ERESTARTSYS, checker was interrupted.\n"); +#endif + } +#if defined(CONFIG_RSBAC_DEBUG) || defined(CONFIG_RSBAC_UDF_CACHE) + else { + u_int signal; +#if defined(CONFIG_RSBAC_UDF_CACHE) + union rsbac_attribute_value_t i_attr_val1; +#endif + + signal = err & 255; + rsbac_pr_debug(adf_udf, "udf_do_check(): call_usermodehelper() returned %u (result %u, signal %u).\n", err, result, signal); +#if defined(CONFIG_RSBAC_UDF_CACHE) + /* only cache, if not killed by signal and no temp fail */ + if ( !signal + && (result != UDF_res_temp_fail_allow) + && (result != UDF_res_temp_fail_deny) + ) { + if(!result) + i_attr_val1.udf_checked = UDF_allowed; + else + i_attr_val1.udf_checked = UDF_denied; + if (rsbac_set_attr(SW_UDF, + T_FILE, + tid, + A_udf_checked, + i_attr_val1)) + rsbac_printk(KERN_WARNING "udf_do_check(): rsbac_set_attr() returned error!\n"); + } +#endif + } +#endif + + if (!err || (result == UDF_res_temp_fail_allow)) + return GRANTED; + else + return NOT_GRANTED; +} + +static int udf_ignored(union rsbac_target_id_t tid) +{ + union rsbac_attribute_value_t i_attr_val1; + + if (rsbac_get_attr(SW_UDF, + T_FILE, + tid, + A_udf_do_check, + &i_attr_val1, + TRUE)) { + rsbac_printk(KERN_WARNING + "rsbac_adf_request_udf(): rsbac_get_attr() for udf_do_check returned error!\n"); + return FALSE; + } + if(i_attr_val1.udf_do_check == UDF_never) + return TRUE; + return FALSE; +} + +#if defined(CONFIG_RSBAC_UDF_UDF_PROT) +static enum rsbac_adf_req_ret_t udf_check_secoff(rsbac_uid_t owner, enum rsbac_attribute_t attr, int readonly) +{ + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + /* Security Officer? */ + i_tid.user = owner; + if (rsbac_get_attr(SW_UDF, + T_USER, + i_tid, + A_udf_role, + &i_attr_val1, + TRUE)) { + rsbac_printk(KERN_WARNING + "rsbac_adf_request_udf(): rsbac_get_attr() returned error!\n"); + return NOT_GRANTED; + } + /* if sec_officer, then grant */ + if ( (i_attr_val1.system_role == SR_security_officer) + || (readonly && (i_attr_val1.system_role == SR_administrator)) + ) + return GRANTED; + else + return NOT_GRANTED; +} +#endif + +/************************************************* */ +/* Externally visible functions */ +/************************************************* */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_init_udf(void) +#else +int __init rsbac_init_udf(void) +#endif +{ + if (rsbac_is_initialized()) + { + rsbac_printk(KERN_WARNING "rsbac_init_udf(): RSBAC already initialized\n"); + return -RSBAC_EREINIT; + } + + /* init data structures */ + rsbac_printk(KERN_INFO "rsbac_init_udf(): Initializing RSBAC: UDF subsystem\n"); + if (udf_checker_prog[0]) + rsbac_printk(KERN_DEBUG "rsbac_init_udf(): rsbac_udf_checker is %s\n", udf_checker_prog); + else + rsbac_printk(KERN_DEBUG "rsbac_init_udf(): rsbac_udf_checker is unset, no checking\n"); + + if (udf_checker_wait & UMH_KILLABLE) + rsbac_printk(KERN_DEBUG "rsbac_init_udf(): rsbac_udf_nokill is not set, checker is killable\n"); + else + rsbac_printk(KERN_DEBUG "rsbac_init_udf(): rsbac_udf_nokill is set, checker is not killable\n"); + + #if defined(CONFIG_RSBAC_PROC) + udf_checker = proc_create("udf_checker", S_IFREG | S_IRUGO | S_IWUGO, proc_rsbac_root_p, &udf_checker_proc_fops); + #endif + + return 0; +} + +inline enum rsbac_adf_req_ret_t +rsbac_adf_request_udf (enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + int daemon_allowed; + + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + /* get udf_do_check for target */ + switch(target) { + case T_FILE: + switch(request) { + case R_EXECUTE: + if(udf_ignored(tid)) + return DO_NOT_CARE; + daemon_allowed = 0; + break; + case R_READ_WRITE_OPEN: + case R_READ_OPEN: + if(udf_ignored(tid)) + return DO_NOT_CARE; + daemon_allowed = 1; + break; +#if defined(CONFIG_RSBAC_UDF_UDF_PROT) + case R_READ_ATTRIBUTE: + switch (attr) { + case A_udf_role: + case A_udf_checker: + case A_udf_checked: + case A_udf_do_check: + case A_system_role: + case A_none: + return udf_check_secoff(owner, attr, TRUE); + default: + return DO_NOT_CARE; + } + case R_MODIFY_ATTRIBUTE: + switch (attr) { + case A_udf_role: + case A_udf_checker: + case A_udf_checked: + case A_udf_do_check: + case A_system_role: + case A_none: + return udf_check_secoff(owner, attr, FALSE); + default: + return DO_NOT_CARE; + } +#endif + default: + return DO_NOT_CARE; + } + break; + +#if defined(CONFIG_RSBAC_UDF_UDF_PROT) + case T_DIR: + case T_PROCESS: + case T_USER: + switch(request) { + case R_READ_ATTRIBUTE: + switch (attr) { + case A_udf_role: + case A_udf_checker: + case A_udf_checked: + case A_udf_do_check: + case A_system_role: + case A_none: + return udf_check_secoff(owner, attr, TRUE); + default: + return DO_NOT_CARE; + } + case R_MODIFY_ATTRIBUTE: + switch (attr) { + case A_udf_role: + case A_udf_checker: + case A_udf_checked: + case A_udf_do_check: + case A_system_role: + case A_none: + return udf_check_secoff(owner, attr, FALSE); + default: + return DO_NOT_CARE; + } + default: + return DO_NOT_CARE; + } + break; + case T_NONE: + switch(request) { + case R_SWITCH_MODULE: + /* we need the switch_target */ + if(attr != A_switch_target) + return NOT_GRANTED; + /* do not care for other modules */ + if( (attr_val.switch_target != SW_UDF) +#ifdef CONFIG_RSBAC_SOFTMODE + && (attr_val.switch_target != SW_SOFTMODE) +#endif +#ifdef CONFIG_RSBAC_FREEZE + && (attr_val.switch_target != SW_FREEZE) +#endif +#ifdef CONFIG_RSBAC_MPROTECT + && (attr_val.switch_target != SW_MPROTECT) +#endif + ) + return DO_NOT_CARE; + return udf_check_secoff(owner, attr, FALSE); + default: + return DO_NOT_CARE; + } + break; +#endif /* UDF_UDF_PROT */ + + default: + return DO_NOT_CARE; + } + +/* From here we can only have FILE targets */ + +/* checker enabled? */ + if (!udf_checker_prog[0]) { + rsbac_pr_debug(adf_udf, "pid %u(%s), no checker defined.\n", + current->pid, current->comm); + return DO_NOT_CARE; + } + + if (daemon_allowed) { + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_UDF, + T_PROCESS, + i_tid, + A_udf_checker, + &i_attr_val1, + FALSE)) { + rsbac_printk(KERN_WARNING + "rsbac_adf_request_udf(): rsbac_get_attr() returned error!\n"); + return NOT_GRANTED; + } + /* if checker, then grant */ + if (i_attr_val1.udf_checker) { + rsbac_pr_debug(adf_udf, "pid %u(%s) is a checker, no checking required for device %02u:%02u inode %lu.\n", + current->pid, current->comm, + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), + tid.file.inode); + return GRANTED; + } + } + +#if defined(CONFIG_RSBAC_UDF_CACHE) + if (rsbac_get_attr(SW_UDF, + target, + tid, + A_udf_checked, + &i_attr_val1, + FALSE)) { + rsbac_printk(KERN_WARNING + "rsbac_adf_request_udf(): rsbac_get_attr() returned error!\n"); + return NOT_GRANTED; + } + if(i_attr_val1.udf_checked == UDF_allowed) { + rsbac_pr_debug(adf_udf, "pid %u(%s), result allowed for device %02u:%02u inode %lu taken from cache.\n", + current->pid, current->comm, + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), + tid.file.inode); + return GRANTED; + } + if(i_attr_val1.udf_checked == UDF_denied) { + rsbac_pr_debug(adf_udf, "pid %u(%s), result denied for device %02u:%02u inode %lu taken from cache.\n", + current->pid, current->comm, + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), + tid.file.inode); + return NOT_GRANTED; + } +#endif + + rsbac_pr_debug(adf_udf, "pid %u(%s), checking required for device %02u:%02u inode %lu.\n", + current->pid, current->comm, + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), + tid.file.inode); + /* call checker */ + return udf_do_check(tid); +} /* end of rsbac_adf_request_udf() */ + + +/*****************************************************************************/ +/* If the request returned granted and the operation is performed, */ +/* the following function can be called by the AEF to get all aci set */ +/* correctly. For write accesses that are performed fully within the kernel, */ +/* this is usually not done to prevent extra calls, including R_CLOSE for */ +/* cleaning up. Because of this, the write boundary is not adjusted - there */ +/* is no user-level writing anyway... */ +/* The second instance of target specification is the new target, if one has */ +/* been created, otherwise its values are ignored. */ +/* On success, 0 is returned, and an error from rsbac/error.h otherwise. */ + +inline int rsbac_adf_set_attr_udf( + enum rsbac_adf_request_t request, + rsbac_pid_t caller_pid, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t new_target, + union rsbac_target_id_t new_tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t attr_val, + rsbac_uid_t owner) +{ + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + switch(target) { + case T_FILE: + switch(request) { + case R_EXECUTE: + /* get udf_checker for file */ + if (rsbac_get_attr(SW_UDF, + T_FILE, + tid, + A_udf_checker, + &i_attr_val1, + TRUE)) { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_udf(): rsbac_get_attr() returned error!\n"); + return -RSBAC_EREADFAILED; + } + /* and set for process, if new program is checker */ + if(i_attr_val1.udf_checker) { + i_tid.process = caller_pid; + if (rsbac_set_attr(SW_UDF, + T_PROCESS, + i_tid, + A_udf_checker, + i_attr_val1)) { + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_udf(): rsbac_set_attr() returned error!\n"); + return -RSBAC_EWRITEFAILED; + } + } + return 0; + case R_CLOSE: + if(udf_ignored(tid)) + return 0; + if( (attr == A_f_mode) + && (attr_val.f_mode & FMODE_WRITE) + ) { + udf_reset_checked(tid.file); +#if defined(CONFIG_RSBAC_UDF_ON_CLOSE) + break; +#endif + } + return 0; + case R_APPEND_OPEN: + case R_READ_WRITE_OPEN: + case R_WRITE_OPEN: + if(!udf_ignored(tid)) + udf_reset_checked(tid.file); + return 0; + case R_DELETE: + if(!udf_ignored(tid)) + udf_reset_checked(tid.file); + return 0; + default: + return 0; + } + break; + case T_PROCESS: + switch(request) { + case R_CLONE: + /* Get udf_checker from first process */ + if (rsbac_get_attr(SW_UDF, + T_PROCESS, + tid, + A_udf_checker, + &i_attr_val1, + FALSE)) { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_udf(): rsbac_get_attr() returned error!\n"); + return -RSBAC_EREADFAILED; + } + /* Set udf_checker for new process, if set for first */ + if ( i_attr_val1.udf_checker + && (rsbac_set_attr(SW_UDF, + T_PROCESS, + new_tid, + A_udf_checker, + i_attr_val1)) ) { + rsbac_printk(KERN_WARNING "rsbac_adf_set_attr_udf(): rsbac_set_attr() returned error!\n"); + return -RSBAC_EWRITEFAILED; + } + return 0; + default: + return 0; + } + default: + return 0; + } + +/* only needed for CLOSE, if enabled */ +#if defined(CONFIG_RSBAC_UDF_ON_CLOSE) +/* checker enabled? */ + if (!udf_checker_prog[0]) + return 0; + + i_tid.process = caller_pid; + if (rsbac_get_attr(SW_UDF, + T_PROCESS, + i_tid, + A_udf_checker, + &i_attr_val1, + FALSE)) { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_udf(): rsbac_get_attr() returned error!\n"); + return -RSBAC_EREADFAILED; + } + /* if checker, then grant */ + if (i_attr_val1.udf_checker) { + rsbac_pr_debug(adf_udf, "pid %u(%s) is a checker, no checking required for device %02u:%02u inode %lu.\n", + current->pid, current->comm, + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), + tid.file.inode); + return 0; + } + +#if defined(CONFIG_RSBAC_UDF_CACHE) + /* get udf_checked for file */ + if (rsbac_get_attr(SW_UDF, + target, + tid, + A_udf_checked, + &i_attr_val1, + FALSE)) + { + rsbac_printk(KERN_WARNING + "rsbac_adf_set_attr_udf(): rsbac_get_attr() returned error!\n"); + return -RSBAC_EREADFAILED; + } + if(i_attr_val1.udf_checked == UDF_allowed) + return 0; + if(i_attr_val1.udf_checked == UDF_denied) + return 0; +#endif + + rsbac_pr_debug(adf_udf, "pid %u(%s), checking required for device %02u:%02u inode %lu.\n", + current->pid, current->comm, + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), + tid.file.inode); + /* call checker */ + udf_do_check(tid); +#endif /* RSBAC_UDF_ON_CLOSE */ + + return 0; +} /* end of rsbac_adf_set_attr_udf() */ diff --git a/rsbac/data_structures/Makefile b/rsbac/data_structures/Makefile new file mode 100644 index 000000000000..83b2a5a43c86 --- /dev/null +++ b/rsbac/data_structures/Makefile @@ -0,0 +1,18 @@ +# +# File: rsbac/data_structures/Makefile +# +# Makefile for the RSBAC data structures. +# +# Author and (c) 1999-2012 Amon Ott +# + +obj-y += aci_data_structures.o gen_lists.o + +# Adding policy dependent data structures + +obj-$(CONFIG_RSBAC_MAC) += mac_data_structures.o +obj-$(CONFIG_RSBAC_RC) += rc_data_structures.o +obj-$(CONFIG_RSBAC_AUTH) += auth_data_structures.o +obj-$(CONFIG_RSBAC_ACL) += acl_data_structures.o +obj-$(CONFIG_RSBAC_UM) += um_data_structures.o + diff --git a/rsbac/data_structures/aci_data_structures.c b/rsbac/data_structures/aci_data_structures.c new file mode 100644 index 000000000000..0217cec66563 --- /dev/null +++ b/rsbac/data_structures/aci_data_structures.c @@ -0,0 +1,14579 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of ACI data structures */ +/* Author and (c) 1999-2017: Amon Ott */ +/* (some smaller parts copied from fs/namei.c */ +/* and others) */ +/* */ +/* Last modified: 17/May/2017 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../fs/mount.h" + +#define FUSE_SUPER_MAGIC 0x65735546 +#define CEPH_SUPER_MAGIC 0x00c36400 + +#ifdef CONFIG_RSBAC_MAC +#include +#endif + +#ifdef CONFIG_RSBAC_DAZ +#include +#endif + +#if defined(CONFIG_RSBAC_RC) +#include +#endif + +#if defined(CONFIG_RSBAC_AUTH) +#include +#endif + +#if defined(CONFIG_RSBAC_ACL) +#include +#endif + +#if defined(CONFIG_RSBAC_JAIL) +rsbac_jail_id_t rsbac_jail_syslog_jail_id = 0; +#endif + +#if defined(CONFIG_RSBAC_PAX) && (defined(CONFIG_PAX_NOEXEC) || defined(CONFIG_PAX_ASLR)) +#include +#endif + +#ifdef CONFIG_RSBAC_UM +#include +#endif + +#ifdef CONFIG_RSBAC_UDF +#include +#endif + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +#include +#include +static u_int auto_interval = CONFIG_RSBAC_AUTO_WRITE * HZ; +#endif /* CONFIG_RSBAC_AUTO_WRITE */ + +#if (defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0)) \ + || defined(CONFIG_RSBAC_INIT_THREAD) +static DECLARE_WAIT_QUEUE_HEAD(rsbacd_wait); +#endif + +#if defined(CONFIG_RSBAC_NET_OBJ) +#include +#endif + +/************************************************************************** */ +/* Global Variables */ +/************************************************************************** */ + +/* The following global variables are needed for access to ACI data. */ + +#if defined(CONFIG_RSBAC_REG) +EXPORT_SYMBOL(rsbac_initialized); +#endif +rsbac_boolean_t rsbac_initialized = FALSE; + +static rsbac_boolean_t rsbac_allow_mounts = FALSE; + +static char compiled_modules[80]; + +kdev_t rsbac_root_dev; +#ifdef CONFIG_RSBAC_INIT_DELAY +struct vfsmount * rsbac_root_vfsmount_p = NULL; +#endif +#if defined(CONFIG_RSBAC_REG) +EXPORT_SYMBOL(rsbac_root_dev); +#endif +DEFINE_SEMAPHORE(rsbac_write_sem); + +static struct rsbac_device_list_head_t * device_head_p[RSBAC_NR_DEVICE_LISTS]; +static spinlock_t device_list_locks[RSBAC_NR_DEVICE_LISTS]; +static struct srcu_struct device_list_srcu[RSBAC_NR_DEVICE_LISTS]; +static struct lock_class_key device_list_lock_class; + +#ifdef CONFIG_RSBAC_XSTATS +__u64 syscall_count[RSYS_none]; +#endif + +static struct rsbac_dev_handles_t dev_handles; +static struct rsbac_dev_handles_t dev_major_handles; +static struct rsbac_ipc_handles_t ipc_handles; +static struct rsbac_user_handles_t user_handles; +#ifdef CONFIG_RSBAC_RC_UM_PROT +static struct rsbac_group_handles_t group_handles; +#endif +static struct rsbac_process_handles_t process_handles; + +#ifdef CONFIG_RSBAC_NET_DEV +static struct rsbac_netdev_handles_t netdev_handles; +#endif +#ifdef CONFIG_RSBAC_NET_OBJ +static rsbac_list_handle_t net_temp_handle; +static struct rsbac_nettemp_handles_t nettemp_handles; +#if defined(CONFIG_RSBAC_MAC) || defined(CONFIG_RSBAC_RC) +static struct rsbac_lnetobj_handles_t lnetobj_handles; +static struct rsbac_rnetobj_handles_t rnetobj_handles; +#endif +#if defined(CONFIG_RSBAC_IND_NETOBJ_LOG) +static struct rsbac_gen_netobj_aci_t def_gen_netobj_aci = + DEFAULT_GEN_NETOBJ_ACI; +#endif +#endif + +/* Default ACIs: implemented as variables, might be changeable some time */ + +/* rsbac root dir items, end of recursive inherit */ +static struct rsbac_gen_fd_aci_t def_gen_root_dir_aci = + DEFAULT_GEN_ROOT_DIR_ACI; +static struct rsbac_gen_fd_aci_t def_gen_fd_aci = DEFAULT_GEN_FD_ACI; + +#if defined(CONFIG_RSBAC_MAC) +static struct rsbac_mac_fd_aci_t def_mac_root_dir_aci = + DEFAULT_MAC_ROOT_DIR_ACI; +static struct rsbac_mac_fd_aci_t def_mac_fd_aci = DEFAULT_MAC_FD_ACI; +#endif +#if defined(CONFIG_RSBAC_DAZ) +static struct rsbac_daz_fd_aci_t def_daz_root_dir_aci = DEFAULT_DAZ_ROOT_DIR_ACI; +#if defined(CONFIG_RSBAC_DAZ_CACHE) +static rsbac_time_t rsbac_daz_ttl = CONFIG_RSBAC_DAZ_TTL; +#endif +#endif +#if defined(CONFIG_RSBAC_RC) +static struct rsbac_rc_fd_aci_t def_rc_root_dir_aci = + DEFAULT_RC_ROOT_DIR_ACI; +static struct rsbac_rc_fd_aci_t def_rc_fd_aci = DEFAULT_RC_FD_ACI; +#endif +#if defined(CONFIG_RSBAC_RES) +static struct rsbac_res_fd_aci_t def_res_fd_aci = DEFAULT_RES_FD_ACI; +#endif +#if defined(CONFIG_RSBAC_UDF) +static struct rsbac_udf_fd_aci_t def_udf_root_dir_aci = DEFAULT_UDF_ROOT_DIR_ACI; +#if defined(CONFIG_RSBAC_UDF_CACHE) +static rsbac_time_t rsbac_udf_ttl = CONFIG_RSBAC_UDF_TTL; +#endif +#endif + +#if defined(CONFIG_RSBAC_PROC) +#include + +#ifdef CONFIG_RSBAC_XSTATS +static __u64 get_attr_count[T_NONE] = { 0, 0, 0, 0, 0, 0, 0 }; +static __u64 set_attr_count[T_NONE] = { 0, 0, 0, 0, 0, 0, 0 }; +static __u64 remove_count[T_NONE] = { 0, 0, 0, 0, 0, 0, 0 }; +static __u64 get_parent_count = 0; +#endif + +#if defined(CONFIG_RSBAC_REG) +EXPORT_SYMBOL(proc_rsbac_root_p); +#endif +struct proc_dir_entry *proc_rsbac_root_p = NULL; + +#if defined(CONFIG_RSBAC_REG) +EXPORT_SYMBOL(proc_rsbac_backup_p); +#endif +struct proc_dir_entry *proc_rsbac_backup_p = NULL; + +#endif /* PROC */ + +#ifdef CONFIG_DEVFS_MOUNT +#include +#endif + +static struct rsbac_mount_list_t * rsbac_mount_list = NULL; + +#ifdef CONFIG_RSBAC_MAC +static struct rsbac_mac_process_aci_t mac_init_p_aci = + DEFAULT_MAC_P_INIT_ACI; +#endif +#ifdef CONFIG_RSBAC_RC +static struct rsbac_rc_process_aci_t rc_kernel_p_aci = + DEFAULT_RC_P_KERNEL_ACI; +#endif + +static kdev_t umount_device_in_progress = RSBAC_AUTO_DEV; + +static struct kmem_cache * device_item_slab = NULL; + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +static struct rsbac_delayed_kfree_list_t * delayed_kfree_first = NULL; +static struct rsbac_delayed_kfree_list_t * delayed_kfree_last = NULL; +DEFINE_SPINLOCK(delayed_kfree_lock); +static struct kmem_cache * delayed_kfree_item_slab = NULL; +#ifdef CONFIG_RSBAC_XSTATS +static u_long delayed_kfree_count = 0; +static u_int delayed_kfree_used = 0; +#endif +#endif + +/**************************************************/ +/* Declarations of internal functions */ +/**************************************************/ + +static struct rsbac_device_list_item_t *lookup_device(kdev_t kdev, u_int hash); + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +static u_int gen_nr_fd_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; +static u_int gen_nr_p_hash_bits = 1; + +#if defined(CONFIG_RSBAC_MAC) +static u_int mac_nr_fd_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; +static u_int mac_nr_p_hash_bits = 1; +#endif +#if defined(CONFIG_RSBAC_DAZ) +static u_int daz_nr_fd_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; + +#if defined(CONFIG_RSBAC_DAZ_CACHE) +static u_int daz_scanned_nr_fd_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; +#endif +#endif +#if defined(CONFIG_RSBAC_FF) +static u_int ff_nr_fd_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; +#endif +#if defined(CONFIG_RSBAC_RC) +static u_int rc_nr_fd_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; +static u_int rc_nr_p_hash_bits = 1; +#endif +#if defined(CONFIG_RSBAC_AUTH) +static u_int auth_nr_fd_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; +#endif +#if defined(CONFIG_RSBAC_CAP) +static u_int cap_nr_fd_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; +#endif +#if defined(CONFIG_RSBAC_JAIL) +static u_int jail_nr_p_hash_bits = 1; +#endif +#if defined(CONFIG_RSBAC_PAX) +static u_int pax_nr_fd_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; +#endif +#if defined(CONFIG_RSBAC_RES) +static u_int res_nr_fd_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; +#endif +#if defined(CONFIG_RSBAC_UDF) +static u_int udf_nr_fd_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; + +#if defined(CONFIG_RSBAC_UDF_CACHE) +static u_int udf_checked_nr_fd_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; +#endif +#endif + +static inline u_int device_hash(kdev_t id) +{ + return id & (RSBAC_NR_DEVICE_LISTS - 1); +} + +/* These help functions do NOT handle data consistency protection by */ +/* rw-spinlocks! This is done exclusively by non-internal functions! */ + +/************************************************************************** */ +/* Read/Write functions */ + +/* This help function protects some filesystems from being written to */ +/* and disables writing under some conditions, e.g. in an interrupt */ + +rsbac_boolean_t rsbac_type_writable(struct super_block * sb_p) +{ +#ifdef CONFIG_RSBAC_NO_WRITE + return FALSE; +#else + if (!sb_p || !sb_p->s_dev) + return FALSE; + if ( (sb_p->s_magic == SOCKFS_MAGIC) +#ifndef CONFIG_RSBAC_MSDOS_WRITE + || (sb_p->s_magic == MSDOS_SUPER_MAGIC) +#endif + || (sb_p->s_magic == PIPEFS_MAGIC) + || (sb_p->s_magic == TMPFS_MAGIC) + || (sb_p->s_magic == ANON_INODE_FS_MAGIC) + || (sb_p->s_magic == 0xa10a10a1) /* AIO_RING_MAGIC */ + || (sb_p->s_magic == BDEVFS_MAGIC) + || (sb_p->s_magic == DEVPTS_SUPER_MAGIC) + || (sb_p->s_magic == NSFS_MAGIC) + || (sb_p->s_magic == PROC_SUPER_MAGIC) + || (sb_p->s_magic == DEBUGFS_MAGIC) + || (sb_p->s_magic == CGROUP_SUPER_MAGIC) + || (sb_p->s_magic == BINFMTFS_MAGIC) + || (sb_p->s_magic == SECURITYFS_MAGIC) + || (sb_p->s_magic == SELINUX_MAGIC) + || (sb_p->s_magic == SYSFS_MAGIC) + || (sb_p->s_magic == NFS_SUPER_MAGIC) + || (sb_p->s_magic == CODA_SUPER_MAGIC) + || (sb_p->s_magic == NCP_SUPER_MAGIC) + || (sb_p->s_magic == SMB_SUPER_MAGIC) + || (sb_p->s_magic == ISOFS_SUPER_MAGIC) + || (sb_p->s_magic == OCFS2_SUPER_MAGIC) + || (sb_p->s_magic == FUSE_SUPER_MAGIC) + || (sb_p->s_magic == CEPH_SUPER_MAGIC) + ) + return FALSE; + else + return TRUE; +#endif +} + +rsbac_boolean_t rsbac_device_type_writable(struct rsbac_device_list_item_t *device_p) +{ + if (!device_p || !device_p->vfsmount_p || !device_p->vfsmount_p->mnt_sb) + return FALSE; + return rsbac_type_writable(device_p->vfsmount_p->mnt_sb); +} + +rsbac_boolean_t rsbac_writable(struct super_block * sb_p) +{ +#ifdef CONFIG_RSBAC_NO_WRITE + return FALSE; +#else + if (!sb_p || !sb_p->s_dev) + return FALSE; + if (rsbac_debug_no_write || (sb_p->s_flags & MS_RDONLY) + || in_interrupt()) + return FALSE; + if (!MAJOR(sb_p->s_dev)) + return FALSE; + return rsbac_type_writable(sb_p); +#endif +} + +#ifdef CONFIG_RSBAC_FD_CACHE +static rsbac_boolean_t rsbac_want_cache(struct rsbac_device_list_item_t * device_p) +{ + if ( !rsbac_fd_cache_disable + && ( (RSBAC_MAJOR(device_p->id) > 1) + || ( device_p->vfsmount_p + && device_p->vfsmount_p->mnt_sb + && ( + (rsbac_fd_cache_fuse && device_p->vfsmount_p->mnt_sb->s_magic == FUSE_SUPER_MAGIC) + || (rsbac_fd_cache_ceph && device_p->vfsmount_p->mnt_sb->s_magic == CEPH_SUPER_MAGIC) + ) + ) + ) + ) + return TRUE; + else + return FALSE; +} +#endif + +/* This lookup function ensures correct access to the file system. */ +/* It returns a pointer to the dentry of the rsbac directory on the mounted */ +/* device specified by kdev. If the directory */ +/* does not exist, it is created, if create_dir == TRUE and writable. */ + +static int lookup_aci_path_dentry(struct vfsmount *vfsmount_p, + struct dentry **dir_dentry_pp, + rsbac_boolean_t create_dir, kdev_t kdev) +{ + struct dentry *dir_dentry_p = NULL; + struct dentry *root_dentry_p = NULL; + int err = 0; + struct rsbac_device_list_item_t *device_p; + u_int hash; + int srcu_idx; + + if (!dir_dentry_pp) + return -RSBAC_EINVALIDPOINTER; + + if (!vfsmount_p) { + vfsmount_p = rsbac_get_vfsmount(kdev); + if (!vfsmount_p) { + rsbac_printk(KERN_WARNING "lookup_aci_path_dentry(): unknown device %02u:%02u\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + return -RSBAC_EINVALIDDEV; + } + } + + /* pipefs and sockfs must not be read from */ + if ((vfsmount_p->mnt_sb->s_magic == PIPEFS_MAGIC) + || (vfsmount_p->mnt_sb->s_magic == SOCKFS_MAGIC) + ) { + return -RSBAC_ENOTFOUND; + } + hash = device_hash(kdev); + + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(kdev, hash); + if (!device_p) { + rsbac_printk(KERN_WARNING "lookup_aci_path_dentry(): No entry for device %02u:%02u\n", + MAJOR(kdev), MINOR(kdev)); + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + return -RSBAC_EINVALIDDEV; + } + /* already looked up earlier? */ + if (device_p->rsbac_dir_dentry_p) { + *dir_dentry_pp = device_p->rsbac_dir_dentry_p; +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_ds) { + spin_lock(&device_p->rsbac_dir_dentry_p->d_lock); + rsbac_pr_debug(ds, "device_p->rsbac_dir_dentry_p->d_lockref.count " + "for device %02u:%02u is %i!\n", + MAJOR(vfsmount_p->mnt_sb->s_dev), MINOR(vfsmount_p->mnt_sb->s_dev), + device_p->rsbac_dir_dentry_p->d_lockref.count); + spin_unlock(&device_p->rsbac_dir_dentry_p->d_lock); + } +#endif + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + return 0; + } + /* Must unlock here for the lookup */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + rsbac_pr_debug(ds, "first time lookup for or non-existing %s on device " + "%02u:%02u!\n", RSBAC_ACI_PATH, + MAJOR(vfsmount_p->mnt_sb->s_dev), MINOR(vfsmount_p->mnt_sb->s_dev)); + if (!vfsmount_p->mnt_sb->s_root) { + rsbac_printk(KERN_WARNING "lookup_aci_path_dentry(): Super_block for device %02u:%02u has no root dentry!\n", + MAJOR(vfsmount_p->mnt_sb->s_dev), MINOR(vfsmount_p->mnt_sb->s_dev)); + err = -RSBAC_EINVALIDDEV; + goto out; + } + + if (!vfsmount_p->mnt_sb->s_root->d_inode) { + rsbac_printk(KERN_WARNING "lookup_aci_path_dentry(): Super_block for device %02u:%02u has no root dentry->d_inode!\n", + MAJOR(vfsmount_p->mnt_sb->s_dev), MINOR(vfsmount_p->mnt_sb->s_dev)); + err = -RSBAC_EINVALIDDEV; + goto out; + } + + /* lookup dentry of ACI_PATH on this device */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_ds) { + spin_lock(&vfsmount_p->mnt_sb->s_root->d_lock); + rsbac_pr_debug(ds, "lookup rsbac path %s for device %02u:%02u, " + "sb_p->s_root->d_lockref.count is %i!\n", + RSBAC_ACI_PATH, MAJOR(vfsmount_p->mnt_sb->s_dev), + MINOR(vfsmount_p->mnt_sb->s_dev), + vfsmount_p->mnt_sb->s_root->d_lockref.count); + spin_unlock(&vfsmount_p->mnt_sb->s_root->d_lock); + } +#endif + inode_lock_nested(vfsmount_p->mnt_sb->s_root->d_inode, I_MUTEX_XATTR); + dir_dentry_p = + rsbac_lookup_one_len(RSBAC_ACI_PATH, vfsmount_p->mnt_sb->s_root, + strlen(RSBAC_ACI_PATH)); + inode_unlock(vfsmount_p->mnt_sb->s_root->d_inode); + + if (IS_ERR(dir_dentry_p)) + switch (PTR_ERR(dir_dentry_p)) { + case -ENOENT: + case -ENOTDIR: + err = -RSBAC_ENOTFOUND; + goto out; + case -ENOMEM: + rsbac_printk(KERN_WARNING "lookup_aci_path_dentry(): memory allocation error!\n"); + err = -RSBAC_ENOROOTDIR; + goto out; + case -ENAMETOOLONG: + rsbac_printk(KERN_WARNING "lookup_aci_path_dentry(): ACI_PATH too long on fs!\n"); + err = -RSBAC_EPATHTOOLONG; + goto out; + case -EACCES: + rsbac_printk(KERN_WARNING "lookup_aci_path_dentry(): No access to ACI_PATH!\n"); + err = -RSBAC_EACCESS; + goto out; + default: + rsbac_printk(KERN_WARNING "lookup_aci_path_dentry(): Error on root dir: %li!\n", + PTR_ERR(dir_dentry_p)); + err = -RSBAC_ENOROOTDIR; + goto out; + } + + if (!dir_dentry_p) { + rsbac_printk(KERN_WARNING "lookup_aci_path_dentry(): rsbac_lookup_(dentry|one) returned null pointer!\n"); + err = -RSBAC_EINVALIDPOINTER; + goto out; + } + if (!dir_dentry_p->d_inode) { /* dir could not be found -> try to create it */ + /* but only, if allowed... */ + if (!create_dir) { + err = -RSBAC_ENOTFOUND; + goto out_dir_dput; + } + rsbac_pr_debug(ds, "try to create dir, first test writable!\n"); + /* ... and writable. */ + if (!rsbac_writable(vfsmount_p->mnt_sb)) { /* mounted read only or special case */ + err = -RSBAC_ENOTWRITABLE; + goto out_dir_dput; + } + root_dentry_p = lock_parent(dir_dentry_p); + err = PTR_ERR(root_dentry_p); + if (IS_ERR(root_dentry_p)) { + err = -RSBAC_ECOULDNOTCREATEPATH; + goto out_dir_dput; + } + if (!root_dentry_p->d_inode + || !root_dentry_p->d_inode->i_op + || !root_dentry_p->d_inode->i_op->mkdir) { + unlock_dir(root_dentry_p); + err = -RSBAC_ECOULDNOTCREATEPATH; + goto out_dir_dput; + } + dquot_initialize(root_dentry_p->d_inode); + err = + root_dentry_p->d_inode->i_op->mkdir(root_dentry_p-> + d_inode, + dir_dentry_p, + RSBAC_ACI_DIR_MODE); + unlock_dir(root_dentry_p); + if (err) { + err = -RSBAC_ECOULDNOTCREATEPATH; + goto out_dir_dput; + } + } else { /* was found */ + /* check, whether this is a dir */ + if (!S_ISDIR(dir_dentry_p->d_inode->i_mode)) { /* no dir! We have a real prob here! */ + rsbac_printk(KERN_WARNING "lookup_aci_path_dentry(): supposed /%s dir on dev %02u:%02u is no dir!\n", + RSBAC_ACI_PATH, + MAJOR(vfsmount_p->mnt_sb->s_dev), + MINOR(vfsmount_p->mnt_sb->s_dev)); + err = -RSBAC_EACCESS; + goto out_dir_dput; + } + } +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_ds) { + spin_lock(&dir_dentry_p->d_lock); + rsbac_pr_debug(ds, "dir_dentry_p->d_lockref.count is %i!\n", + dir_dentry_p->d_lockref.count); + spin_unlock(&dir_dentry_p->d_lock); + spin_lock(&vfsmount_p->mnt_sb->s_root->d_lock); + rsbac_pr_debug(ds, "vfsmount_p->mnt_sb->s_root->d_lockref.count is now %i!\n", + vfsmount_p->mnt_sb->s_root->d_lockref.count); + spin_unlock(&vfsmount_p->mnt_sb->s_root->d_lock); + } +#endif + /* we want to keep dir_dentry_p in device_item */ + /* dput must be done in remove_device_item! */ + *dir_dentry_pp = dir_dentry_p; + + /* Must lock and relookup device_p to cache result */ + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(kdev, hash); + if (device_p && !device_p->rsbac_dir_dentry_p) { + device_p->rsbac_dir_dentry_p = dir_dentry_p; + device_p->rsbac_dir_inode = dir_dentry_p->d_inode->i_ino; + } + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + + out: + return err; + + out_dir_dput: + dput(dir_dentry_p); + goto out; +} + +/************************************************************************** */ +/* The lookup functions return NULL, if the item is not found, and a */ +/* pointer to the item otherwise. */ + +/* First, a lookup for the device list item */ + +static struct rsbac_device_list_item_t *lookup_device(kdev_t kdev, u_int hash) +{ + struct rsbac_device_list_head_t *head_p = srcu_dereference(device_head_p[hash], &device_list_srcu[hash]); + struct rsbac_device_list_item_t *curr = srcu_dereference(head_p->curr, &device_list_srcu[hash]); + + /* if there is no current item or it is not the right one, search... */ + if (!(curr && (MAJOR(curr->id) == MAJOR(kdev)) + && (MINOR(curr->id) == MINOR(kdev)))) + { + curr = srcu_dereference(head_p->head, &device_list_srcu[hash]); + while (curr + && ((RSBAC_MAJOR(curr->id) != RSBAC_MAJOR(kdev)) + || (RSBAC_MINOR(curr->id) != RSBAC_MINOR(kdev)) + ) + ) { + curr = srcu_dereference(curr->next, &device_list_srcu[hash]); + } + if (curr) + device_head_p[hash]->curr = curr; + } + /* it is the current item -> return it */ + return curr; +} + +static struct rsbac_device_list_item_t *lookup_device_locked(kdev_t kdev, u_int hash) +{ + struct rsbac_device_list_item_t *curr = device_head_p[hash]->curr; + + /* if there is no current item or it is not the right one, search... */ + if (!(curr && (MAJOR(curr->id) == MAJOR(kdev)) + && (MINOR(curr->id) == MINOR(kdev)))) + { + curr = device_head_p[hash]->head; + while (curr + && ((RSBAC_MAJOR(curr->id) != RSBAC_MAJOR(kdev)) + || (RSBAC_MINOR(curr->id) != RSBAC_MINOR(kdev)) + ) + ) { + curr = curr->next; + } + if (curr) + device_head_p[hash]->curr = curr; + } + /* it is the current item -> return it */ + return curr; +} + +static int dev_compare(void *desc1, void *desc2) +{ + int result; + struct rsbac_dev_desc_t *i_desc1 = desc1; + struct rsbac_dev_desc_t *i_desc2 = desc2; + + result = memcmp(&i_desc1->type, + &i_desc2->type, sizeof(i_desc1->type)); + if (result) + return result; + result = memcmp(&i_desc1->major, + &i_desc2->major, sizeof(i_desc1->major)); + if (result) + return result; + return memcmp(&i_desc1->minor, + &i_desc2->minor, sizeof(i_desc1->minor)); +} + +#ifdef CONFIG_RSBAC_RC +static int dev_major_compare(void *desc1, void *desc2) +{ + int result; + struct rsbac_dev_desc_t *i_desc1 = desc1; + struct rsbac_dev_desc_t *i_desc2 = desc2; + + result = memcmp(&i_desc1->type, + &i_desc2->type, sizeof(i_desc1->type)); + if (result) + return result; + return memcmp(&i_desc1->major, + &i_desc2->major, sizeof(i_desc1->major)); +} +#endif + +static int ipc_compare(void *desc1, void *desc2) +{ + int result; + struct rsbac_ipc_t *i_desc1 = desc1; + struct rsbac_ipc_t *i_desc2 = desc2; + + result = memcmp(&i_desc1->type, + &i_desc2->type, sizeof(i_desc1->type)); + if (result) + return result; + else + return memcmp(&i_desc1->id.id_nr, + &i_desc2->id.id_nr, + sizeof(i_desc1->id.id_nr)); +} + +#ifdef CONFIG_RSBAC_NET_DEV +#if defined(CONFIG_RSBAC_IND_NETDEV_LOG) || defined(CONFIG_RSBAC_RC) +static int netdev_compare(void *desc1, void *desc2) +{ + return strncmp(desc1, desc2, RSBAC_IFNAMSIZ); +} +#endif +#endif + +/************************************************************************** */ +/* Convert functions */ + +static int gen_fd_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_gen_fd_aci_t *new_aci = new_data; + struct rsbac_gen_fd_old_aci_t *old_aci = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + new_aci->log_array_low = old_aci->log_array_low; + new_aci->log_array_high = old_aci->log_array_high; + new_aci->log_program_based = old_aci->log_program_based; + new_aci->symlink_add_remote_ip = old_aci->symlink_add_remote_ip; + new_aci->symlink_add_uid = old_aci->symlink_add_uid; + new_aci->symlink_add_mac_level = old_aci->symlink_add_mac_level; + new_aci->symlink_add_rc_role = old_aci->symlink_add_rc_role; + new_aci->allow_write_exec = old_aci->allow_write_exec; + new_aci->fake_root_uid = old_aci->fake_root_uid; + new_aci->auid_exempt = old_aci->auid_exempt; + new_aci->vset = RSBAC_UM_VIRTUAL_KEEP; + return 0; +} + +static int gen_fd_old_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_gen_fd_aci_t *new_aci = new_data; + struct rsbac_gen_fd_old_old_aci_t *old_aci = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + new_aci->log_array_low = old_aci->log_array_low; + new_aci->log_array_high = old_aci->log_array_high; + new_aci->log_program_based = old_aci->log_program_based; + new_aci->symlink_add_remote_ip = 0; + new_aci->symlink_add_uid = old_aci->symlink_add_uid; + new_aci->symlink_add_mac_level = old_aci->symlink_add_mac_level; + new_aci->symlink_add_rc_role = old_aci->symlink_add_rc_role; + new_aci->allow_write_exec = old_aci->allow_write_exec; + new_aci->fake_root_uid = old_aci->fake_root_uid; + new_aci->auid_exempt = old_aci->auid_exempt; + new_aci->vset = RSBAC_UM_VIRTUAL_KEEP; + return 0; +} + +static rsbac_list_conv_function_t *gen_fd_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_GEN_FD_OLD_ACI_VERSION: + return gen_fd_conv; + case RSBAC_GEN_FD_OLD_OLD_ACI_VERSION: + return gen_fd_old_conv; + default: + return NULL; + } +} + +static int gen_dev_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_dev_desc_t *new = new_desc; + struct rsbac_dev_t *old = old_desc; + + memcpy(new_data, old_data, sizeof(struct rsbac_gen_dev_aci_t)); + new->type = old->type; + new->major = RSBAC_MAJOR(old->id); + new->minor = RSBAC_MINOR(old->id); + return 0; +} + +static rsbac_list_conv_function_t *gen_dev_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_GEN_DEV_OLD_ACI_VERSION: + return gen_dev_conv; + default: + return NULL; + } +} + +static int gen_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + memcpy(new_data, old_data, sizeof(struct rsbac_gen_user_aci_t)); + return 0; +} + +static rsbac_list_conv_function_t *gen_user_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_GEN_USER_OLD_ACI_VERSION: + return gen_user_conv; + default: + return NULL; + } +} + +#ifdef CONFIG_RSBAC_MAC +static int mac_old_fd_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_mac_fd_aci_t *new_aci = new_data; + struct rsbac_mac_fd_old_aci_t *old_aci = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + new_aci->sec_level = old_aci->sec_level; + new_aci->mac_categories = old_aci->mac_categories; + new_aci->mac_auto = old_aci->mac_auto; + new_aci->mac_prop_trusted = old_aci->mac_prop_trusted; + new_aci->mac_file_flags = old_aci->mac_file_flags; + return 0; +} + +static int mac_old_old_fd_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + struct rsbac_mac_fd_aci_t *new_aci = new_data; + struct rsbac_mac_fd_old_old_aci_t *old_aci = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + new_aci->sec_level = old_aci->sec_level; + new_aci->mac_categories = old_aci->mac_categories; + new_aci->mac_auto = old_aci->mac_auto; + new_aci->mac_prop_trusted = FALSE; + if (old_aci->mac_shared) + new_aci->mac_file_flags = MAC_write_up; + else + new_aci->mac_file_flags = 0; + return 0; +} + +static int mac_old_old_old_fd_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + struct rsbac_mac_fd_aci_t *new_aci = new_data; + struct rsbac_mac_fd_old_old_old_aci_t *old_aci = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + new_aci->sec_level = old_aci->sec_level; + new_aci->mac_categories = old_aci->mac_categories; + new_aci->mac_auto = old_aci->mac_auto; + new_aci->mac_prop_trusted = FALSE; + new_aci->mac_file_flags = 0; + return 0; +} + +static rsbac_list_conv_function_t *mac_fd_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_MAC_FD_OLD_ACI_VERSION: + return mac_old_fd_conv; + case RSBAC_MAC_FD_OLD_OLD_ACI_VERSION: + return mac_old_old_fd_conv; + case RSBAC_MAC_FD_OLD_OLD_OLD_ACI_VERSION: + return mac_old_old_old_fd_conv; + default: + return NULL; + } +} + +static int mac_dev_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_dev_desc_t *new = new_desc; + struct rsbac_dev_t *old = old_desc; + + memcpy(new_data, old_data, sizeof(struct rsbac_mac_dev_aci_t)); + new->type = old->type; + new->major = RSBAC_MAJOR(old->id); + new->minor = RSBAC_MINOR(old->id); + return 0; +} + +static rsbac_list_conv_function_t *mac_dev_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_MAC_DEV_OLD_ACI_VERSION: + return mac_dev_conv; + default: + return NULL; + } +} + +static int mac_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + memcpy(new_data, old_data, sizeof(struct rsbac_mac_user_aci_t)); + return 0; +} + +static int mac_old_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + struct rsbac_mac_user_aci_t *new_aci = new_data; + struct rsbac_mac_user_old_aci_t *old_aci = old_data; + + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + new_aci->security_level = old_aci->access_appr; + new_aci->initial_security_level = old_aci->access_appr; + new_aci->min_security_level = old_aci->min_access_appr; + new_aci->mac_categories = old_aci->mac_categories; + new_aci->mac_initial_categories = old_aci->mac_categories; + new_aci->mac_min_categories = old_aci->mac_min_categories; + new_aci->system_role = old_aci->system_role; + new_aci->mac_user_flags = RSBAC_MAC_DEF_U_FLAGS; + if (old_aci->mac_allow_auto) + new_aci->mac_user_flags |= MAC_allow_auto; + return 0; +} + +static int mac_old_old_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + struct rsbac_mac_user_aci_t *new_aci = new_data; + struct rsbac_mac_user_old_old_aci_t *old_aci = old_data; + + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + new_aci->security_level = old_aci->access_appr; + new_aci->initial_security_level = old_aci->access_appr; + new_aci->min_security_level = old_aci->min_access_appr; + new_aci->mac_categories = old_aci->mac_categories; + new_aci->mac_initial_categories = old_aci->mac_categories; + new_aci->mac_min_categories = old_aci->mac_min_categories; + new_aci->system_role = old_aci->system_role; + new_aci->mac_user_flags = RSBAC_MAC_DEF_U_FLAGS; + return 0; +} + +static int mac_old_old_old_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + struct rsbac_mac_user_aci_t *new_aci = new_data; + struct rsbac_mac_user_old_old_old_aci_t *old_aci = old_data; + + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + new_aci->security_level = old_aci->access_appr; + new_aci->initial_security_level = old_aci->access_appr; + new_aci->min_security_level = SL_unclassified; + new_aci->mac_categories = old_aci->mac_categories; + new_aci->mac_initial_categories = old_aci->mac_categories; + new_aci->mac_min_categories = RSBAC_MAC_MIN_CAT_VECTOR; + new_aci->system_role = old_aci->system_role; + new_aci->mac_user_flags = RSBAC_MAC_DEF_U_FLAGS; + return 0; +} + +static rsbac_list_conv_function_t *mac_user_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_MAC_USER_OLD_ACI_VERSION: + return mac_user_conv; + case RSBAC_MAC_USER_OLD_OLD_ACI_VERSION: + return mac_old_user_conv; + case RSBAC_MAC_USER_OLD_OLD_OLD_ACI_VERSION: + return mac_old_old_user_conv; + case RSBAC_MAC_USER_OLD_OLD_OLD_OLD_ACI_VERSION: + return mac_old_old_old_user_conv; + default: + return NULL; + } +} +#endif + +#ifdef CONFIG_RSBAC_DAZ +static int daz_old_fd_conv( + void * old_desc, + void * old_data, + void * new_desc, + void * new_data) + { + struct rsbac_daz_fd_aci_t * new_aci = new_data; + struct rsbac_daz_fd_old_aci_t * old_aci = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + new_aci->daz_scanner = old_aci->daz_scanner; + new_aci->daz_do_scan = DEFAULT_DAZ_FD_DO_SCAN; + return 0; + } + +static rsbac_list_conv_function_t * daz_fd_get_conv(rsbac_version_t old_version) + { + switch(old_version) + { + case RSBAC_DAZ_FD_OLD_ACI_VERSION: + return daz_old_fd_conv; + default: + return NULL; + } + } + +static int daz_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + memcpy(new_data, old_data, sizeof(rsbac_system_role_int_t)); + return 0; +} + +static rsbac_list_conv_function_t *daz_user_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_DAZ_USER_OLD_ACI_VERSION: + return daz_user_conv; + default: + return NULL; + } +} +#endif + +#ifdef CONFIG_RSBAC_FF +static int ff_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + memcpy(new_data, old_data, sizeof(rsbac_system_role_int_t)); + return 0; +} + +static rsbac_list_conv_function_t *ff_user_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_FF_USER_OLD_ACI_VERSION: + return ff_user_conv; + default: + return NULL; + } +} +#endif + +#ifdef CONFIG_RSBAC_RC +static int rc_dev_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_dev_desc_t *new = new_desc; + struct rsbac_dev_t *old = old_desc; + + memcpy(new_data, old_data, sizeof(rsbac_rc_type_id_t)); + new->type = old->type; + new->major = RSBAC_MAJOR(old->id); + new->minor = RSBAC_MINOR(old->id); + return 0; +} + +static rsbac_list_conv_function_t *rc_dev_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_RC_DEV_OLD_ACI_VERSION: + return rc_dev_conv; + default: + return NULL; + } +} + +static int rc_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + memcpy(new_data, old_data, sizeof(struct rsbac_rc_user_aci_t)); + return 0; +} + +static int rc_user_old_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_rc_user_aci_t *new_aci = new_data; + rsbac_rc_role_id_t *old_aci = old_data; + + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + new_aci->rc_role = *old_aci; + new_aci->rc_type = RSBAC_RC_GENERAL_TYPE; + return 0; +} + +static rsbac_list_conv_function_t *rc_user_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_RC_USER_OLD_ACI_VERSION: + return rc_user_conv; + case RSBAC_RC_USER_OLD_OLD_ACI_VERSION: + return rc_user_old_conv; + default: + return NULL; + } +} +#endif + +#ifdef CONFIG_RSBAC_AUTH +static int auth_old_fd_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_auth_fd_aci_t *new_aci = new_data; + struct rsbac_auth_fd_old_aci_t *old_aci = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + new_aci->auth_may_setuid = old_aci->auth_may_setuid; + new_aci->auth_may_set_cap = old_aci->auth_may_set_cap; + new_aci->auth_learn = FALSE; + return 0; +} + +static rsbac_list_conv_function_t *auth_fd_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_AUTH_FD_OLD_ACI_VERSION: + return auth_old_fd_conv; + default: + return NULL; + } +} + +static int auth_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + memcpy(new_data, old_data, sizeof(rsbac_system_role_int_t)); + return 0; +} + +static rsbac_list_conv_function_t *auth_user_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_AUTH_USER_OLD_ACI_VERSION: + return auth_user_conv; + default: + return NULL; + } +} +#endif + +#ifdef CONFIG_RSBAC_CAP +static int cap_old_fd_conv(void *old_desc, void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_cap_fd_aci_t *new_aci = new_data; + struct rsbac_cap_fd_old_aci_t *old_aci = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + new_aci->min_caps.cap[0] = old_aci->min_caps; + new_aci->max_caps.cap[0] = old_aci->max_caps; + new_aci->min_caps.cap[1] = (__u32) 0; + new_aci->max_caps.cap[1] = (__u32) -1; + new_aci->cap_ld_env = old_aci->cap_ld_env; + return 0; +} + +static int cap_old_old_fd_conv(void *old_desc, void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_cap_fd_aci_t *new_aci = new_data; + struct rsbac_cap_fd_old_old_aci_t *old_aci = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + new_aci->min_caps.cap[0] = old_aci->min_caps; + new_aci->max_caps.cap[0] = old_aci->max_caps; + new_aci->min_caps.cap[1] = (__u32) 0; + new_aci->max_caps.cap[1] = (__u32) -1; + new_aci->cap_ld_env = LD_inherit; + return 0; +} + +static rsbac_list_conv_function_t *cap_fd_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_CAP_FD_OLD_OLD_ACI_VERSION: + return cap_old_old_fd_conv; + case RSBAC_CAP_FD_OLD_ACI_VERSION: + return cap_old_fd_conv; + default: + return NULL; + } +} + +static int cap_old_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + struct rsbac_cap_user_aci_t *new_aci = new_data; + struct rsbac_cap_user_old_aci_t *old_aci = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_uid_t)); + new_aci->cap_role = old_aci->cap_role; + new_aci->min_caps.cap[0] = old_aci->min_caps; + new_aci->max_caps.cap[0] = old_aci->max_caps; + new_aci->min_caps.cap[1] = (__u32) 0; + new_aci->max_caps.cap[1] = (__u32) -1; + new_aci->cap_ld_env = old_aci->cap_ld_env; + return 0; +} + +static int cap_old_old_user_conv(void *old_desc, void *old_data, void *new_desc, void *new_data) +{ + rsbac_uid_t *new_user = new_desc; + rsbac_old_uid_t *old_user = old_desc; + struct rsbac_cap_user_aci_t *new_aci = new_data; + struct rsbac_cap_user_old_old_aci_t *old_aci = old_data; + + *new_user = RSBAC_GEN_UID(0,*old_user); + new_aci->cap_role = old_aci->cap_role; + new_aci->min_caps.cap[0] = old_aci->min_caps; + new_aci->max_caps.cap[0] = old_aci->max_caps; + new_aci->min_caps.cap[1] = (__u32) 0; + new_aci->max_caps.cap[1] = (__u32) -1; + new_aci->cap_ld_env = old_aci->cap_ld_env; + return 0; +} + +static int cap_old_old_old_user_conv(void *old_desc, void *old_data, void *new_desc, void *new_data) +{ + rsbac_uid_t *new_user = new_desc; + rsbac_old_uid_t *old_user = old_desc; + struct rsbac_cap_user_aci_t *new_aci = new_data; + struct rsbac_cap_user_old_old_aci_t *old_aci = old_data; + + *new_user = RSBAC_GEN_UID(0,*old_user); + new_aci->cap_role = old_aci->cap_role; + new_aci->min_caps.cap[0] = old_aci->min_caps; + new_aci->max_caps.cap[0] = old_aci->max_caps; + new_aci->min_caps.cap[1] = (__u32) 0; + new_aci->max_caps.cap[1] = (__u32) -1; + new_aci->cap_ld_env = LD_allow; + return 0; +} + +static rsbac_list_conv_function_t *cap_user_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_CAP_USER_OLD_ACI_VERSION: + return cap_old_user_conv; + case RSBAC_CAP_USER_OLD_OLD_ACI_VERSION: + return cap_old_old_user_conv; + case RSBAC_CAP_USER_OLD_OLD_OLD_ACI_VERSION: + return cap_old_old_old_user_conv; + default: + return NULL; + } +} +#endif + +#ifdef CONFIG_RSBAC_JAIL +static int jail_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + memcpy(new_data, old_data, sizeof(rsbac_system_role_int_t)); + return 0; +} + +static rsbac_list_conv_function_t *jail_user_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_JAIL_USER_OLD_ACI_VERSION: + return jail_user_conv; + default: + return NULL; + } +} +#endif + +#ifdef CONFIG_RSBAC_PAX +static int pax_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + memcpy(new_data, old_data, sizeof(rsbac_system_role_int_t)); + return 0; +} + +static rsbac_list_conv_function_t *pax_user_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_PAX_USER_OLD_ACI_VERSION: + return pax_user_conv; + default: + return NULL; + } +} +#endif + +#ifdef CONFIG_RSBAC_RES +static int res_user_conv(void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + memcpy(new_data, old_data, sizeof(struct rsbac_res_user_aci_t)); + return 0; +} + +static rsbac_list_conv_function_t *res_user_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_RES_USER_OLD_ACI_VERSION: + return res_user_conv; + default: + return NULL; + } +} +#endif + + +#ifdef CONFIG_RSBAC_NET_OBJ +static int net_temp_old_conv(void *old_desc, void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_net_temp_data_t *new_aci = new_data; + struct rsbac_net_temp_old_data_t *old_aci = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_net_temp_id_t)); + new_aci->address_family = old_aci->address_family; + new_aci->type = old_aci->type; + new_aci->protocol = old_aci->protocol; + memcpy(new_aci->netdev, old_aci->netdev, sizeof(rsbac_netdev_id_t)); + memcpy(new_aci->name, old_aci->name, sizeof(new_aci->name)); + switch(new_aci->address_family) { + case AF_INET: + new_aci->address.inet.nr_addr = 1; + new_aci->address.inet.addr[0] = *((__u32 *) old_aci->address); + new_aci->address.inet.valid_bits[0] = old_aci->valid_len; + if((old_aci->min_port == 0) && (old_aci->max_port == RSBAC_NET_MAX_PORT)) + new_aci->ports.nr_ports = 0; + else { + new_aci->ports.nr_ports = 1; + new_aci->ports.ports[0].min = old_aci->min_port; + new_aci->ports.ports[0].max = old_aci->max_port; + } + break; + default: + memcpy(new_aci->address.other.addr, old_aci->address, sizeof(old_aci->address)); + new_aci->address.other.valid_len = old_aci->valid_len; + new_aci->ports.nr_ports = 0; + break; + } + return 0; +} + + +static rsbac_list_conv_function_t *net_temp_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_NET_TEMP_OLD_VERSION: + return net_temp_old_conv; + default: + return NULL; + } +} +#endif + +/************************************************************************** */ +/* The add_item() functions add an item to the list, set head.curr to it, */ +/* and return a pointer to the item. */ +/* These functions will NOT check, if there is already an item under the */ +/* same ID! If this happens, the lookup functions will return the old item! */ +/* All list manipulation must be protected by rw-spinlocks to prevent */ +/* inconsistency and undefined behaviour in other concurrent functions. */ + +/* register_fd_lists() */ +/* register fd lists for device */ + +static int register_fd_lists(struct rsbac_device_list_item_t *device_p, + kdev_t kdev) +{ + char *name; + int err = 0; + int tmperr; + struct rsbac_list_info_t *info_p; + u_int tmp_flags; + + if (!device_p) + return -RSBAC_EINVALIDPOINTER; + name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (!name) + return -RSBAC_ENOMEM; + info_p = rsbac_kmalloc(sizeof(*info_p)); + if (!info_p) { + rsbac_kfree(name); + return -RSBAC_ENOMEM; + } + if (rsbac_device_type_writable(device_p)) { + tmp_flags = RSBAC_LIST_PERSIST; + device_p->persist = TRUE; + } else { + tmp_flags = 0; + device_p->persist = FALSE; + } + + /* register general lists */ + { + info_p->version = RSBAC_GEN_FD_ACI_VERSION; + info_p->key = RSBAC_GEN_FD_ACI_KEY; + info_p->desc_size = tmp_flags ? sizeof(rsbac_old_inode_nr_t) : sizeof(rsbac_inode_nr_t); + info_p->data_size = + sizeof(struct rsbac_gen_fd_aci_t); + info_p->max_age = 0; + gen_nr_fd_hash_bits = RSBAC_GEN_NR_FD_LIST_HASH_BITS; + tmperr = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &device_p->handles.gen, + info_p, + tmp_flags | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + gen_fd_get_conv, + &def_gen_fd_aci, + RSBAC_GEN_FD_NAME, + kdev, + gen_nr_fd_hash_bits, + tmp_flags ? rsbac_list_hash_old_fd : rsbac_list_hash_fd, + RSBAC_GEN_OLD_FD_NAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "register_fd_lists(): registering general list %s for device %02u:%02u failed with error %s!\n", + RSBAC_GEN_FD_NAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, + tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + } + +#if defined(CONFIG_RSBAC_MAC) + { + /* register MAC lists */ + info_p->version = RSBAC_MAC_FD_ACI_VERSION; + info_p->key = RSBAC_MAC_FD_ACI_KEY; + info_p->desc_size = tmp_flags ? sizeof(rsbac_old_inode_nr_t) : sizeof(rsbac_inode_nr_t); + info_p->data_size = + sizeof(struct rsbac_mac_fd_aci_t); + info_p->max_age = 0; + mac_nr_fd_hash_bits = RSBAC_MAC_NR_FD_LIST_HASH_BITS; + tmperr = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &device_p->handles.mac, + info_p, + tmp_flags | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + mac_fd_get_conv, + &def_mac_fd_aci, + RSBAC_MAC_FD_NAME, + kdev, + mac_nr_fd_hash_bits, + tmp_flags ? rsbac_list_hash_old_fd : rsbac_list_hash_fd, + RSBAC_MAC_OLD_FD_NAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "register_fd_lists(): registering MAC list %s for device %02u:%02u failed with error %s!\n", + RSBAC_MAC_FD_NAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, + tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + } +#endif + +#if defined(CONFIG_RSBAC_DAZ) + { + struct rsbac_daz_fd_aci_t def_daz_fd_aci = + DEFAULT_DAZ_FD_ACI; + /* register DAZ lists */ + info_p->version = RSBAC_DAZ_FD_ACI_VERSION; + info_p->key = RSBAC_DAZ_FD_ACI_KEY; + info_p->desc_size = tmp_flags ? sizeof(rsbac_old_inode_nr_t) : sizeof(rsbac_inode_nr_t); + info_p->data_size = + sizeof(struct rsbac_daz_fd_aci_t); + info_p->max_age = 0; + daz_nr_fd_hash_bits = RSBAC_DAZ_NR_FD_LIST_HASH_BITS; + tmperr = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &device_p->handles.daz, + info_p, + tmp_flags | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + daz_fd_get_conv, + &def_daz_fd_aci, + RSBAC_DAZ_FD_NAME, kdev, + daz_nr_fd_hash_bits, + tmp_flags ? rsbac_list_hash_old_fd : rsbac_list_hash_fd, + RSBAC_DAZ_OLD_FD_NAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "register_fd_lists(): registering DAZ list %s for device %02u:%02u failed with error %s!\n", + RSBAC_DAZ_FD_NAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, + tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + } +#if defined(CONFIG_RSBAC_DAZ_CACHE) + { + rsbac_daz_scanned_t def_daz_scanned_fd_aci = + DEFAULT_DAZ_FD_SCANNED; + + info_p->version = RSBAC_DAZ_SCANNED_FD_ACI_VERSION; + info_p->key = RSBAC_DAZ_FD_ACI_KEY; +#ifdef CONFIG_RSBAC_DAZ_PERSIST + info_p->desc_size = tmp_flags ? sizeof(rsbac_old_inode_nr_t) : sizeof(rsbac_inode_nr_t); +#else + info_p->desc_size = sizeof(rsbac_inode_nr_t); +#endif + info_p->data_size = sizeof(rsbac_daz_scanned_t); + info_p->max_age = 0; + daz_scanned_nr_fd_hash_bits = RSBAC_DAZ_SCANNED_NR_FD_LIST_HASH_BITS; + tmperr = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &device_p->handles.dazs, + info_p, +#ifdef CONFIG_RSBAC_DAZ_PERSIST + tmp_flags | +#endif + RSBAC_LIST_DEF_DATA | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_AUTO_HASH_RESIZE | + RSBAC_LIST_NO_MAX, + NULL, + NULL, + &def_daz_scanned_fd_aci, + RSBAC_DAZ_SCANNED_FD_NAME, kdev, + daz_scanned_nr_fd_hash_bits, +#ifdef CONFIG_RSBAC_DAZ_PERSIST + tmp_flags ? rsbac_list_hash_old_fd : rsbac_list_hash_fd, +#else + rsbac_list_hash_fd, +#endif + RSBAC_DAZ_SCANNED_OLD_FD_NAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "register_fd_lists(): registering DAZ scanned list %s for device %02u:%02u failed with error %s!\n", + RSBAC_DAZ_SCANNED_FD_NAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, + tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + } +#endif +#endif + +#if defined(CONFIG_RSBAC_FF) + { + rsbac_ff_flags_t def_ff_fd_aci = RSBAC_FF_DEF; + + info_p->version = RSBAC_FF_FD_ACI_VERSION; + info_p->key = RSBAC_FF_FD_ACI_KEY; + info_p->desc_size = tmp_flags ? sizeof(rsbac_old_inode_nr_t) : sizeof(rsbac_inode_nr_t); + info_p->data_size = sizeof(rsbac_ff_flags_t); + info_p->max_age = 0; + ff_nr_fd_hash_bits = RSBAC_FF_NR_FD_LIST_HASH_BITS; + tmperr = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &device_p->handles.ff, + info_p, + tmp_flags | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, &def_ff_fd_aci, + RSBAC_FF_FD_NAME, kdev, + ff_nr_fd_hash_bits, + tmp_flags ? rsbac_list_hash_old_fd : rsbac_list_hash_fd, + RSBAC_FF_OLD_FD_NAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "register_fd_lists(): registering FF list %s for device %02u:%02u failed with error %s!\n", + RSBAC_FF_FD_NAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, + tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + } +#endif + +#if defined(CONFIG_RSBAC_RC) + { + info_p->version = RSBAC_RC_FD_ACI_VERSION; + info_p->key = RSBAC_RC_FD_ACI_KEY; + info_p->desc_size = tmp_flags ? sizeof(rsbac_old_inode_nr_t) : sizeof(rsbac_inode_nr_t); + info_p->data_size = + sizeof(struct rsbac_rc_fd_aci_t); + info_p->max_age = 0; + rc_nr_fd_hash_bits = RSBAC_RC_NR_FD_LIST_HASH_BITS; + tmperr = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &device_p->handles.rc, + info_p, + tmp_flags | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, &def_rc_fd_aci, + RSBAC_RC_FD_NAME, kdev, + rc_nr_fd_hash_bits, + tmp_flags ? rsbac_list_hash_old_fd : rsbac_list_hash_fd, + RSBAC_RC_OLD_FD_NAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "register_fd_lists(): registering RC list %s for device %02u:%02u failed with error %s!\n", + RSBAC_RC_FD_NAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, + tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + } +#endif + +#if defined(CONFIG_RSBAC_AUTH) + { + struct rsbac_auth_fd_aci_t def_auth_fd_aci = + DEFAULT_AUTH_FD_ACI; + + info_p->version = RSBAC_AUTH_FD_ACI_VERSION; + info_p->key = RSBAC_AUTH_FD_ACI_KEY; + info_p->desc_size = tmp_flags ? sizeof(rsbac_old_inode_nr_t) : sizeof(rsbac_inode_nr_t); + info_p->data_size = + sizeof(struct rsbac_auth_fd_aci_t); + info_p->max_age = 0; + auth_nr_fd_hash_bits = RSBAC_AUTH_NR_FD_LIST_HASH_BITS; + tmperr = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &device_p->handles.auth, + info_p, + tmp_flags | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + auth_fd_get_conv, + &def_auth_fd_aci, + RSBAC_AUTH_FD_NAME, kdev, + auth_nr_fd_hash_bits, + tmp_flags ? rsbac_list_hash_old_fd : rsbac_list_hash_fd, + RSBAC_AUTH_OLD_FD_NAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "register_fd_lists(): registering AUTH list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_NAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, + tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + } +#endif + +#if defined(CONFIG_RSBAC_CAP) + { + struct rsbac_cap_fd_aci_t def_cap_fd_aci = DEFAULT_CAP_FD_ACI; + + info_p->version = RSBAC_CAP_FD_ACI_VERSION; + info_p->key = RSBAC_CAP_FD_ACI_KEY; + info_p->desc_size = tmp_flags ? sizeof(rsbac_old_inode_nr_t) : sizeof(rsbac_inode_nr_t); + info_p->data_size = + sizeof(struct rsbac_cap_fd_aci_t); + info_p->max_age = 0; + cap_nr_fd_hash_bits = RSBAC_CAP_NR_FD_LIST_HASH_BITS; + tmperr = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &device_p->handles.cap, + info_p, + tmp_flags | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + cap_fd_get_conv, + &def_cap_fd_aci, + RSBAC_CAP_FD_NAME, kdev, + cap_nr_fd_hash_bits, + tmp_flags ? rsbac_list_hash_old_fd : rsbac_list_hash_fd, + RSBAC_CAP_OLD_FD_NAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "register_fd_lists(): registering CAP list %s for device %02u:%02u failed with error %s!\n", + RSBAC_CAP_FD_NAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, + tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + } +#endif + +#if defined(CONFIG_RSBAC_PAX) + { + rsbac_pax_flags_t def_pax_fd_aci; + +#ifdef CONFIG_RSBAC_PAX_DEFAULT + def_pax_fd_aci = 0; +#ifdef CONFIG_RSBAC_PAX_PAGEEXEC + def_pax_fd_aci |= PF_PAX_PAGEEXEC; +#endif +#ifdef CONFIG_RSBAC_PAX_EMUTRAMP + def_pax_fd_aci |= PF_PAX_EMUTRAMP; +#endif +#ifdef CONFIG_RSBAC_PAX_MPROTECT + def_pax_fd_aci |= PF_PAX_MPROTECT; +#endif +#ifdef CONFIG_RSBAC_PAX_RANDMMAP + def_pax_fd_aci |= PF_PAX_RANDMMAP; +#endif +#ifdef CONFIG_RSBAC_PAX_RANDEXEC + def_pax_fd_aci |= PF_PAX_RANDEXEC; +#endif +#ifdef CONFIG_RSBAC_PAX_SEGMEXEC + def_pax_fd_aci |= PF_PAX_SEGMEXEC; +#endif + +#else + def_pax_fd_aci = RSBAC_PAX_DEF_FLAGS; +#endif + + info_p->version = RSBAC_PAX_FD_ACI_VERSION; + info_p->key = RSBAC_PAX_FD_ACI_KEY; + info_p->desc_size = tmp_flags ? sizeof(rsbac_old_inode_nr_t) : sizeof(rsbac_inode_nr_t); + info_p->data_size = sizeof(rsbac_pax_flags_t); + info_p->max_age = 0; + pax_nr_fd_hash_bits = RSBAC_PAX_NR_FD_LIST_HASH_BITS; + tmperr = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &device_p->handles.pax, + info_p, + tmp_flags | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, &def_pax_fd_aci, + RSBAC_PAX_FD_NAME, kdev, + pax_nr_fd_hash_bits, + tmp_flags ? rsbac_list_hash_old_fd : rsbac_list_hash_fd, + RSBAC_PAX_OLD_FD_NAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "register_fd_lists(): registering PAX list %s for device %02u:%02u failed with error %s!\n", + RSBAC_PAX_FD_NAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, + tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + } +#endif + +#if defined(CONFIG_RSBAC_RES) + { + info_p->version = RSBAC_RES_FD_ACI_VERSION; + info_p->key = RSBAC_RES_FD_ACI_KEY; + info_p->desc_size = tmp_flags ? sizeof(rsbac_old_inode_nr_t) : sizeof(rsbac_inode_nr_t); + info_p->data_size = + sizeof(struct rsbac_res_fd_aci_t); + info_p->max_age = 0; + res_nr_fd_hash_bits = RSBAC_RES_NR_FD_LIST_HASH_BITS; + tmperr = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &device_p->handles.res, + info_p, + tmp_flags | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, &def_res_fd_aci, + RSBAC_RES_FD_NAME, kdev, + res_nr_fd_hash_bits, + tmp_flags ? rsbac_list_hash_old_fd : rsbac_list_hash_fd, + RSBAC_RES_OLD_FD_NAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "register_fd_lists(): registering RES list %s for device %02u:%02u failed with error %s!\n", + RSBAC_RES_FD_NAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, + tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + } +#endif + +#if defined(CONFIG_RSBAC_UDF) + { + struct rsbac_udf_fd_aci_t def_udf_fd_aci = + DEFAULT_UDF_FD_ACI; + /* register UDF lists */ + info_p->version = RSBAC_UDF_FD_ACI_VERSION; + info_p->key = RSBAC_UDF_FD_ACI_KEY; + info_p->desc_size = tmp_flags ? sizeof(rsbac_old_inode_nr_t) : sizeof(rsbac_inode_nr_t); + info_p->data_size = + sizeof(struct rsbac_udf_fd_aci_t); + info_p->max_age = 0; + udf_nr_fd_hash_bits = RSBAC_UDF_NR_FD_LIST_HASH_BITS; + tmperr = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &device_p->handles.udf, + info_p, + tmp_flags | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + &def_udf_fd_aci, + RSBAC_UDF_FD_NAME, kdev, + udf_nr_fd_hash_bits, + tmp_flags ? rsbac_list_hash_old_fd : rsbac_list_hash_fd, + NULL); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "register_fd_lists(): registering UDF list %s for device %02u:%02u failed with error %s!\n", + RSBAC_UDF_FD_NAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, + tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + } +#if defined(CONFIG_RSBAC_UDF_CACHE) + { + rsbac_udf_checked_t def_udf_checked_fd_aci = + DEFAULT_UDF_FD_CHECKED; + + info_p->version = RSBAC_UDF_CHECKED_FD_ACI_VERSION; + info_p->key = RSBAC_UDF_FD_ACI_KEY; +#ifdef CONFIG_RSBAC_UDF_PERSIST + info_p->desc_size = tmp_flags ? sizeof(rsbac_old_inode_nr_t) : sizeof(rsbac_inode_nr_t); +#else + info_p->desc_size = sizeof(rsbac_inode_nr_t); +#endif + info_p->data_size = sizeof(rsbac_udf_checked_t); + info_p->max_age = 0; + udf_checked_nr_fd_hash_bits = RSBAC_UDF_CHECKED_NR_FD_LIST_HASH_BITS; + tmperr = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &device_p->handles.udfc, + info_p, +#ifdef CONFIG_RSBAC_UDF_PERSIST + tmp_flags | +#endif + RSBAC_LIST_DEF_DATA | (RSBAC_MAJOR(kdev) ? RSBAC_LIST_OWN_SLAB : 0) | + RSBAC_LIST_AUTO_HASH_RESIZE | + RSBAC_LIST_NO_MAX, + NULL, + NULL, + &def_udf_checked_fd_aci, + RSBAC_UDF_CHECKED_FD_NAME, kdev, + udf_checked_nr_fd_hash_bits, +#ifdef CONFIG_RSBAC_UDF_PERSIST + tmp_flags ? rsbac_list_hash_old_fd : rsbac_list_hash_fd, +#else + rsbac_list_hash_fd, +#endif + NULL); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "register_fd_lists(): registering UDF checked list %s for device %02u:%02u failed with error %s!\n", + RSBAC_UDF_CHECKED_FD_NAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, + tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + } +#endif +#endif + + rsbac_kfree(name); + rsbac_kfree(info_p); + return err; +} + +/* aci_detach_fd_lists() */ +/* detach from fd lists for device */ + +static int aci_detach_fd_lists(struct rsbac_device_list_item_t *device_p) +{ + int err = 0; + int tmperr; + + if (!device_p) + return -RSBAC_EINVALIDPOINTER; + + /* detach all general lists */ + tmperr = rsbac_list_detach(&device_p->handles.gen, + RSBAC_GEN_FD_ACI_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "detach_fd_lists(): detaching from general list %s for device %02u:%02u failed with error %s!\n", + RSBAC_GEN_FD_NAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + +#if defined(CONFIG_RSBAC_MAC) + /* detach all MAC lists */ + tmperr = rsbac_list_detach(&device_p->handles.mac, + RSBAC_MAC_FD_ACI_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "detach_fd_lists(): detaching from MAC list %s for device %02u:%02u failed with error %s!\n", + RSBAC_MAC_FD_NAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif + +#if defined(CONFIG_RSBAC_DAZ) + /* detach all DAZ lists */ + tmperr = rsbac_list_detach(&device_p->handles.daz, + RSBAC_DAZ_FD_ACI_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "detach_fd_lists(): detaching from DAZ list %s for device %02u:%02u failed with error %s!\n", + RSBAC_DAZ_FD_NAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#if defined(CONFIG_RSBAC_DAZ_CACHE) + /* detach all DAZ scanned lists */ + tmperr = rsbac_list_detach(&device_p->handles.dazs, + RSBAC_DAZ_FD_ACI_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "detach_fd_lists(): detaching from DAZ scanned list %s for device %02u:%02u failed with error %s!\n", + RSBAC_DAZ_SCANNED_FD_NAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif +#endif + +#if defined(CONFIG_RSBAC_FF) + /* detach all FF lists */ + tmperr = rsbac_list_detach(&device_p->handles.ff, + RSBAC_FF_FD_ACI_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "detach_fd_lists(): detaching from FF list %s for device %02u:%02u failed with error %s!\n", + RSBAC_FF_FD_NAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif + +#if defined(CONFIG_RSBAC_RC) + /* detach all RC lists */ + tmperr = rsbac_list_detach(&device_p->handles.rc, + RSBAC_RC_FD_ACI_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "detach_fd_lists(): detaching from RC list %s for device %02u:%02u failed with error %s!\n", + RSBAC_RC_FD_NAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif + +#if defined(CONFIG_RSBAC_AUTH) + /* detach all AUTH lists */ + tmperr = rsbac_list_detach(&device_p->handles.auth, + RSBAC_AUTH_FD_ACI_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "detach_fd_lists(): detaching from AUTH list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_NAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif + +#if defined(CONFIG_RSBAC_CAP) + /* detach all CAP lists */ + tmperr = rsbac_list_detach(&device_p->handles.cap, + RSBAC_CAP_FD_ACI_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "detach_fd_lists(): detaching from CAP list %s for device %02u:%02u failed with error %s!\n", + RSBAC_CAP_FD_NAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif + +#if defined(CONFIG_RSBAC_PAX) + /* detach all PAX lists */ + tmperr = rsbac_list_detach(&device_p->handles.pax, + RSBAC_PAX_FD_ACI_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "detach_fd_lists(): detaching from PAX list %s for device %02u:%02u failed with error %s!\n", + RSBAC_PAX_FD_NAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif + +#if defined(CONFIG_RSBAC_RES) + /* detach all RES lists */ + tmperr = rsbac_list_detach(&device_p->handles.res, + RSBAC_RES_FD_ACI_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "detach_fd_lists(): detaching from RES list %s for device %02u:%02u failed with error %s!\n", + RSBAC_RES_FD_NAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif + +#if defined(CONFIG_RSBAC_UDF) + /* detach all UDF lists */ + tmperr = rsbac_list_detach(&device_p->handles.udf, + RSBAC_UDF_FD_ACI_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "detach_fd_lists(): detaching from UDF list %s for device %02u:%02u failed with error %s!\n", + RSBAC_UDF_FD_NAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#if defined(CONFIG_RSBAC_UDF_CACHE) + /* detach all UDF checked lists */ + tmperr = rsbac_list_detach(&device_p->handles.udfc, + RSBAC_UDF_FD_ACI_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "detach_fd_lists(): detaching from UDF checked list %s for device %02u:%02u failed with error %s!\n", + RSBAC_UDF_CHECKED_FD_NAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif +#endif + + return err; +} + +static void registration_error(int err, char *listname) +{ + if (err < 0) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_do_init(): Registering %s list failed with error %s\n", + listname, get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } +} + +#ifdef CONFIG_RSBAC_FD_CACHE +static int register_fd_cache_lists(struct rsbac_device_list_item_t *device_p) +{ + int err = 0; + struct rsbac_list_lol_info_t *list_info_p; + char * tmp; + + if (device_p->fd_cache_handle[SW_GEN]) { + rsbac_printk(KERN_WARNING "register_fd_cache_lists(): GEN list for device %02u:%02u already registered, refusing device!\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id)); + return -RSBAC_EINVALIDDEV; + } + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } + tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if (!tmp) { + rsbac_kfree(list_info_p); + return -ENOMEM; + } + rsbac_pr_debug(fdcache, "registering FD Cache lists for device %02u:%02u\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id)); + list_info_p->version = RSBAC_FD_CACHE_VERSION; + list_info_p->key = RSBAC_FD_CACHE_KEY; + list_info_p->desc_size = sizeof(rsbac_inode_nr_t); + list_info_p->data_size = 0; + list_info_p->subdesc_size = sizeof(rsbac_enum_t); + list_info_p->subdata_size = + sizeof(union rsbac_attribute_value_cache_t); + list_info_p->max_age = 0; + +#ifdef CONFIG_RSBAC_MPROTECT + sprintf(tmp, "%sGEN", RSBAC_FD_CACHE_NAME); + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &(device_p->fd_cache_handle[SW_GEN]), list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_OWN_SLAB | \ + RSBAC_LIST_AUTO_HASH_RESIZE | \ + RSBAC_LIST_NO_MAX_WARN, + NULL, + NULL, /* subcompare */ + NULL, NULL, /* get_conv */ + NULL, NULL, /* def data */ + tmp, + device_p->id, + RSBAC_LIST_MIN_MAX_HASH_BITS, + rsbac_list_hash_fd, + NULL); + if (err) { + char *tmp2; + + tmp2 = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp2) { + rsbac_printk(KERN_WARNING "register_fd_cache_lists(): registering GEN list %s for device %02u:%02u failed with error %s!\n", + tmp, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp2, err)); + rsbac_kfree(tmp2); + } + } else + rsbac_list_lol_max_items(device_p->fd_cache_handle[SW_GEN], + RSBAC_FD_CACHE_KEY, + CONFIG_RSBAC_FD_CACHE_MAX_ITEMS, A_none); +#endif + +#if defined(CONFIG_RSBAC_MAC) && defined(CONFIG_RSBAC_MAC_DEF_INHERIT) + sprintf(tmp, "%sMAC", RSBAC_FD_CACHE_NAME); + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &(device_p->fd_cache_handle[SW_MAC]), list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_OWN_SLAB | \ + RSBAC_LIST_AUTO_HASH_RESIZE | \ + RSBAC_LIST_NO_MAX_WARN, + NULL, + NULL, /* subcompare */ + NULL, NULL, /* get_conv */ + NULL, NULL, /* def data */ + tmp, + device_p->id, + RSBAC_LIST_MIN_MAX_HASH_BITS, + rsbac_list_hash_fd, + NULL); + if (err) { + char *tmp2; + + tmp2 = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp2) { + rsbac_printk(KERN_WARNING "register_fd_cache_lists(): registering MAC list %s for device %02u:%02u failed with error %s!\n", + tmp, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp2, err)); + rsbac_kfree(tmp2); + } + } else + rsbac_list_lol_max_items(device_p->fd_cache_handle[SW_MAC], + RSBAC_FD_CACHE_KEY, + CONFIG_RSBAC_FD_CACHE_MAX_ITEMS, A_none); +#endif +#if defined(CONFIG_RSBAC_FF) + sprintf(tmp, "%sFF", RSBAC_FD_CACHE_NAME); + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &(device_p->fd_cache_handle[SW_FF]), list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_OWN_SLAB | \ + RSBAC_LIST_AUTO_HASH_RESIZE | \ + RSBAC_LIST_NO_MAX_WARN, + NULL, + NULL, /* subcompare */ + NULL, NULL, /* get_conv */ + NULL, NULL, /* def data */ + tmp, + device_p->id, + RSBAC_LIST_MIN_MAX_HASH_BITS, + rsbac_list_hash_fd, + NULL); + if (err) { + char *tmp2; + + tmp2 = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp2) { + rsbac_printk(KERN_WARNING "register_fd_cache_lists(): registering FF list %s for device %02u:%02u failed with error %s!\n", + tmp, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp2, err)); + rsbac_kfree(tmp2); + } + } else + rsbac_list_lol_max_items(device_p->fd_cache_handle[SW_FF], + RSBAC_FD_CACHE_KEY, + CONFIG_RSBAC_FD_CACHE_MAX_ITEMS, A_none); +#endif +#if defined(CONFIG_RSBAC_RC) + sprintf(tmp, "%sRC", RSBAC_FD_CACHE_NAME); + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &(device_p->fd_cache_handle[SW_RC]), list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_OWN_SLAB | \ + RSBAC_LIST_AUTO_HASH_RESIZE | \ + RSBAC_LIST_NO_MAX_WARN, + NULL, + NULL, /* subcompare */ + NULL, NULL, /* get_conv */ + NULL, NULL, /* def data */ + tmp, + device_p->id, + RSBAC_LIST_MIN_MAX_HASH_BITS, + rsbac_list_hash_fd, + NULL); + if (err) { + char *tmp2; + + tmp2 = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp2) { + rsbac_printk(KERN_WARNING "register_fd_cache_lists(): registering RC list %s for device %02u:%02u failed with error %s!\n", + tmp, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp2, err)); + rsbac_kfree(tmp2); + } + } else + rsbac_list_lol_max_items(device_p->fd_cache_handle[SW_RC], + RSBAC_FD_CACHE_KEY, + CONFIG_RSBAC_FD_CACHE_MAX_ITEMS, A_none); +#endif +#if defined(CONFIG_RSBAC_DAZ) + sprintf(tmp, "%sDAZ", RSBAC_FD_CACHE_NAME); + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &(device_p->fd_cache_handle[SW_DAZ]), list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_OWN_SLAB | \ + RSBAC_LIST_AUTO_HASH_RESIZE | \ + RSBAC_LIST_NO_MAX_WARN, + NULL, + NULL, /* subcompare */ + NULL, NULL, /* get_conv */ + NULL, NULL, /* def data */ + tmp, + device_p->id, + RSBAC_LIST_MIN_MAX_HASH_BITS, + rsbac_list_hash_fd, + NULL); + if (err) { + char *tmp2; + + tmp2 = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp2) { + rsbac_printk(KERN_WARNING "register_fd_cache_lists(): registering DAZ list %s for device %02u:%02u failed with error %s!\n", + tmp, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp2, err)); + rsbac_kfree(tmp2); + } + } else + rsbac_list_lol_max_items(device_p->fd_cache_handle[SW_DAZ], + RSBAC_FD_CACHE_KEY, + CONFIG_RSBAC_FD_CACHE_MAX_ITEMS, + A_none); +#endif +#if defined(CONFIG_RSBAC_UDF) + sprintf(tmp, "%sUDF", RSBAC_FD_CACHE_NAME); + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &(device_p->fd_cache_handle[SW_UDF]), list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_OWN_SLAB | \ + RSBAC_LIST_AUTO_HASH_RESIZE | \ + RSBAC_LIST_NO_MAX_WARN, + NULL, + NULL, /* subcompare */ + NULL, NULL, /* get_conv */ + NULL, NULL, /* def data */ + tmp, + device_p->id, + RSBAC_LIST_MIN_MAX_HASH_BITS, + rsbac_list_hash_fd, + NULL); + if (err) { + char *tmp2; + + tmp2 = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp2) { + rsbac_printk(KERN_WARNING "register_fd_cache_lists(): registering UDF list %s for device %02u:%02u failed with error %s!\n", + tmp, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp2, err)); + rsbac_kfree(tmp2); + } + } else + rsbac_list_lol_max_items(device_p->fd_cache_handle[SW_UDF], + RSBAC_FD_CACHE_KEY, + CONFIG_RSBAC_FD_CACHE_MAX_ITEMS, + A_none); +#endif + + rsbac_kfree(list_info_p); + rsbac_kfree(tmp); + return err; +} + +static int unregister_fd_cache_lists(struct rsbac_device_list_item_t *device_p) +{ + u_int i; + int err; + + rsbac_pr_debug(fdcache, "unregistering FD Cache lists for device %02u:%02u\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id)); + for (i = 0; i < SW_NONE; i++) { + if (device_p->fd_cache_handle[i]) { + err = rsbac_list_lol_detach(&(device_p->fd_cache_handle[i]), RSBAC_FD_CACHE_KEY); + device_p->fd_cache_handle[i] = NULL; + if (err) { + char *tmp2; + + tmp2 = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp2) { + rsbac_printk(KERN_WARNING "unregister_fd_cache_lists(): unregistering list for device %02u:%02u, module %u failed with error %s!\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + i, + get_error_name(tmp2, err)); + rsbac_kfree(tmp2); + } + } + } + } + return 0; +} +#endif + + +/* Create a device item without adding to list. No locking needed. */ +static struct rsbac_device_list_item_t +*create_device_item(struct vfsmount *vfsmount_p) +{ + struct rsbac_device_list_item_t *new_item_p; + + if (!vfsmount_p) + return NULL; + /* allocate memory for new device, return NULL, if failed */ + if (!(new_item_p = rsbac_smalloc_clear_unlocked(device_item_slab))) + return NULL; + + new_item_p->id = vfsmount_p->mnt_sb->s_dev; + new_item_p->vfsmount_p = vfsmount_p; + new_item_p->mount_count = 1; + new_item_p->persist = FALSE; + + return new_item_p; +} + +/* Add an existing device item to list. Locking needed. */ +static struct rsbac_device_list_item_t +*add_device_item(struct rsbac_device_list_item_t *device_p) +{ + struct rsbac_device_list_head_t * new_p; + struct rsbac_device_list_head_t * old_p; + u_int hash; + + if (!device_p) + return NULL; + + hash = device_hash(device_p->id); + spin_lock(&device_list_locks[hash]); + old_p = device_head_p[hash]; + new_p = rsbac_kmalloc(sizeof(*new_p)); + *new_p = *old_p; + /* add new device to device list */ + if (!new_p->head) { /* first device */ + new_p->head = device_p; + new_p->tail = device_p; + new_p->curr = device_p; + new_p->count = 1; + device_p->prev = NULL; + device_p->next = NULL; + } else { /* there is another device -> hang to tail */ + device_p->prev = new_p->tail; + device_p->next = NULL; + new_p->tail->next = device_p; + new_p->tail = device_p; + new_p->curr = device_p; + new_p->count++; + } + rcu_assign_pointer(device_head_p[hash], new_p); + spin_unlock(&device_list_locks[hash]); + synchronize_srcu(&device_list_srcu[hash]); + rsbac_kfree(old_p); + return device_p; +} + +/************************************************************************** */ +/* The remove_item() functions remove an item from the list. If this item */ +/* is head, tail or curr, these pointers are set accordingly. */ +/* To speed up removing several subsequent items, curr is set to the next */ +/* item, if possible. */ +/* If the item is not found, nothing is done. */ + +static void clear_device_item(struct rsbac_device_list_item_t *item_p) +{ + if (!item_p) + return; + + /* dput() rsbac_dir_dentry_p, if set */ + if (item_p->rsbac_dir_dentry_p) { + dput(item_p->rsbac_dir_dentry_p); + } + + /* OK, lets remove the device item itself */ + rsbac_sfree(device_item_slab, item_p); +} + +/* remove_device_item unlocks device_list_locks[hash]! */ +static void remove_device_item(kdev_t kdev) +{ + struct rsbac_device_list_item_t *item_p; + u_int hash; + + hash = device_hash(kdev); + if ((item_p = lookup_device_locked(kdev, hash))) { + struct rsbac_device_list_head_t * new_p; + struct rsbac_device_list_head_t * old_p; + + old_p = device_head_p[hash]; + new_p = rsbac_kmalloc(sizeof(*new_p)); + if (!new_p) { + /* Ouch! */ + spin_unlock(&device_list_locks[hash]); + return; + } + *new_p = *old_p; + if (new_p->head == item_p) { /* item is head */ + if (new_p->tail == item_p) { /* item is head and tail = only item -> list will be empty */ + new_p->head = NULL; + new_p->tail = NULL; + } else { /* item is head, but not tail -> next item becomes head */ + item_p->next->prev = NULL; + new_p->head = item_p->next; + } + } else { /* item is not head */ + if (new_p->tail == item_p) { /*item is not head, but tail -> previous item becomes tail */ + item_p->prev->next = NULL; + new_p->tail = item_p->prev; + } else { /* item is neither head nor tail -> item is cut out */ + item_p->prev->next = item_p->next; + item_p->next->prev = item_p->prev; + } + } + + /* curr is no longer valid -> reset. */ + new_p->curr = NULL; + /* adjust counter */ + new_p->count--; + rcu_assign_pointer(device_head_p[hash], new_p); + spin_unlock(&device_list_locks[hash]); + synchronize_srcu(&device_list_srcu[hash]); + rsbac_kfree(old_p); + } else { + spin_unlock(&device_list_locks[hash]); + } +} + +/**************************************************/ +/* Externally visible help functions */ +/**************************************************/ + +/* helper, copied from open.d/do_truncate() */ +static int rsbac_clear_file(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + int error; + struct iattr newattrs; + + inode_lock(inode); + newattrs.ia_size = 0; + newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; + error = notify_change(dentry, &newattrs, NULL); + inode_unlock(inode); + return error; +} + +#if defined(CONFIG_RSBAC_REG) +EXPORT_SYMBOL(rsbac_check_device); +#endif + +int rsbac_check_device(kdev_t kdev) +{ + struct rsbac_device_list_item_t *device_p; + u_int hash; + int srcu_idx; + + hash = device_hash(kdev); + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(kdev, hash); + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + if (device_p) + return 0; + else + return -RSBAC_ENOTFOUND; +} + +#if defined(CONFIG_RSBAC_REG) +EXPORT_SYMBOL(rsbac_get_vfsmount); +#endif +struct vfsmount *rsbac_get_vfsmount(kdev_t kdev) +{ + struct rsbac_device_list_item_t *device_p; + struct vfsmount *vfsmount_p; + u_int hash; + int srcu_idx; + + if (RSBAC_IS_AUTO_DEV(kdev)) + return NULL; + + hash = device_hash(kdev); + /* get super_block-pointer */ + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(kdev, hash); + if (!device_p) { + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_get_vfsmount(): unknown device %02u:%02u\n", + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev)); + return NULL; + } + vfsmount_p = device_p->vfsmount_p; + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + return vfsmount_p; +} + +#if defined(CONFIG_RSBAC_REG) +EXPORT_SYMBOL(rsbac_read_open); +#endif +int rsbac_read_open(char *name, struct file **file_pi, kdev_t kdev) +{ + struct dentry *dir_dentry_p; + struct dentry *file_dentry_p; + struct file *file_p; + struct path path; + int err = 0; + struct vfsmount *vfsmount_p; + + if (!name || !file_pi) { + rsbac_pr_debug(ds, "called with NULL pointer!"); + return -RSBAC_EINVALIDPOINTER; + } + + vfsmount_p = rsbac_get_vfsmount(kdev); + if (!vfsmount_p) { + rsbac_printk(KERN_WARNING "rsbac_read_open(): invalid device %02u:%02u\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + return -RSBAC_EINVALIDDEV; + } + + /* lookup dentry of ACI_PATH on root device, lock is released there */ + if ((err = + lookup_aci_path_dentry(vfsmount_p, &dir_dentry_p, FALSE, kdev))) { + goto out; + } + + inode_lock(dir_dentry_p->d_inode); + /* open file for reading - this must be done 'by hand', because */ + /* standard system calls are now extended by rsbac decision calls. */ + file_dentry_p = + rsbac_lookup_one_len(name, dir_dentry_p, strlen(name)); + inode_unlock(dir_dentry_p->d_inode); + + if (!file_dentry_p || IS_ERR(file_dentry_p)) { /* error in lookup */ + err = -RSBAC_EREADFAILED; + goto out; + } + if (!file_dentry_p->d_inode || !file_dentry_p->d_inode->i_size) { + /* file not found or empty: trying backup */ + char *bname; + int name_len = strlen(name); + + dput(file_dentry_p); + bname = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (!bname) { + err = -RSBAC_ENOMEM; + goto out; + } + + strcpy(bname, name); + bname[name_len] = 'b'; + name_len++; + bname[name_len] = (char) 0; + rsbac_pr_debug(ds, "could not lookup file %s, trying backup %s\n", + name, bname); + + inode_lock(dir_dentry_p->d_inode); + file_dentry_p = + rsbac_lookup_one_len(bname, dir_dentry_p, + strlen(bname)); + inode_unlock(dir_dentry_p->d_inode); + rsbac_kfree(bname); + if (!file_dentry_p || IS_ERR(file_dentry_p)) { /* error in lookup */ + return -RSBAC_EREADFAILED; + } + if (!file_dentry_p->d_inode || !file_dentry_p->d_inode->i_size) { + /* backup file also not found: return error */ + rsbac_pr_debug(ds, "backup file %sb not found or empty\n", + name); + dput(file_dentry_p); + err = -RSBAC_ENOTFOUND; + goto out; + } + } + if (!(S_ISREG(file_dentry_p->d_inode->i_mode))) { /* this is not a file! -> error! */ + rsbac_printk(KERN_WARNING "rsbac_read_open(): expected file is not a file!\n"); + inode_unlock(dir_dentry_p->d_inode); + dput(file_dentry_p); + err = -RSBAC_EREADFAILED; + goto out; + } + + /* Now we fill the file structure and */ + /* if there is an open func for this file, use it, otherwise ignore */ + path.dentry = file_dentry_p; + path.mnt = mntget(vfsmount_p); + file_p = alloc_file(&path, FMODE_READ, path.dentry->d_inode->i_fop); + + if (!file_p) { + path_put(&path); + rsbac_printk(KERN_WARNING "rsbac_read_open(): could not open file '%s'!\n", + name); + err = -RSBAC_EREADFAILED; + goto out; + } + + /* if there is no read func, we get a problem -> error */ + if (!file_p->f_op) { + rsbac_printk(KERN_WARNING "rsbac_read_open(): no f_op for file '%s'!\n", + name); + path_put(&path); + err = -RSBAC_EREADFAILED; + goto out; + } + if (!file_p->f_op->read && !file_p->f_op->read_iter) { + rsbac_printk(KERN_WARNING "rsbac_read_open(): no read function for file '%s'!\n", + name); + path_put(&path); + err = -RSBAC_EREADFAILED; + goto out; + } + + *file_pi = file_p; + + if (file_p->f_op->open) + err = file_p->f_path.dentry->d_inode->i_fop->open(path.dentry->d_inode, file_p); + +out: + return err; +} + +#ifndef check_parent +#define check_parent(dir, dentry) \ + ((dir) == (dentry)->d_parent && !list_empty(&dentry->d_bucket)) +#endif + +#if defined(CONFIG_RSBAC_REG) +EXPORT_SYMBOL(rsbac_write_open); +#endif +int rsbac_write_open(char *name, struct file **file_pi, kdev_t kdev) +{ + struct dentry *dir_dentry_p = NULL; + struct dentry *ldir_dentry_p = NULL; + struct dentry *file_dentry_p = NULL; + struct file * file_p; + struct path path; + int err = 0; + int tmperr = 0; + struct vfsmount *vfsmount_p; + + if (!file_pi || !name) { + rsbac_pr_debug(write, "called with NULL pointer!\n"); + return -RSBAC_EINVALIDPOINTER; + } + + /* get super_block-pointer */ + vfsmount_p = rsbac_get_vfsmount(kdev); + if (!vfsmount_p) { + rsbac_printk(KERN_WARNING "rsbac_write_open(): invalid device %02u:%02u\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + return -RSBAC_EINVALIDDEV; + } + if (!rsbac_writable(vfsmount_p->mnt_sb)) { + rsbac_pr_debug(write, "called for non-writable device\n"); + return -RSBAC_ENOTWRITABLE; + } + + err = mnt_want_write(vfsmount_p); + if (err) + return err; + + /* lookup dentry of ACI_PATH on this device (create, if needed and possible), + * returns errorcode, if failed */ + if ((tmperr = lookup_aci_path_dentry(vfsmount_p, &dir_dentry_p, TRUE, + kdev))) { + err = tmperr; + goto out; + } + + inode_lock(dir_dentry_p->d_inode); + /* open file for reading - this must be done 'by hand', because */ + /* standard system calls are now extended by rsbac decision calls. */ + file_dentry_p = + rsbac_lookup_one_len(name, dir_dentry_p, strlen(name)); + inode_unlock(dir_dentry_p->d_inode); + if (!file_dentry_p || IS_ERR(file_dentry_p)) { + rsbac_pr_debug(write, "lookup of %s returned error %li\n", + name, PTR_ERR(file_dentry_p)); + err = -RSBAC_EWRITEFAILED; + goto out; + } +#if 1 + if (file_dentry_p->d_inode) { /* file was found: try to rename it as backup file */ + if ( !dir_dentry_p->d_inode->i_op + || !dir_dentry_p->d_inode->i_op->rename + ) { + rsbac_printk(KERN_WARNING "rsbac_write_open(): File system supports no rename - no backup of %s made!", + name); + } else { + char *bname; + int name_len = strlen(name); + struct dentry *new_file_dentry_p = NULL; + struct dentry *old_dir_p, *new_dir_p; + + bname = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (!bname) { + err = -RSBAC_ENOMEM; + goto out_dput; + } + strcpy(bname, name); + bname[name_len] = 'b'; + bname[name_len + 1] = (char) 0; + inode_lock(dir_dentry_p->d_inode); + new_file_dentry_p = + rsbac_lookup_one_len(bname, dir_dentry_p, + strlen(bname)); + inode_unlock(dir_dentry_p->d_inode); + if (new_file_dentry_p + && !IS_ERR(new_file_dentry_p)) { + /* lock parent == rsbac-dir for rest of rename */ + old_dir_p = dget(file_dentry_p->d_parent); + new_dir_p = + dget(new_file_dentry_p->d_parent); + double_lock(new_dir_p, old_dir_p); + dquot_initialize(old_dir_p->d_inode); + dquot_initialize(new_dir_p->d_inode); + /* try to rename file in rsbac dir */ + /* rsbac_pr_debug(write, "calling rename function\n"); */ + lock_two_nondirectories(file_dentry_p->d_inode, new_file_dentry_p->d_inode); + err = dir_dentry_p->d_inode->i_op->rename(old_dir_p->d_inode, + file_dentry_p, + new_dir_p->d_inode, + new_file_dentry_p, + 0); + unlock_two_nondirectories(file_dentry_p->d_inode, new_file_dentry_p->d_inode); + /* unlock dir (dputs both dentries) */ + double_unlock(new_dir_p, old_dir_p); + if (err) { + rsbac_printk(KERN_WARNING "rsbac_write_open(): could not rename %s to %s on dev %02u:%02u, error %i - no backup!\n", + name, bname, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + err); + } else { + /* The following d_move() should become unconditional */ + if (! + (vfsmount_p->mnt_sb->s_type-> + fs_flags + & FS_RENAME_DOES_D_MOVE + )) + d_move(file_dentry_p, + new_file_dentry_p); + fsnotify_create(old_dir_p->d_inode, + new_file_dentry_p); + } + dput(new_file_dentry_p); + dput(file_dentry_p); + /* re-init dentry structure */ + inode_lock(dir_dentry_p->d_inode); + file_dentry_p = + rsbac_lookup_one_len(name, + dir_dentry_p, + strlen(name)); + inode_unlock(dir_dentry_p->d_inode); + if (!file_dentry_p + || IS_ERR(file_dentry_p)) { + rsbac_pr_debug(write, "relookup of %s " + "returned error %li\n", + name, + PTR_ERR(file_dentry_p)); + err = -RSBAC_EWRITEFAILED; + goto out; + } + if (file_dentry_p->d_inode) { + rsbac_printk(KERN_WARNING "rsbac_write_open(): relookup of %s returned dentry with existing inode %li, trying unlink\n", + name, + file_dentry_p-> + d_inode->i_ino); + /* file was found: try to delete it */ + if (!dir_dentry_p->d_inode->i_op + || !dir_dentry_p->d_inode-> + i_op->unlink) { + rsbac_printk(KERN_WARNING "rsbac_write_open(): File system supports no unlink - %s not deleted!", + name); + rsbac_kfree(bname); + err = -RSBAC_EWRITEFAILED; + goto out_dput; + } else { + old_dir_p = + lock_parent + (file_dentry_p); + dquot_initialize(old_dir_p->d_inode); + err = -ENOENT; + err = + dir_dentry_p-> + d_inode->i_op-> + unlink + (old_dir_p-> + d_inode, + file_dentry_p); + /* unlock parent dir */ + unlock_dir(old_dir_p); + /* free file dentry */ + dput(file_dentry_p); + if (err) { + rsbac_printk + (KERN_WARNING + "rsbac_write_open(): could not unlink %s on dev %02u:%02u, error %i!\n", + name, + RSBAC_MAJOR + (kdev), + RSBAC_MINOR + (kdev), err); + } + /* re-init dentry structure */ + inode_lock(dir_dentry_p->d_inode); + file_dentry_p = + rsbac_lookup_one_len + (name, dir_dentry_p, + strlen(name)); + inode_unlock(dir_dentry_p->d_inode); + if (!file_dentry_p + || + IS_ERR(file_dentry_p)) { + rsbac_pr_debug(write, "relookup of %s returned error %li\n", + name, + PTR_ERR(file_dentry_p)); + rsbac_kfree(bname); + err = + -RSBAC_EWRITEFAILED; + goto out; + } + if (file_dentry_p->d_inode) { + rsbac_printk + (KERN_WARNING + "rsbac_write_open(): relookup of %s returned dentry with existing inode %li\n", + name, + file_dentry_p-> + d_inode-> + i_ino); + rsbac_kfree(bname); + err = + -RSBAC_EWRITEFAILED; + goto out_dput; + } + } + } + } else { + rsbac_printk(KERN_WARNING "rsbac_write_open(): rsbac_lookup_(dentry|one) for backup file %s on dev %02u:%02u failed with error %li - no backup!\n", + bname, RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + PTR_ERR(new_file_dentry_p)); + } + rsbac_kfree(bname); + } + } +#endif /* backup part */ + + if (!file_dentry_p->d_inode) { + /* file not found or renamed away: try to create a new one */ + if (!dir_dentry_p->d_inode->i_op + || !dir_dentry_p->d_inode->i_op->create) { + rsbac_printk(KERN_WARNING "%s\n", + "rsbac_write_open(): File system supports no create!"); + err = -RSBAC_EWRITEFAILED; + goto out_dput; + } + + /* lock parent == rsbac-dir for create */ + ldir_dentry_p = lock_parent(file_dentry_p); + if (IS_ERR(ldir_dentry_p)) { + rsbac_pr_debug(write, "lock_parent of %s returned " + "error %li\n", name, + PTR_ERR(ldir_dentry_p)); + err = -RSBAC_EWRITEFAILED; + goto out_dput; + } + /* try to create file in rsbac dir */ + /* rsbac_pr_debug(write, "calling create function\n"); */ + dquot_initialize(ldir_dentry_p->d_inode); + err = + dir_dentry_p->d_inode->i_op->create(ldir_dentry_p-> + d_inode, + file_dentry_p, + RSBAC_ACI_FILE_MODE, + NULL); + unlock_dir(ldir_dentry_p); + + if (err) { + goto out_dput; + } + /* create was successful */ + } + + if (!(S_ISREG(file_dentry_p->d_inode->i_mode))) { /* this is not a file! -> error! */ + rsbac_printk(KERN_WARNING "rsbac_write_open(): expected file is not a file, mode is %o!\n", + file_dentry_p->d_inode->i_mode); + err = -RSBAC_EWRITEFAILED; + goto out_dput; + } + /* Without a write function we get into troubles -> error */ + if (!file_dentry_p->d_inode->i_fop) { + rsbac_printk(KERN_WARNING "rsbac_write_open(): file f_op missing!\n"); + err = -RSBAC_EWRITEFAILED; + goto out_dput; + } + if (!file_dentry_p->d_inode->i_fop->write && !file_dentry_p->d_inode->i_fop->write_iter) { + rsbac_printk(KERN_WARNING "rsbac_write_open(): file write function missing!\n"); + err = -RSBAC_EWRITEFAILED; + goto out_dput; + } + + /* alloc_file() will call mnt_want_write */ + mnt_drop_write(vfsmount_p); + + if ((tmperr = get_write_access(file_dentry_p->d_inode))) { + rsbac_printk(KERN_WARNING "rsbac_write_open(): could not get write access on file!\n"); + dput(file_dentry_p); + return -RSBAC_EWRITEFAILED; + } + + /* Now we fill the file structure, file_take_write, mnt_want_write */ + path.dentry = file_dentry_p; + path.mnt = mntget(vfsmount_p); + file_p = alloc_file(&path, FMODE_WRITE, path.dentry->d_inode->i_fop); + if (!file_p) { + rsbac_printk(KERN_WARNING "rsbac_write_open(): could not init file!\n"); + put_write_access(file_p->f_path.dentry->d_inode); + path_put(&path); + return -RSBAC_EWRITEFAILED; + } + + /* truncating */ + if (rsbac_clear_file(file_dentry_p)) { + if (file_p->f_op->release) + file_p->f_op->release(file_dentry_p->d_inode, + file_p); + rsbac_printk(KERN_WARNING "rsbac_write_open(): could not truncate!\n"); + err = -RSBAC_EWRITEFAILED; + put_write_access(file_p->f_path.dentry->d_inode); + goto out_dput; + } + /* set synchronous mode for this file */ + file_p->f_flags |= O_SYNC; + *file_pi = file_p; + +out: + if (err) + mnt_drop_write(vfsmount_p); + return err; + +out_dput: + dput(file_dentry_p); + goto out; +} + + +#if defined(CONFIG_RSBAC_REG) +EXPORT_SYMBOL(rsbac_read_close); +#endif +void rsbac_read_close(struct file *file_p) +{ + /* cleanup copied from __fput */ + if (file_p->f_op && file_p->f_op->release) + file_p->f_op->release(file_p->f_path.dentry->d_inode, file_p); + path_put(&file_p->f_path); + put_filp(file_p); +} + +#if defined(CONFIG_RSBAC_REG) +EXPORT_SYMBOL(rsbac_write_close); +#endif +void rsbac_write_close(struct file *file_p) +{ + put_write_access(file_p->f_path.dentry->d_inode); +// mnt_drop_write(file_p->f_path.mnt); + rsbac_read_close(file_p); +} + +#if defined(CONFIG_RSBAC_REG) +EXPORT_SYMBOL(rsbac_lookup_full_path); +#endif +int rsbac_lookup_full_path(struct dentry *dentry_p, char path[], int maxlen, int pseudonymize) +{ + int len = 0; + char *i_path; + int tmplen = 0; +#ifdef CONFIG_RSBAC_LOG_PSEUDO_FS + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val; +#endif + int srcu_idx; + + if (!dentry_p || !path) + return -RSBAC_EINVALIDPOINTER; + if (maxlen <= 0) + return -RSBAC_EINVALIDVALUE; + i_path = rsbac_kmalloc(maxlen + RSBAC_MAXNAMELEN); + if (!i_path) + return -RSBAC_ENOMEM; + + path[0] = 0; + + while (dentry_p && (len < maxlen) && dentry_p->d_name.len + && dentry_p->d_name.name) { +#ifdef CONFIG_RSBAC_LOG_PSEUDO_FS + if ( pseudonymize + && dentry_p->d_inode + && dentry_p->d_parent + && dentry_p->d_parent->d_inode + && (i_tid.user = __kuid_val(dentry_p->d_inode->i_uid)) + && (__kuid_val(dentry_p->d_inode->i_uid) != + __kuid_val(dentry_p->d_parent->d_inode->i_uid)) + && !rsbac_get_attr(SW_GEN, T_USER, i_tid, A_pseudo, + &i_attr_val, FALSE) + && i_attr_val.pseudo) { /* Max len of 32 Bit value in decimal print is 11 */ + if ((maxlen - len) < 12) { + rsbac_kfree(i_path); + return len; + } + tmplen = + snprintf(i_path, 11, "%u", i_attr_val.pseudo); + } else +#endif + { + tmplen = dentry_p->d_name.len; + if ((tmplen + 1) > (maxlen - len)) { + rsbac_kfree(i_path); + return len; + } + strncpy(i_path, dentry_p->d_name.name, tmplen); + } + /* Skip double / on multi mounts. + * Last / is appended at the end of the function */ + if((i_path[tmplen-1] != '/') && (tmplen != 1)) { + if(len && (i_path[tmplen-1] != '/')) { + i_path[tmplen] = '/'; + tmplen++; + } + i_path[tmplen]=0; + strcat(i_path, path); + strcpy(path, i_path); + len += tmplen; + } + if (dentry_p->d_parent && (dentry_p->d_parent != dentry_p) + && (dentry_p->d_sb->s_root != dentry_p) + ) + dentry_p = dentry_p->d_parent; + else { + struct rsbac_device_list_item_t *device_p; + u_int hash; + + if (dentry_p->d_sb->s_dev == rsbac_root_dev) { + break; + } + hash = device_hash(dentry_p->d_sb->s_dev); + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(dentry_p->d_sb->s_dev, hash); + if ( device_p + && device_p->vfsmount_p + && real_mount(device_p->vfsmount_p)->mnt_mountpoint + && real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_sb + && (real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_sb->s_dev != dentry_p->d_sb->s_dev) + ) { + dentry_p = real_mount(device_p->vfsmount_p)->mnt_mountpoint; + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + } else { + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + break; + } + } + } + + i_path[tmplen]=0; + strcat(i_path, path); + strcpy(path, i_path); + + rsbac_kfree(i_path); + return len; +} + +/************************************************* */ +/* proc fs functions */ +/************************************************* */ + +#if defined(CONFIG_RSBAC_PROC) +static int +devices_proc_show(struct seq_file *m, void *v) +{ + struct rsbac_device_list_head_t *head_p; + struct rsbac_device_list_item_t *device_p; + u_int count = 0; + u_int i; + int srcu_idx; + + if (!rsbac_initialized) + return -ENOSYS; + + for (i = 0; i < RSBAC_NR_DEVICE_LISTS; i++) + count += device_head_p[i]->count; + seq_printf(m, "%u RSBAC Devices\n---------------\nHash size is %u\n", + count, RSBAC_NR_DEVICE_LISTS); + + for (i = 0; i < RSBAC_NR_DEVICE_LISTS; i++) { + srcu_idx = srcu_read_lock(&device_list_srcu[i]); + head_p = srcu_dereference(device_head_p[i], &device_list_srcu[i]); + for (device_p = srcu_dereference(head_p->head, &device_list_srcu[i]); device_p; + device_p = srcu_dereference(device_p->next, &device_list_srcu[i])) { + if (device_p->vfsmount_p && device_p->vfsmount_p->mnt_sb + && device_p->vfsmount_p->mnt_sb->s_type + && device_p->vfsmount_p->mnt_sb->s_type->name + && real_mount(device_p->vfsmount_p)->mnt_mountpoint) { + seq_printf(m, + "%02u:%02u mount_count %u, fs_type %s (%lx), mountpoint %s, parent %02u:%02u, persist %u\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + device_p->mount_count, + device_p->vfsmount_p->mnt_sb->s_type->name, + device_p->vfsmount_p->mnt_sb->s_magic, + real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_name.name, + RSBAC_MAJOR(real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_sb->s_dev), + RSBAC_MINOR(real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_sb->s_dev), + device_p->persist); + } else + seq_printf(m, + "%02u:%02u mount_count %u, no vfsmount_p, persist %u\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + device_p->mount_count, + device_p->persist); + } + srcu_read_unlock(&device_list_srcu[i], srcu_idx); + } + return 0; +} + +static int devices_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, devices_proc_show, NULL); +} + +static const struct file_operations devices_proc_fops = { + .owner = THIS_MODULE, + .open = devices_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *devices; + +static int +stats_proc_show(struct seq_file *m, void *v) +{ + struct rsbac_device_list_head_t *head_p; + struct rsbac_device_list_item_t *device_p; + long fd_count, fd_dev_count; + u_long fd_sum = 0; + u_long sum = 0; + u_long total_sum = 0; + long tmp_count; + int i; + int srcu_idx; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_initialized) + return -ENOSYS; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + seq_printf(m, "RSBAC Status\n------------\nRSBAC Version: %s, API min: %s, API max: %s\nCompiled Modules:%s\n", + RSBAC_VERSION, RSBAC_API_MIN_VERSION, RSBAC_API_MAX_VERSION, compiled_modules); +#ifdef CONFIG_RSBAC_SWITCH + { + char *active_modules; + + active_modules = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (active_modules) { + active_modules[0] = (char) 0; +#ifdef CONFIG_RSBAC_REG + strcat(active_modules, " REG"); +#endif +#ifdef CONFIG_RSBAC_MAC +#ifdef CONFIG_RSBAC_SWITCH_MAC + if (rsbac_switch_mac) +#endif +#ifdef CONFIG_RSBAC_MAC_LIGHT + strcat(active_modules, " MAC-L"); +#else + strcat(active_modules, " MAC"); +#endif +#endif +#ifdef CONFIG_RSBAC_DAZ +#ifdef CONFIG_RSBAC_SWITCH_DAZ + if (rsbac_switch_daz) +#endif + strcat(active_modules, " DAZ"); +#endif +#ifdef CONFIG_RSBAC_FF +#ifdef CONFIG_RSBAC_SWITCH_FF + if (rsbac_switch_ff) +#endif + strcat(active_modules, " FF"); +#endif +#ifdef CONFIG_RSBAC_RC +#ifdef CONFIG_RSBAC_SWITCH_RC + if (rsbac_switch_rc) +#endif + strcat(active_modules, " RC"); +#endif +#ifdef CONFIG_RSBAC_AUTH +#ifdef CONFIG_RSBAC_SWITCH_AUTH + if (rsbac_switch_auth) +#endif + strcat(active_modules, " AUTH"); +#endif +#ifdef CONFIG_RSBAC_ACL +#ifdef CONFIG_RSBAC_SWITCH_ACL + if (rsbac_switch_acl) +#endif + strcat(active_modules, " ACL"); +#endif +#ifdef CONFIG_RSBAC_CAP +#ifdef CONFIG_RSBAC_SWITCH_CAP + if (rsbac_switch_cap) +#endif + strcat(active_modules, " CAP"); +#endif +#ifdef CONFIG_RSBAC_JAIL +#ifdef CONFIG_RSBAC_SWITCH_JAIL + if (rsbac_switch_jail) +#endif + strcat(active_modules, " JAIL"); +#endif +#ifdef CONFIG_RSBAC_RES +#ifdef CONFIG_RSBAC_SWITCH_RES + if (rsbac_switch_res) +#endif + strcat(active_modules, " RES"); +#endif +#ifdef CONFIG_RSBAC_PAX +#ifdef CONFIG_RSBAC_SWITCH_PAX + if (rsbac_switch_pax) +#endif + strcat(active_modules, " PAX"); +#endif +#ifdef CONFIG_RSBAC_UDF +#ifdef CONFIG_RSBAC_SWITCH_UDF + if (rsbac_switch_udf) +#endif + strcat(active_modules, " UDF"); +#endif + seq_printf(m, "Active Modules: %s\n", + active_modules); + rsbac_kfree(active_modules); + } + } +#else + seq_printf(m, "All modules active (no switching)\n"); +#endif + +#ifdef CONFIG_RSBAC_SOFTMODE + if (rsbac_softmode) { +#ifdef CONFIG_RSBAC_SOFTMODE_IND + seq_printf(m, "Global softmode is enabled\n"); +#else + seq_printf(m, "Softmode is enabled\n"); +#endif + } else { +#ifdef CONFIG_RSBAC_SOFTMODE_IND + seq_printf(m, "Global softmode is disabled\n"); +#else + seq_printf(m, "Softmode is disabled\n"); +#endif + } +#ifdef CONFIG_RSBAC_SOFTMODE_IND + { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + seq_printf(m, + "Individual softmode enabled for:"); + for (i = 0; i <= RSBAC_MAX_MOD; i++) + if (rsbac_ind_softmode[i]) + seq_printf(m, " %s", + get_switch_target_name + (tmp, i)); + rsbac_kfree(tmp); + seq_printf(m, "\n"); + } + } +#endif +#endif + + seq_printf(m, "\n"); + + tmp_count = 0; + for (i = 0; i < RSBAC_NR_DEVICE_LISTS; i++) { + srcu_idx = srcu_read_lock(&device_list_srcu[i]); + head_p = srcu_dereference(device_head_p[i], &device_list_srcu[i]); + device_p = srcu_dereference(head_p->head, &device_list_srcu[i]); + if (device_p) + seq_printf(m, "FD items:\n"); + while (device_p) { + fd_dev_count = 0; + fd_count = rsbac_list_count(device_p->handles.gen); + if (fd_count >= 0) { + seq_printf(m, "Dev %02u:%02u: %lu GEN", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + fd_count); + fd_dev_count += fd_count; + } + +#if defined(CONFIG_RSBAC_MAC) + fd_count = rsbac_list_count(device_p->handles.mac); + if (fd_count >= 0) { + seq_printf(m, ", %lu MAC", fd_count); + fd_dev_count += fd_count; + } +#endif + +#if defined(CONFIG_RSBAC_DAZ) + fd_count = rsbac_list_count(device_p->handles.daz); + if (fd_count >= 0) { + seq_printf(m, ", %lu DAZ", fd_count); + fd_dev_count += fd_count; + } +#if defined(CONFIG_RSBAC_DAZ_CACHE) + fd_count = rsbac_list_count(device_p->handles.dazs); + if (fd_count >= 0) { + seq_printf(m, ", %lu DAZ SCANNED", fd_count); + fd_dev_count += fd_count; + } +#endif +#endif + +#if defined(CONFIG_RSBAC_FF) + fd_count = rsbac_list_count(device_p->handles.ff); + if (fd_count >= 0) { + seq_printf(m, ", %lu FF", fd_count); + fd_dev_count += fd_count; + } +#endif + +#if defined(CONFIG_RSBAC_RC) + fd_count = rsbac_list_count(device_p->handles.rc); + if (fd_count >= 0) { + seq_printf(m, ", %lu RC", fd_count); + fd_dev_count += fd_count; + } +#endif + +#if defined(CONFIG_RSBAC_AUTH) + fd_count = rsbac_list_count(device_p->handles.auth); + if (fd_count >= 0) { + seq_printf(m, ", %lu AUTH", fd_count); + fd_dev_count += fd_count; + } +#endif + +#if defined(CONFIG_RSBAC_CAP) + fd_count = rsbac_list_count(device_p->handles.cap); + if (fd_count >= 0) { + seq_printf(m, ", %lu CAP", fd_count); + fd_dev_count += fd_count; + } +#endif + +#if defined(CONFIG_RSBAC_RES) + fd_count = rsbac_list_count(device_p->handles.res); + if (fd_count >= 0) { + seq_printf(m, ", %lu RES", fd_count); + fd_dev_count += fd_count; + } +#endif + +#if defined(CONFIG_RSBAC_PAX) + fd_count = rsbac_list_count(device_p->handles.pax); + if (fd_count >= 0) { + seq_printf(m, ", %lu PAX", fd_count); + fd_dev_count += fd_count; + } +#endif + +#if defined(CONFIG_RSBAC_UDF) + fd_count = rsbac_list_count(device_p->handles.udf); + if (fd_count >= 0) { + seq_printf(m, ", %lu UDF", fd_count); + fd_dev_count += fd_count; + } +#if defined(CONFIG_RSBAC_UDF_CACHE) + fd_count = rsbac_list_count(device_p->handles.udfc); + if (fd_count >= 0) { + seq_printf(m, ", %lu UDF CHECKED", fd_count); + fd_dev_count += fd_count; + } +#endif +#endif + + seq_printf(m, ", %lu total\n", + fd_dev_count); + fd_sum += fd_dev_count; + device_p = srcu_dereference(device_p->next, &device_list_srcu[i]); + } + tmp_count += device_head_p[i]->count; + srcu_read_unlock(&device_list_srcu[i], srcu_idx); + } + seq_printf(m, + "Sum of %lu Devices with %lu fd-items\n\n", + tmp_count, fd_sum); + total_sum += fd_sum; + /* dev lists */ + sum = 0; + tmp_count = rsbac_list_count(dev_handles.gen); + seq_printf(m, "DEV: %lu GEN", tmp_count); + sum += tmp_count; +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(dev_handles.mac); + seq_printf(m, ", %lu MAC", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(dev_major_handles.rc); + seq_printf(m, ", %lu major RC", tmp_count); + sum += tmp_count; + tmp_count = rsbac_list_count(dev_handles.rc); + seq_printf(m, ", %lu RC", tmp_count); + sum += tmp_count; +#endif + seq_printf(m, ", %lu total\n", sum); + total_sum += sum; + /* ipc lists */ + sum = 0; + seq_printf(m, "IPC: 0 GEN"); +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(ipc_handles.mac); + seq_printf(m, ", %lu MAC", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(ipc_handles.rc); + seq_printf(m, ", %lu RC", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_JAIL) + tmp_count = rsbac_list_count(ipc_handles.jail); + seq_printf(m, ", %lu JAIL", tmp_count); + sum += tmp_count; +#endif + seq_printf(m, ", %lu total\n", sum); + total_sum += sum; + /* user lists */ + sum = 0; + tmp_count = rsbac_list_count(user_handles.gen); + seq_printf(m, "USER: %lu GEN", tmp_count); + sum += tmp_count; +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(user_handles.mac); + seq_printf(m, ", %lu MAC", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_DAZ) + tmp_count = rsbac_list_count(user_handles.daz); + seq_printf(m, ", %lu DAZ", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_FF) + tmp_count = rsbac_list_count(user_handles.ff); + seq_printf(m, ", %lu FF", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(user_handles.rc); + seq_printf(m, ", %lu RC", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_AUTH) + tmp_count = rsbac_list_count(user_handles.auth); + seq_printf(m, ", %lu AUTH", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_CAP) + tmp_count = rsbac_list_count(user_handles.cap); + seq_printf(m, ", %lu CAP", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_JAIL) + tmp_count = rsbac_list_count(user_handles.jail); + seq_printf(m, ", %lu JAIL", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RES) + tmp_count = rsbac_list_count(user_handles.res); + seq_printf(m, ", %lu RES", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_PAX) + tmp_count = rsbac_list_count(user_handles.pax); + seq_printf(m, ", %lu PAX", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_UDF) + tmp_count = rsbac_list_count(user_handles.udf); + seq_printf(m, ", %lu UDF", tmp_count); + sum += tmp_count; +#endif + seq_printf(m, ", %lu total\n", sum); + total_sum += sum; + /* process lists */ + sum = 0; + tmp_count = rsbac_list_count(process_handles.gen); + seq_printf(m, "PROCESS: %lu GEN", tmp_count); + sum += tmp_count; +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(process_handles.mac); + seq_printf(m, ", %lu MAC", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_DAZ) + tmp_count = rsbac_list_count(process_handles.daz); + seq_printf(m, ", %lu DAZ", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(process_handles.rc); + seq_printf(m, ", %lu RC", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_AUTH) + tmp_count = rsbac_list_count(process_handles.auth); + seq_printf(m, ", %lu AUTH", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_CAP) + tmp_count = rsbac_list_count(process_handles.cap); + seq_printf(m, ", %lu CAP", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_JAIL) + tmp_count = rsbac_list_count(process_handles.jail); + seq_printf(m, ", %lu JAIL", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_UDF) + tmp_count = rsbac_list_count(process_handles.udf); + seq_printf(m, ", %lu UDF", tmp_count); + sum += tmp_count; +#endif + seq_printf(m, ", %lu total\n", sum); + total_sum += sum; +#if defined(CONFIG_RSBAC_UM) + /* group lists */ + sum = 0; + seq_printf(m, "GROUP:"); +#if defined(CONFIG_RSBAC_RC_UM_PROT) + tmp_count = rsbac_list_count(group_handles.rc); + seq_printf(m, " %lu RC,", tmp_count); + sum += tmp_count; +#endif + seq_printf(m, " %lu total\n", sum); + total_sum += sum; +#endif + +#if defined(CONFIG_RSBAC_NET_DEV) + /* netdev lists */ + sum = 0; +#if defined(CONFIG_RSBAC_IND_NETDEV_LOG) + tmp_count = rsbac_list_count(netdev_handles.gen); + seq_printf(m, "NETDEV: %lu GEN, ", tmp_count); + sum += tmp_count; +#else + seq_printf(m, "NETDEV: "); +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(netdev_handles.rc); + seq_printf(m, "%lu RC, ", tmp_count); + sum += tmp_count; +#endif + seq_printf(m, "%lu total\n", sum); + total_sum += sum; +#endif + +#if defined(CONFIG_RSBAC_NET_OBJ) + /* net template list */ + tmp_count = rsbac_list_count(net_temp_handle); + seq_printf(m, "%lu Network Templates\n", tmp_count); + /* nettemp lists */ + sum = 0; +#if defined(CONFIG_RSBAC_IND_NETOBJ_LOG) + tmp_count = rsbac_list_count(nettemp_handles.gen); + seq_printf(m, "NETTEMP: %lu GEN, ", tmp_count); + sum += tmp_count; +#else + seq_printf(m, "NETTEMP: "); +#endif +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(nettemp_handles.mac); + seq_printf(m, "%lu MAC, ", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(nettemp_handles.rc); + seq_printf(m, "%lu RC, ", tmp_count); + sum += tmp_count; +#endif + seq_printf(m, "%lu total\n", sum); + total_sum += sum; + /* local netobj lists */ + sum = 0; + seq_printf(m, "LNETOBJ: "); +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(lnetobj_handles.mac); + seq_printf(m, "%lu MAC, ", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(lnetobj_handles.rc); + seq_printf(m, "%lu RC, ", tmp_count); + sum += tmp_count; +#endif + seq_printf(m, "%lu total\n", sum); + total_sum += sum; + /* remote netobj lists */ + sum = 0; + seq_printf(m, "RNETOBJ: "); +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(rnetobj_handles.mac); + seq_printf(m, "%lu MAC, ", tmp_count); + sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(rnetobj_handles.rc); + seq_printf(m, "%lu RC, ", tmp_count); + sum += tmp_count; +#endif + seq_printf(m, "%lu total\n", sum); + total_sum += sum; +#endif /* NET_OBJ */ + + seq_printf(m, + "Total sum of %lu registered rsbac-items\n", + total_sum); + seq_printf(m, + "\nadf_request calls:\nfile: %llu, dir: %llu, fifo: %llu, symlink: %llu, dev: %llu, ipc: %llu, scd: %llu, user: %llu, process: %llu, netdev: %llu, nettemp: %llu, netobj: %llu, group: %llu, unixsock: %llu, total: %llu\n", + rsbac_adf_request_count[T_FILE], + rsbac_adf_request_count[T_DIR], + rsbac_adf_request_count[T_FIFO], + rsbac_adf_request_count[T_SYMLINK], + rsbac_adf_request_count[T_DEV], + rsbac_adf_request_count[T_IPC], + rsbac_adf_request_count[T_SCD], + rsbac_adf_request_count[T_USER], + rsbac_adf_request_count[T_PROCESS], + rsbac_adf_request_count[T_NETDEV], + rsbac_adf_request_count[T_NETTEMP], + rsbac_adf_request_count[T_NETOBJ], + rsbac_adf_request_count[T_GROUP], + rsbac_adf_request_count[T_UNIXSOCK], + rsbac_adf_request_count[T_FILE]+rsbac_adf_request_count[T_DIR]+rsbac_adf_request_count[T_FIFO]+rsbac_adf_request_count[T_SYMLINK]+rsbac_adf_request_count[T_DEV]+rsbac_adf_request_count[T_IPC]+rsbac_adf_request_count[T_SCD]+rsbac_adf_request_count[T_USER]+rsbac_adf_request_count[T_PROCESS]+rsbac_adf_request_count[T_NETDEV]+rsbac_adf_request_count[T_NETTEMP]+rsbac_adf_request_count[T_NETOBJ]+rsbac_adf_request_count[T_GROUP]+rsbac_adf_request_count[T_UNIXSOCK]); + seq_printf(m, + "adf_set_attr calls:\nfile: %llu, dir: %llu, fifo: %llu, symlink: %llu, dev: %llu, ipc: %llu, scd: %llu, user: %llu, process: %llu, netdev: %llu, nettemp: %llu, netobj: %llu, group: %llu, unixsock: %llu, total: %llu\n", + rsbac_adf_set_attr_count[T_FILE], + rsbac_adf_set_attr_count[T_DIR], + rsbac_adf_set_attr_count[T_FIFO], + rsbac_adf_set_attr_count[T_SYMLINK], + rsbac_adf_set_attr_count[T_DEV], + rsbac_adf_set_attr_count[T_IPC], + rsbac_adf_set_attr_count[T_SCD], + rsbac_adf_set_attr_count[T_USER], + rsbac_adf_set_attr_count[T_PROCESS], + rsbac_adf_set_attr_count[T_NETDEV], + rsbac_adf_set_attr_count[T_NETTEMP], + rsbac_adf_set_attr_count[T_NETOBJ], + rsbac_adf_set_attr_count[T_GROUP], + rsbac_adf_set_attr_count[T_UNIXSOCK], + rsbac_adf_set_attr_count[T_FILE]+rsbac_adf_set_attr_count[T_DIR]+rsbac_adf_set_attr_count[T_FIFO]+rsbac_adf_set_attr_count[T_SYMLINK]+rsbac_adf_set_attr_count[T_DEV]+rsbac_adf_set_attr_count[T_IPC]+rsbac_adf_set_attr_count[T_SCD]+rsbac_adf_set_attr_count[T_USER]+rsbac_adf_set_attr_count[T_PROCESS]+rsbac_adf_set_attr_count[T_NETDEV]+rsbac_adf_set_attr_count[T_NETTEMP]+rsbac_adf_set_attr_count[T_NETOBJ]+rsbac_adf_set_attr_count[T_GROUP]+rsbac_adf_set_attr_count[T_UNIXSOCK]); + return 0; +} + +static int stats_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, stats_proc_show, NULL); +} + +static const struct file_operations stats_proc_fops = { + .owner = THIS_MODULE, + .open = stats_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *stats; + +static int +active_proc_show(struct seq_file *m, void *v) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_initialized) + return -ENOSYS; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, "Version: %s, API min: %s, API max: %s\n", + RSBAC_VERSION, RSBAC_API_MIN_VERSION, RSBAC_API_MAX_VERSION); +#ifdef CONFIG_RSBAC_SOFTMODE + if (rsbac_softmode) + seq_printf(m, "Mode: SOFTMODE\n"); + else +#endif + seq_printf(m, "Mode: Secure\n"); +#ifdef CONFIG_RSBAC_SOFTMODE + seq_printf(m, "Softmode: available\n"); +#else + seq_printf(m, "Softmode: unavailable\n"); +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + seq_printf(m, "Ind-Soft: available\n"); +#else + seq_printf(m, "Ind-Soft: unavailable\n"); +#endif +#ifdef CONFIG_RSBAC_SWITCH + seq_printf(m, "Switching off: available for"); +#ifdef CONFIG_RSBAC_SWITCH_MAC +#ifndef CONFIG_RSBAC_SWITCH_ON + if (rsbac_switch_mac) +#endif + seq_printf(m, " MAC"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_DAZ + seq_printf(m, " DAZ"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_FF + seq_printf(m, " FF"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_RC +#ifndef CONFIG_RSBAC_SWITCH_ON + if (rsbac_switch_rc) +#endif + seq_printf(m, " RC"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_AUTH + seq_printf(m, " AUTH"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_ACL + seq_printf(m, " ACL"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_CAP + seq_printf(m, " CAP"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_JAIL + seq_printf(m, " JAIL"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_RES + seq_printf(m, " RES"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_PAX + seq_printf(m, " PAX"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_UDF + seq_printf(m, " UDF"); +#endif + seq_printf(m, "\n"); + seq_printf(m, "Switching on: available for"); +#ifdef CONFIG_RSBAC_SWITCH_ON +#ifdef CONFIG_RSBAC_SWITCH_MAC + seq_printf(m, " MAC"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_RC + seq_printf(m, " RC"); +#endif +#endif +#ifdef CONFIG_RSBAC_SWITCH_DAZ + seq_printf(m, " DAZ"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_FF + seq_printf(m, " FF"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_AUTH + seq_printf(m, " AUTH"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_ACL + seq_printf(m, " ACL"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_CAP + seq_printf(m, " CAP"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_JAIL + seq_printf(m, " JAIL"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_RES + seq_printf(m, " RES"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_PAX + seq_printf(m, " PAX"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_UDF + seq_printf(m, " UDF"); +#endif +#ifdef CONFIG_RSBAC_SWITCH_MPROTECT + seq_printf(m, " MPROTECT"); +#endif + seq_printf(m, "\n"); +#else + seq_printf(m, "Switching off: unavailable\n"); + seq_printf(m, "Switching on: unavailable\n"); +#endif +#endif +#ifdef CONFIG_RSBAC_REG +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_REG]) + seq_printf(m, "Module: REG SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: REG on\n"); +#endif + +#ifdef CONFIG_RSBAC_MAC +#ifdef CONFIG_RSBAC_SWITCH_MAC + if (!rsbac_switch_mac) + seq_printf(m, "Module: MAC OFF\n"); + else +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_MAC]) + seq_printf(m, "Module: MAC SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: MAC on\n"); +#endif + +#ifdef CONFIG_RSBAC_DAZ +#ifdef CONFIG_RSBAC_SWITCH_DAZ + if (!rsbac_switch_daz) + seq_printf(m, "Module: DAZ OFF\n"); + else +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_DAZ]) + seq_printf(m, "Module: DAZ SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: DAZ on\n"); +#endif + +#ifdef CONFIG_RSBAC_FF +#ifdef CONFIG_RSBAC_SWITCH_FF + if (!rsbac_switch_ff) + seq_printf(m, "Module: FF OFF\n"); + else +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_FF]) + seq_printf(m, "Module: FF SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: FF on\n"); +#endif + +#ifdef CONFIG_RSBAC_RC +#ifdef CONFIG_RSBAC_SWITCH_RC + if (!rsbac_switch_rc) + seq_printf(m, "Module: RC OFF\n"); + else +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_RC]) + seq_printf(m, "Module: RC SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: RC on\n"); +#endif + +#ifdef CONFIG_RSBAC_AUTH +#ifdef CONFIG_RSBAC_SWITCH_AUTH + if (!rsbac_switch_auth) + seq_printf(m, "Module: AUTH OFF\n"); + else +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_AUTH]) + seq_printf(m, "Module: AUTH SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: AUTH on\n"); +#endif + +#ifdef CONFIG_RSBAC_ACL +#ifdef CONFIG_RSBAC_SWITCH_ACL + if (!rsbac_switch_acl) + seq_printf(m, "Module: ACL OFF\n"); + else +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_ACL]) + seq_printf(m, "Module: ACL SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: ACL on\n"); +#endif + +#ifdef CONFIG_RSBAC_CAP +#ifdef CONFIG_RSBAC_SWITCH_CAP + if (!rsbac_switch_cap) + seq_printf(m, "Module: CAP OFF\n"); + else +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_CAP]) + seq_printf(m, "Module: CAP SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: CAP on\n"); +#endif + +#ifdef CONFIG_RSBAC_JAIL +#ifdef CONFIG_RSBAC_SWITCH_JAIL + if (!rsbac_switch_jail) + seq_printf(m, "Module: JAIL OFF\n"); + else +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_JAIL]) + seq_printf(m, "Module: JAIL SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: JAIL on\n"); +#endif + +#ifdef CONFIG_RSBAC_RES +#ifdef CONFIG_RSBAC_SWITCH_RES + if (!rsbac_switch_res) + seq_printf(m, "Module: RES OFF\n"); + else +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_RES]) + seq_printf(m, "Module: RES SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: RES on\n"); +#endif + +#ifdef CONFIG_RSBAC_PAX +#ifdef CONFIG_RSBAC_SWITCH_PAX + if (!rsbac_switch_pax) + seq_printf(m, "Module: PAX OFF\n"); + else +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_PAX]) + seq_printf(m, "Module: PAX SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: PAX on\n"); +#endif + +#ifdef CONFIG_RSBAC_UDF +#ifdef CONFIG_RSBAC_SWITCH_UDF + if (!rsbac_switch_udf) + seq_printf(m, "Module: UDF OFF\n"); + else +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_UDF]) + seq_printf(m, "Module: UDF SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: UDF on\n"); +#endif + +#ifdef CONFIG_RSBAC_MPROTECT +#ifdef CONFIG_RSBAC_SWITCH_MPROTECT + if (!rsbac_switch_mprotect) + seq_printf(m, "Module: MPROTECT OFF\n"); + else +#endif +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if (rsbac_ind_softmode[SW_MPROTECT]) + seq_printf(m, "Module: MPROTECT SOFTMODE\n"); + else +#endif + seq_printf(m, "Module: MPROTECT on\n"); +#endif + + return 0; +} + +static int active_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, active_proc_show, NULL); +} + +static const struct file_operations active_proc_fops = { + .owner = THIS_MODULE, + .open = active_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *active; + +#ifdef CONFIG_RSBAC_XSTATS +static int +xstats_proc_show(struct seq_file *m, void *v) +{ + int i, j; + char name[80]; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; +#ifdef CONFIG_RSBAC_FD_CACHE + struct rsbac_device_list_head_t *head_p; + struct rsbac_device_list_item_t *device_p; + int srcu_idx; + int header_shown; +#endif + + if (!rsbac_initialized) + return -ENOSYS; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, + "RSBAC ADF call Statistics\n-------------------------\nadf_request table:\n"); + seq_printf(m, + "Request /\tFILE\tDIR\tFIFO\tSYMLINK\tDEV\tIPC\tSCD\tUSER\tPROCESS\tNETDEV\tNETTEMP\tNETOBJ\tGROUP\tUNIXSOCK NONE"); + + for (i = 0; i < R_NONE; i++) { + get_request_name(name, i); + name[15] = 0; + seq_printf(m, "\n%-14s\t", name); + for (j = 0; j <= T_NONE; j++) { + if ((j == T_NETTEMP_NT) + || (j == T_FD) + ) + continue; + seq_printf(m, "%llu\t", + rsbac_adf_request_xcount[j][i]); + } + } + + seq_printf(m, + "\n\nadf_request calls:\nfile: %llu, dir: %llu, fifo: %llu, symlink: %llu, dev: %llu, ipc: %llu, scd: %llu, user: %llu, process: %llu, netdev: %llu, nettemp: %llu, netobj: %llu, group: %llu, unixsock: %llu, none: %llu, total: %llu\n", + rsbac_adf_request_count[T_FILE], + rsbac_adf_request_count[T_DIR], + rsbac_adf_request_count[T_FIFO], + rsbac_adf_request_count[T_SYMLINK], + rsbac_adf_request_count[T_DEV], + rsbac_adf_request_count[T_IPC], + rsbac_adf_request_count[T_SCD], + rsbac_adf_request_count[T_USER], + rsbac_adf_request_count[T_PROCESS], + rsbac_adf_request_count[T_NETDEV], + rsbac_adf_request_count[T_NETTEMP], + rsbac_adf_request_count[T_NETOBJ], + rsbac_adf_request_count[T_GROUP], + rsbac_adf_request_count[T_UNIXSOCK], + rsbac_adf_request_count[T_NONE], + rsbac_adf_request_count[T_FILE]+rsbac_adf_request_count[T_DIR]+rsbac_adf_request_count[T_FIFO]+rsbac_adf_request_count[T_SYMLINK]+rsbac_adf_request_count[T_DEV]+rsbac_adf_request_count[T_IPC]+rsbac_adf_request_count[T_SCD]+rsbac_adf_request_count[T_USER]+rsbac_adf_request_count[T_PROCESS]+rsbac_adf_request_count[T_NETDEV]+rsbac_adf_request_count[T_NETTEMP]+rsbac_adf_request_count[T_NETOBJ]+rsbac_adf_request_count[T_GROUP]+rsbac_adf_request_count[T_UNIXSOCK]+rsbac_adf_request_count[T_NONE]); + seq_printf(m, + "\n\nadf_set_attr table:\nRequest /\tFILE\tDIR\tFIFO\tSYMLINK\tDEV\tIPC\tSCD\tUSER\tPROCESS\tNETDEV\tNETTEMP\tNETOBJ\tGROUP\tUNIXSOCK NONE"); + for (i = 0; i < R_NONE; i++) { + get_request_name(name, i); + name[15] = 0; + seq_printf(m, "\n%-14s\t", name); + for (j = 0; j <= T_NONE; j++) { + if ((j == T_NETTEMP_NT) + || (j == T_FD) + ) + continue; + seq_printf(m, "%llu\t", + rsbac_adf_set_attr_xcount[j][i]); + } + } + + seq_printf(m, + "\n\nadf_set_attr calls:\nfile: %llu, dir: %llu, fifo: %llu, symlink: %llu, dev: %llu, ipc: %llu, scd: %llu, user: %llu, process: %llu, netdev: %llu, nettemp: %llu, netobj: %llu, group: %llu, unixsock: %llu, none: %llu, total: %llu\n", + rsbac_adf_set_attr_count[T_FILE], + rsbac_adf_set_attr_count[T_DIR], + rsbac_adf_set_attr_count[T_FIFO], + rsbac_adf_set_attr_count[T_SYMLINK], + rsbac_adf_set_attr_count[T_DEV], + rsbac_adf_set_attr_count[T_IPC], + rsbac_adf_set_attr_count[T_SCD], + rsbac_adf_set_attr_count[T_USER], + rsbac_adf_set_attr_count[T_PROCESS], + rsbac_adf_set_attr_count[T_NETDEV], + rsbac_adf_set_attr_count[T_NETTEMP], + rsbac_adf_set_attr_count[T_NETOBJ], + rsbac_adf_set_attr_count[T_GROUP], + rsbac_adf_set_attr_count[T_UNIXSOCK], + rsbac_adf_set_attr_count[T_NONE], + rsbac_adf_set_attr_count[T_FILE]+rsbac_adf_set_attr_count[T_DIR]+rsbac_adf_set_attr_count[T_FIFO]+rsbac_adf_set_attr_count[T_SYMLINK]+rsbac_adf_set_attr_count[T_DEV]+rsbac_adf_set_attr_count[T_IPC]+rsbac_adf_set_attr_count[T_SCD]+rsbac_adf_set_attr_count[T_USER]+rsbac_adf_set_attr_count[T_PROCESS]+rsbac_adf_set_attr_count[T_NETDEV]+rsbac_adf_set_attr_count[T_NETTEMP]+rsbac_adf_set_attr_count[T_NETOBJ]+rsbac_adf_set_attr_count[T_GROUP]+rsbac_adf_set_attr_count[T_UNIXSOCK]+rsbac_adf_set_attr_count[T_NONE]); + seq_printf(m, + "\nSyscall counts\n-------------\n"); + + for (i = 0; i < RSYS_none; i++) { + rsbac_get_syscall_name(name, i); + name[30] = 0; + seq_printf(m, "%-26s %llu\n", + name, syscall_count[i]); + } + + seq_printf(m, + "\n\nData Structures:\nrsbac_get_attr calls:\nfile: %llu, dir: %llu, fifo: %llu, symlink: %llu, dev: %llu, ipc: %llu, scd: %llu, user: %llu, process: %llu, netdev: %llu, nettemp: %llu, netobj: %llu, group: %llu, unixsock: %llu\n", + get_attr_count[T_FILE], + get_attr_count[T_DIR], + get_attr_count[T_FIFO], + get_attr_count[T_SYMLINK], + get_attr_count[T_DEV], + get_attr_count[T_IPC], + get_attr_count[T_SCD], + get_attr_count[T_USER], + get_attr_count[T_PROCESS], + get_attr_count[T_NETDEV], + get_attr_count[T_NETTEMP], + get_attr_count[T_NETOBJ], + get_attr_count[T_GROUP], + get_attr_count[T_UNIXSOCK]); + + seq_printf(m, + "\nrsbac_set_attr calls:\nfile: %llu, dir: %llu, fifo: %llu, symlink: %llu, dev: %llu, ipc: %llu, scd: %llu, user: %llu, process: %llu, netdev: %llu, nettemp: %llu, netobj: %llu, group: %llu, unixsock: %llu\n", + set_attr_count[T_FILE], + set_attr_count[T_DIR], + set_attr_count[T_FIFO], + set_attr_count[T_SYMLINK], + set_attr_count[T_DEV], + set_attr_count[T_IPC], + set_attr_count[T_SCD], + set_attr_count[T_USER], + set_attr_count[T_PROCESS], + set_attr_count[T_NETDEV], + set_attr_count[T_NETTEMP], + set_attr_count[T_NETOBJ], + set_attr_count[T_GROUP], + set_attr_count[T_UNIXSOCK]); + + seq_printf(m, + "\nrsbac_remove_target calls:\nfile: %llu, dir: %llu, fifo: %llu, symlink: %llu, dev: %llu, ipc: %llu, scd: %llu, user: %llu, process: %llu, netdev: %llu, nettemp: %llu, netobj: %llu, group: %llu, unixsock: %llu\n", + remove_count[T_FILE], + remove_count[T_DIR], + remove_count[T_FIFO], + remove_count[T_SYMLINK], + remove_count[T_DEV], + remove_count[T_IPC], + remove_count[T_SCD], + remove_count[T_USER], + remove_count[T_PROCESS], + remove_count[T_NETDEV], + remove_count[T_NETTEMP], + remove_count[T_NETOBJ], + remove_count[T_GROUP], + remove_count[T_UNIXSOCK]); + + seq_printf(m, + "\nrsbac_get_parent calls: %llu\n", + get_parent_count); + +#ifdef CONFIG_RSBAC_FD_CACHE + seq_printf(m, "\nFD Caches:\n"); + for (i = 0; i < RSBAC_NR_DEVICE_LISTS; i++) { + srcu_idx = srcu_read_lock(&device_list_srcu[i]); + head_p = srcu_dereference(device_head_p[i], &device_list_srcu[i]); + device_p = srcu_dereference(head_p->head, &device_list_srcu[i]); + while (device_p) { /* for all sublists */ + header_shown = 0; + for (j = 0; j < SW_NONE; j++) { + if (device_p->fd_cache_handle[j]) { + __u64 tmp_hits = device_p->fd_cache_hits[j]; + __u64 tmp_misses = device_p->fd_cache_misses[j]; + + if (!header_shown) { + seq_printf(m, + "\n%02u:%02u hits misses items subitem hm-ratio\n", + RSBAC_MAJOR(device_p->id), RSBAC_MINOR(device_p->id)); + header_shown = 1; + } + while ((tmp_hits > (__u32) -1) || (tmp_misses > (__u32) -1)) { + tmp_hits >>= 1; + tmp_misses >>= 1; + } + if (!tmp_misses) + tmp_misses = 1; + seq_printf(m, "%-8s %-20llu %-20llu %-7lu %-7lu %u\n", + get_switch_target_name(name, j), + device_p->fd_cache_hits[j], device_p->fd_cache_misses[j], + rsbac_list_lol_count(device_p->fd_cache_handle[j]), + rsbac_list_lol_all_subcount(device_p->fd_cache_handle[j]), + ((__u32) tmp_hits)/((__u32) tmp_misses)); + } + } + if (header_shown) + seq_printf(m, "%u fd_cache_invalidates, %u fd_cache_invalidate_alls\n", + device_p->fd_cache_invalidates, device_p->fd_cache_invalidate_alls); + device_p = srcu_dereference(device_p->next, &device_list_srcu[i]); + } + srcu_read_unlock(&device_list_srcu[i], srcu_idx); + } +#endif +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) + seq_printf(m, "\n%u delayed_kfree items in use, %lu delayed_kfree calls counted\n", + delayed_kfree_used, delayed_kfree_count); +#endif + return 0; +} + +static int xstats_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, xstats_proc_show, NULL); +} + +static const struct file_operations xstats_proc_fops = { + .owner = THIS_MODULE, + .open = xstats_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *xstats; +#endif + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +static int +auto_write_proc_show(struct seq_file *m, void *v) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_initialized) + return -ENOSYS; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, + "RSBAC auto write settings\n-------------------------\n"); + seq_printf(m, + "auto interval %u jiffies (%i jiffies = 1 second)\n", + auto_interval, HZ); + +#ifdef CONFIG_RSBAC_DEBUG + seq_printf(m, "debug level is %i\n", + rsbac_debug_auto); +#endif + + return 0; +} + +static int auto_write_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, auto_write_proc_show, NULL); +} + +static ssize_t auto_write_proc_write(struct file *file, + const char __user * buf, size_t count, + loff_t *data) +{ + ssize_t err; + char *k_buf; + char *p; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (count > PROC_BLOCK_SIZE) { + return -EOVERFLOW; + } + + if (!(k_buf = (char *) __get_free_page(GFP_KERNEL))) + return -ENOMEM; + err = copy_from_user(k_buf, buf, count); + if (err < 0) + return err; + + err = count; + if (count < 13 || strncmp("auto", k_buf, 4)) { + goto out; + } + if (!rsbac_initialized) { + err = -ENOSYS; + goto out; + } + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + err = -EPERM; + goto out; + } + + /* + * Usage: echo "auto interval #N" > /proc/rsbac_info/auto_write + * to set auto_interval to given value + */ + if (!strncmp("interval", k_buf + 5, 8)) { + unsigned int interval; + + p = k_buf + 5 + 9; + + if (*p == '\0') + goto out; + + interval = simple_strtoul(p, NULL, 0); + /* only accept minimum of 1 second */ + if (interval >= HZ) { + rsbac_printk(KERN_INFO "auto_write_proc_write(): setting auto write interval to %u\n", + interval); + auto_interval = interval; + err = count; + goto out; + } else { + rsbac_printk(KERN_INFO "auto_write_proc_write(): rejecting too short auto write interval %u (min. %i)\n", + interval, HZ); + goto out; + } + } +#ifdef CONFIG_RSBAC_DEBUG + /* + * Usage: echo "auto debug #N" > /proc/rsbac_info/auto_write + * to set rsbac_debug_auto to given value + */ + if (!strncmp("debug", k_buf + 5, 5)) { + unsigned int debug_level; + + p = k_buf + 5 + 6; + + if (*p == '\0') + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if (!debug_level || (debug_level == 1)) { + rsbac_printk(KERN_INFO "auto_write_proc_write(): setting rsbac_debug_auto to %u\n", + debug_level); + rsbac_debug_auto = debug_level; + err = count; + } else { + rsbac_printk(KERN_INFO "auto_write_proc_write(): rejecting invalid debug level (should be 0 or 1)\n"); + } + } +#endif + + out: + free_page((ulong) k_buf); + return err; +} + +static const struct file_operations auto_write_proc_fops = { + .owner = THIS_MODULE, + .open = auto_write_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = auto_write_proc_write, +}; + +static struct proc_dir_entry *auto_write; +#endif /* CONFIG_RSBAC_AUTO_WRITE > 0 */ + +static int +versions_proc_show(struct seq_file *m, void *v) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_initialized) + return -ENOSYS; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, + "RSBAC version settings (%s)\n----------------------\n", + RSBAC_VERSION); + seq_printf(m, + "Device list head size is %u, hash size is %u\n", + (int) sizeof(struct rsbac_device_list_item_t), + RSBAC_NR_DEVICE_LISTS); + seq_printf(m, + "FD lists:\nGEN aci version is %u, aci entry size is %Zd, %u lists per device\n", + RSBAC_GEN_FD_ACI_VERSION, + sizeof(struct rsbac_gen_fd_aci_t), + 1 << gen_nr_fd_hash_bits); +#if defined(CONFIG_RSBAC_MAC) + seq_printf(m, + "MAC aci version is %u, aci entry size is %Zd, %u lists per device\n", + RSBAC_MAC_FD_ACI_VERSION, + sizeof(struct rsbac_mac_fd_aci_t), + 1 << mac_nr_fd_hash_bits); +#endif +#if defined(CONFIG_RSBAC_DAZ) + seq_printf(m, + "DAZ aci version is %u, aci entry size is %Zd, %u lists per device\n", + RSBAC_DAZ_FD_ACI_VERSION, + sizeof(struct rsbac_daz_fd_aci_t), + 1 << daz_nr_fd_hash_bits); +#if defined(CONFIG_RSBAC_DAZ_CACHE) + seq_printf(m, + "DAZS aci version is %u, aci entry size is %Zd, %u lists per device\n", + RSBAC_DAZ_SCANNED_FD_ACI_VERSION, + sizeof(rsbac_daz_scanned_t), + 1 << daz_scanned_nr_fd_hash_bits); +#endif +#endif +#if defined(CONFIG_RSBAC_FF) + seq_printf(m, + "FF aci version is %u, aci entry size is %Zd, %u lists per device\n", + RSBAC_FF_FD_ACI_VERSION, sizeof(rsbac_ff_flags_t), + 1 << ff_nr_fd_hash_bits); +#endif +#if defined(CONFIG_RSBAC_RC) + seq_printf(m, + "RC aci version is %u, aci entry size is %Zd, %u lists per device\n", + RSBAC_RC_FD_ACI_VERSION, + sizeof(struct rsbac_rc_fd_aci_t), + 1 << rc_nr_fd_hash_bits); +#endif +#if defined(CONFIG_RSBAC_AUTH) + seq_printf(m, + "AUTH aci version is %u, aci entry size is %Zd, %u lists per device\n", + RSBAC_AUTH_FD_ACI_VERSION, + sizeof(struct rsbac_auth_fd_aci_t), + 1 << auth_nr_fd_hash_bits); +#endif +#if defined(CONFIG_RSBAC_CAP) + seq_printf(m, + "CAP aci version is %u, aci entry size is %Zd, %u lists per device\n", + RSBAC_CAP_FD_ACI_VERSION, + sizeof(struct rsbac_cap_fd_aci_t), + 1 << cap_nr_fd_hash_bits); +#endif +#if defined(CONFIG_RSBAC_PAX) + seq_printf(m, + "PAX aci version is %u, aci entry size is %Zd, %u lists per device\n", + RSBAC_PAX_FD_ACI_VERSION, sizeof(rsbac_pax_flags_t), + 1 << pax_nr_fd_hash_bits); +#endif +#if defined(CONFIG_RSBAC_RES) + seq_printf(m, + "RES aci version is %u, aci entry size is %Zd, %u lists per device\n", + RSBAC_RES_FD_ACI_VERSION, + sizeof(struct rsbac_res_fd_aci_t), + 1 << res_nr_fd_hash_bits); +#endif +#if defined(CONFIG_RSBAC_UDF) + seq_printf(m, + "UDF aci version is %u, aci entry size is %Zd, %u lists per device\n", + RSBAC_UDF_FD_ACI_VERSION, + sizeof(struct rsbac_udf_fd_aci_t), + 1 << udf_nr_fd_hash_bits); +#if defined(CONFIG_RSBAC_UDF_CACHE) + seq_printf(m, + "UDFC aci version is %u, aci entry size is %Zd, %u lists per device\n", + RSBAC_UDF_CHECKED_FD_ACI_VERSION, + sizeof(rsbac_udf_checked_t), + 1 << udf_checked_nr_fd_hash_bits); +#endif +#endif + seq_printf(m, + "\nDEV lists:\nGEN aci version is %u, aci entry size is %Zd\n", + RSBAC_GEN_DEV_ACI_VERSION, + sizeof(struct rsbac_gen_dev_aci_t)); +#if defined(CONFIG_RSBAC_MAC) + seq_printf(m, + "MAC aci version is %u, aci entry size is %Zd\n", + RSBAC_MAC_DEV_ACI_VERSION, + sizeof(struct rsbac_mac_dev_aci_t)); +#endif +#if defined(CONFIG_RSBAC_RC) + seq_printf(m, + "RC aci version is %u, aci entry size is %Zd\n", + RSBAC_RC_DEV_ACI_VERSION, sizeof(rsbac_rc_type_id_t)); +#endif + seq_printf(m, "\nIPC lists:\n"); +#if defined(CONFIG_RSBAC_MAC) + seq_printf(m, + "MAC aci version is %u, aci entry size is %Zd\n", + RSBAC_MAC_IPC_ACI_VERSION, + sizeof(struct rsbac_mac_ipc_aci_t)); +#endif +#if defined(CONFIG_RSBAC_RC) + seq_printf(m, + "RC aci version is %u, aci entry size is %Zd\n", + RSBAC_RC_IPC_ACI_VERSION, sizeof(rsbac_rc_type_id_t)); +#endif +#if defined(CONFIG_RSBAC_JAIL) + seq_printf(m, + "JAIL aci version is %u, aci entry size is %Zd\n", + RSBAC_JAIL_IPC_ACI_VERSION, sizeof(rsbac_jail_id_t)); +#endif + seq_printf(m, + "\nUSER lists:\nGEN aci version is %u, aci entry size is %Zd\n", + RSBAC_GEN_USER_ACI_VERSION, + sizeof(struct rsbac_gen_user_aci_t)); +#if defined(CONFIG_RSBAC_MAC) + seq_printf(m, + "MAC aci version is %u, aci entry size is %Zd\n", + RSBAC_MAC_USER_ACI_VERSION, + sizeof(struct rsbac_mac_user_aci_t)); +#endif +#if defined(CONFIG_RSBAC_DAZ) + seq_printf(m, + "DAZ aci version is %u, aci entry size is %Zd\n", + RSBAC_DAZ_USER_ACI_VERSION, + sizeof(rsbac_system_role_int_t)); +#endif +#if defined(CONFIG_RSBAC_RC) + seq_printf(m, + "RC aci version is %u, aci entry size is %Zd\n", + RSBAC_RC_USER_ACI_VERSION, sizeof(rsbac_rc_role_id_t)); +#endif +#if defined(CONFIG_RSBAC_AUTH) + seq_printf(m, + "AUTH aci version is %u, aci entry size is %Zd\n", + RSBAC_AUTH_USER_ACI_VERSION, + sizeof(rsbac_system_role_int_t)); +#endif +#if defined(CONFIG_RSBAC_CAP) + seq_printf(m, + "CAP aci version is %u, aci entry size is %Zd\n", + RSBAC_CAP_USER_ACI_VERSION, + sizeof(struct rsbac_cap_user_aci_t)); +#endif +#if defined(CONFIG_RSBAC_JAIL) + seq_printf(m, + "JAIL aci version is %u, aci entry size is %Zd\n", + RSBAC_JAIL_USER_ACI_VERSION, + sizeof(rsbac_system_role_int_t)); +#endif +#if defined(CONFIG_RSBAC_PAX) + seq_printf(m, + "PAX aci version is %u, aci entry size is %Zd\n", + RSBAC_PAX_USER_ACI_VERSION, + sizeof(rsbac_system_role_int_t)); +#endif +#if defined(CONFIG_RSBAC_RES) + seq_printf(m, + "RES aci version is %u, aci entry size is %Zd\n", + RSBAC_RES_USER_ACI_VERSION, + sizeof(struct rsbac_res_user_aci_t)); +#endif +#if defined(CONFIG_RSBAC_UDF) + seq_printf(m, + "UDF aci version is %u, aci entry size is %Zd\n", + RSBAC_UDF_USER_ACI_VERSION, + sizeof(rsbac_system_role_int_t)); +#endif + seq_printf(m, + "\nPROCESS lists:\nGEN aci version is %i, aci entry size is %Zd, default number of lists is %u\n", + RSBAC_GEN_PROCESS_ACI_VERSION, + sizeof(rsbac_request_vector_t), + 1 << RSBAC_P_LIST_HASH_BITS); +#if defined(CONFIG_RSBAC_MAC) + seq_printf(m, + "MAC aci version is %u, aci entry size is %Zd, default number of lists is %u\n", + RSBAC_MAC_PROCESS_ACI_VERSION, + sizeof(struct rsbac_mac_process_aci_t), + 1 << RSBAC_P_LIST_HASH_BITS); +#endif +#if defined(CONFIG_RSBAC_RC) + seq_printf(m, + "RC aci version is %u, aci entry size is %Zd, default number of lists is %u\n", + RSBAC_RC_PROCESS_ACI_VERSION, + sizeof(struct rsbac_rc_process_aci_t), + 1 << RSBAC_P_LIST_HASH_BITS); +#endif +#if defined(CONFIG_RSBAC_AUTH) + seq_printf(m, + "AUTH aci version is %u, aci entry size is %Zd\n", + RSBAC_AUTH_PROCESS_ACI_VERSION, + sizeof(struct rsbac_auth_process_aci_t)); +#endif +#if defined(CONFIG_RSBAC_CAP) + seq_printf(m, + "CAP aci version is %u, aci entry size is %Zd\n", + RSBAC_CAP_PROCESS_ACI_VERSION, + sizeof(struct rsbac_cap_process_aci_t)); +#endif +#if defined(CONFIG_RSBAC_JAIL) + seq_printf(m, + "JAIL aci version is %u, aci entry size is %Zd, number of lists is %u\n", + RSBAC_JAIL_PROCESS_ACI_VERSION, + sizeof(struct rsbac_jail_process_aci_t), + 1 << RSBAC_P_LIST_HASH_BITS); +#endif + +#if defined(CONFIG_RSBAC_NET_DEV) + seq_printf(m, "\nNETDEV lists:\n"); +#if defined(CONFIG_RSBAC_IND_NETDEV_LOG) + seq_printf(m, + "GEN aci version is %u, aci entry size is %Zd\n", + RSBAC_GEN_NETDEV_ACI_VERSION, + sizeof(struct rsbac_gen_netdev_aci_t)); +#endif +#if defined(CONFIG_RSBAC_RC) + seq_printf(m, + "RC aci version is %u, aci entry size is %Zd\n", + RSBAC_RC_NETDEV_ACI_VERSION, + sizeof(rsbac_rc_type_id_t)); +#endif +#endif + +#if defined(CONFIG_RSBAC_NET_OBJ) + seq_printf(m, + "\nNetwork Template list: version is %u, data size is %Zd\n", + RSBAC_NET_TEMP_VERSION, + sizeof(struct rsbac_net_temp_data_t)); + seq_printf(m, + "\nNETOBJ lists:\nGEN aci version is %u, aci entry size is %Zd\n", + RSBAC_GEN_NETOBJ_ACI_VERSION, + sizeof(struct rsbac_gen_netobj_aci_t)); +#if defined(CONFIG_RSBAC_MAC) + seq_printf(m, + "MAC aci version is %u, aci entry size is %Zd\n", + RSBAC_MAC_NETOBJ_ACI_VERSION, + sizeof(struct rsbac_mac_netobj_aci_t)); +#endif +#if defined(CONFIG_RSBAC_RC) + seq_printf(m, + "RC aci version is %u, aci entry size is %Zd\n", + RSBAC_RC_NETOBJ_ACI_VERSION, + sizeof(rsbac_rc_type_id_t)); +#endif +#endif + seq_printf(m, + "\nlog_levels array: version is %u, array size is %Zd\n", + RSBAC_LOG_LEVEL_VERSION, + R_NONE * (T_NONE + 1) * sizeof(rsbac_enum_t)); + seq_printf(m, + "\nattribute value union size is %u\n", + (int) sizeof(union rsbac_attribute_value_t)); +#ifdef CONFIG_RSBAC_FD_CACHE + seq_printf(m, + "fd cache attribute value union size is %u\n", + (int) sizeof(union rsbac_attribute_value_cache_t)); +#endif + return 0; +} + +static int versions_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, versions_proc_show, NULL); +} + +static const struct file_operations versions_proc_fops = { + .owner = THIS_MODULE, + .open = versions_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *versions; + +#ifdef CONFIG_RSBAC_NET_OBJ +static int +net_temp_proc_show(struct seq_file *m, void *v) +{ + rsbac_net_temp_id_t *temp_array; + long count; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_initialized) + return -ENOSYS; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, "Network Templates\n-----------------\n"); + count = + rsbac_list_get_all_desc(net_temp_handle, + (void **) &temp_array); + if (count > 0) { + __u32 i; + struct rsbac_net_temp_data_t data; + + for (i = 0; i < count; i++) { + if (!rsbac_list_get_data + (net_temp_handle, &temp_array[i], &data)) { + seq_printf(m, "%10u %s\n", + temp_array[i], data.name); + } + } + rsbac_kfree(temp_array); + } + seq_printf(m, "%lu templates\n", count); + return 0; +} + +static int net_temp_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, net_temp_proc_show, NULL); +} + +static const struct file_operations net_temp_proc_fops = { + .owner = THIS_MODULE, + .open = net_temp_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *net_temp; +#endif /* NET_OBJ */ + +#ifdef CONFIG_RSBAC_JAIL +static int +jails_proc_show(struct seq_file *m, void *v) +{ + rsbac_pid_t *pid_array; + struct rsbac_ipc_t *ipc_array; + u_long count = 0; + u_int i; + struct rsbac_jail_process_aci_t data; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_initialized) + return -ENOSYS; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, + "Syslog-Jail is %u\n\nJAILed Processes\n----------------\nPID Jail-ID Flags Max Caps SCD get SCD modify IP\n", + rsbac_jail_syslog_jail_id); + + count = rsbac_list_get_all_desc(process_handles.jail, + (void **) &pid_array); + if (count > 0) { + for (i = 0; i < count; i++) { + if (!rsbac_list_get_data + (process_handles.jail, + &pid_array[i], &data)) { + seq_printf(m, + "%-5u %-10u %-7u %-10i%-10u %-10u %-10u %u.%u.%u.%u\n", + pid_nr(pid_array[i]), data.id, + data.flags, + data.max_caps.cap[1], + data.max_caps.cap[0], + data.scd_get, + data.scd_modify, + NIPQUAD(data.ip)); + } + } + rsbac_kfree(pid_array); + } + seq_printf(m, "%lu jailed processes\n", count); + seq_printf(m, + "\nJAIL IPCs\n---------\nType IPC-ID Jail-ID\n"); + + count = + rsbac_list_get_all_desc(ipc_handles.jail, + (void **) &ipc_array); + if (count > 0) { + __u32 i; + rsbac_jail_id_t data; + char tmp[RSBAC_MAXNAMELEN]; + + for (i = 0; i < count; i++) { + if (!rsbac_list_get_data + (ipc_handles.jail, &ipc_array[i], &data)) { + seq_printf(m, + "%-10s %-10lu %-10u\n", + get_ipc_target_name(tmp, + ipc_array + [i].type), + ipc_array[i].id.id_nr, data); + } + } + rsbac_kfree(ipc_array); + } + seq_printf(m, "%lu JAIL IPCs\n", count); + return 0; +} + +static int jails_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, jails_proc_show, NULL); +} + +static const struct file_operations jails_proc_fops = { + .owner = THIS_MODULE, + .open = jails_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *jails; + +#endif /* JAIL */ + +#ifdef CONFIG_RSBAC_PAX +static int +pax_proc_show(struct seq_file *m, void *v) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_initialized) + return -ENOSYS; + + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + seq_puts(m, "RSBAC PaX module\n----------------\n"); + seq_printf(m, "%li user list items.\n", rsbac_list_count(user_handles.pax)); + return 0; +} + +static int pax_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, pax_proc_show, NULL); +} + +static const struct file_operations pax_proc_fops = { + .owner = THIS_MODULE, + .open = pax_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *pax; +#endif + +static int register_all_rsbac_proc(void) +{ + proc_rsbac_root_p = proc_mkdir_mode("rsbac-info", + S_IFDIR | S_IRUGO | S_IXUGO, + NULL); + if (!proc_rsbac_root_p) + return -RSBAC_ECOULDNOTADDITEM; + + proc_rsbac_backup_p = proc_mkdir_mode("backup", + S_IFDIR | S_IRUGO | + S_IXUGO, + proc_rsbac_root_p); + if (!proc_rsbac_backup_p) + return -RSBAC_ECOULDNOTADDITEM; + + devices = proc_create("devices", S_IFREG | S_IRUGO, proc_rsbac_root_p, &devices_proc_fops); + stats = proc_create("stats", S_IFREG | S_IRUGO, proc_rsbac_root_p, &stats_proc_fops); + active = proc_create("active", S_IFREG | S_IRUGO, proc_rsbac_root_p, &active_proc_fops); +#ifdef CONFIG_RSBAC_XSTATS + xstats = proc_create("xstats", S_IFREG | S_IRUGO, proc_rsbac_root_p, &xstats_proc_fops); +#endif +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) + auto_write = proc_create("auto_write", S_IFREG | S_IRUGO | S_IWUGO, proc_rsbac_root_p, &auto_write_proc_fops); +#endif + versions = proc_create("versions", S_IFREG | S_IRUGO, proc_rsbac_root_p, &versions_proc_fops); +#ifdef CONFIG_RSBAC_NET_OBJ + net_temp = proc_create("net_temp", S_IFREG | S_IRUGO, proc_rsbac_root_p, &net_temp_proc_fops); +#endif +#ifdef CONFIG_RSBAC_JAIL + jails = proc_create("jails", S_IFREG | S_IRUGO, proc_rsbac_root_p, &jails_proc_fops); +#endif +#ifdef CONFIG_RSBAC_PAX + pax = proc_create("pax", S_IFREG | S_IRUGO, proc_rsbac_root_p, &pax_proc_fops); +#endif + + return 0; +} + + +/************************************************* */ +/* RSBAC daemon */ +/************************************************* */ + +/************************************************************************** */ +/* Initialization, including ACI restoration for root device from disk. */ +/* After this call, all ACI is kept in memory for performance reasons, */ +/* but user and file/dir object ACI are written to disk on every change. */ + +/* Since there can be no access to aci data structures before init, */ +/* rsbac_do_init() will initialize all rw-spinlocks to unlocked. */ + +/* DAZ init prototype */ +#if defined(CONFIG_RSBAC_DAZ) +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_init_daz(void); +#else +int __init rsbac_init_daz(void); +#endif +#endif + +/* UDF init prototype */ +#if defined(CONFIG_RSBAC_UDF) +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_init_udf(void); +#else +int __init rsbac_init_udf(void); +#endif +#endif + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +static void walk_delayed_kfree(void) +{ + struct rsbac_delayed_kfree_list_t * item; + struct rsbac_delayed_kfree_list_t * last_item; + struct rsbac_delayed_kfree_list_t * next_item; + rsbac_time_t now = RSBAC_CURRENT_TIME; +#ifdef CONFIG_RSBAC_XSTATS + u_int tmp_delayed_kfree_used; +#endif +// u_int count = 0; + + spin_lock(&delayed_kfree_lock); + item = delayed_kfree_first; + last_item = delayed_kfree_last; + delayed_kfree_first = delayed_kfree_last = NULL; +#ifdef CONFIG_RSBAC_XSTATS + tmp_delayed_kfree_used = delayed_kfree_used; + delayed_kfree_used = 0; +#endif + spin_unlock(&delayed_kfree_lock); + + while (item && (item->max_age < now)) { + next_item = item->next; + rsbac_kfree(item->data); + rsbac_sfree(delayed_kfree_item_slab, item); + item = next_item; +#ifdef CONFIG_RSBAC_XSTATS + tmp_delayed_kfree_used--; +#endif +// count++; + } + if (item) { +// rsbac_printk(KERN_DEBUG "walk_delayed_kfree() kfree'd %u items at %u, next is at %u\n", count, now, item->max_age); + spin_lock(&delayed_kfree_lock); + if (delayed_kfree_first) { + last_item->next = delayed_kfree_first; + delayed_kfree_first = item; + } else { + delayed_kfree_first = item; + delayed_kfree_last = last_item; + } +#ifdef CONFIG_RSBAC_XSTATS + delayed_kfree_used += tmp_delayed_kfree_used; +#endif + spin_unlock(&delayed_kfree_lock); +// } else if (count) { +// rsbac_printk(KERN_DEBUG "walk_delayed_kfree() kfree'd all %u items at %u\n", count, now); + } +} +#endif + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int register_dev_lists(void) +#else +static int __init register_dev_lists(void) +#endif +{ + int err = 0; + struct rsbac_list_info_t *list_info_p; + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } + rsbac_pr_debug(ds, "registering DEV lists\n"); + { + struct rsbac_gen_dev_aci_t def_aci = DEFAULT_GEN_DEV_ACI; + + list_info_p->version = RSBAC_GEN_DEV_ACI_VERSION; + list_info_p->key = RSBAC_GEN_DEV_ACI_KEY; + list_info_p->desc_size = sizeof(struct rsbac_dev_desc_t); + list_info_p->data_size = + sizeof(struct rsbac_gen_dev_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &dev_handles.gen, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + dev_compare, + gen_dev_get_conv, &def_aci, + RSBAC_GEN_ACI_DEV_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_dev, + NULL); + if (err) { + registration_error(err, "DEV General"); + } + } +#if defined(CONFIG_RSBAC_MAC) + { + struct rsbac_mac_dev_aci_t def_aci = DEFAULT_MAC_DEV_ACI; + + list_info_p->version = RSBAC_MAC_DEV_ACI_VERSION; + list_info_p->key = RSBAC_MAC_DEV_ACI_KEY; + list_info_p->desc_size = sizeof(struct rsbac_dev_desc_t); + list_info_p->data_size = + sizeof(struct rsbac_mac_dev_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &dev_handles.mac, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + dev_compare, + mac_dev_get_conv, &def_aci, + RSBAC_MAC_ACI_DEV_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_dev, + NULL); + if (err) { + registration_error(err, "DEV MAC"); + } + } +#endif +#if defined(CONFIG_RSBAC_RC) + { + rsbac_rc_type_id_t def_major_aci = RSBAC_RC_GENERAL_TYPE; + rsbac_rc_type_id_t def_aci = RC_type_inherit_parent; + + list_info_p->version = RSBAC_RC_DEV_ACI_VERSION; + list_info_p->key = RSBAC_RC_DEV_ACI_KEY; + list_info_p->desc_size = sizeof(struct rsbac_dev_desc_t); + list_info_p->data_size = sizeof(rsbac_rc_type_id_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &dev_major_handles.rc, + list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + dev_major_compare, + rc_dev_get_conv, &def_major_aci, + RSBAC_RC_ACI_DEV_MAJOR_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_dev, + NULL); + if (err) { + registration_error(err, "DEV major RC"); + } + list_info_p->version = RSBAC_RC_DEV_ACI_VERSION; + list_info_p->key = RSBAC_RC_DEV_ACI_KEY; + list_info_p->desc_size = sizeof(struct rsbac_dev_desc_t); + list_info_p->data_size = sizeof(rsbac_rc_type_id_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &dev_handles.rc, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + dev_compare, + rc_dev_get_conv, &def_aci, + RSBAC_RC_ACI_DEV_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_dev, + NULL); + if (err) { + registration_error(err, "DEV RC"); + } + } +#endif + + rsbac_kfree(list_info_p); + return err; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int register_ipc_lists(void) +#else +static int __init register_ipc_lists(void) +#endif +{ + int err = 0; + struct rsbac_list_info_t *list_info_p; + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } + rsbac_pr_debug(ds, "registering IPC lists\n"); +#if defined(CONFIG_RSBAC_MAC) + { + struct rsbac_mac_ipc_aci_t def_aci = DEFAULT_MAC_IPC_ACI; + + list_info_p->version = RSBAC_MAC_IPC_ACI_VERSION; + list_info_p->key = RSBAC_MAC_IPC_ACI_KEY; + list_info_p->desc_size = sizeof(struct rsbac_ipc_t); + list_info_p->data_size = + sizeof(struct rsbac_mac_ipc_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &ipc_handles.mac, + list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_OWN_SLAB | RSBAC_LIST_AUTO_HASH_RESIZE, + ipc_compare, + NULL, + &def_aci, + RSBAC_MAC_ACI_IPC_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_ipc, + NULL); + if (err) { + registration_error(err, "IPC MAC"); + } + } +#endif +#if defined(CONFIG_RSBAC_RC) + { + rsbac_rc_type_id_t def_aci = RSBAC_RC_GENERAL_TYPE; + + list_info_p->version = RSBAC_RC_IPC_ACI_VERSION; + list_info_p->key = RSBAC_RC_IPC_ACI_KEY; + list_info_p->desc_size = sizeof(struct rsbac_ipc_t); + list_info_p->data_size = sizeof(rsbac_rc_type_id_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &ipc_handles.rc, + list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_OWN_SLAB | RSBAC_LIST_AUTO_HASH_RESIZE, + ipc_compare, + NULL, + &def_aci, + RSBAC_RC_ACI_IPC_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_ipc, + NULL); + if (err) { + registration_error(err, "IPC RC"); + } + } +#endif +#if defined(CONFIG_RSBAC_JAIL) + { + rsbac_jail_id_t def_aci = RSBAC_JAIL_DEF_ID; + + list_info_p->version = RSBAC_JAIL_IPC_ACI_VERSION; + list_info_p->key = RSBAC_JAIL_IPC_ACI_KEY; + list_info_p->desc_size = sizeof(struct rsbac_ipc_t); + list_info_p->data_size = sizeof(rsbac_jail_id_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &ipc_handles.jail, + list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_OWN_SLAB | RSBAC_LIST_AUTO_HASH_RESIZE, + ipc_compare, + NULL, + &def_aci, + RSBAC_JAIL_ACI_IPC_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_ipc, + NULL); + if (err) { + registration_error(err, "IPC JAIL"); + } + } +#endif + + rsbac_kfree(list_info_p); + return err; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int register_user_lists1(void) +#else +static int __init register_user_lists1(void) +#endif +{ + int err = 0; + struct rsbac_list_info_t *list_info_p; + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } + rsbac_pr_debug(ds, "registering USER lists\n"); + { + struct rsbac_gen_user_aci_t def_aci = DEFAULT_GEN_U_ACI; + + list_info_p->version = RSBAC_GEN_USER_ACI_VERSION; + list_info_p->key = RSBAC_GEN_USER_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_uid_t); + list_info_p->data_size = + sizeof(struct rsbac_gen_user_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &user_handles.gen, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | +#ifndef CONFIG_RSBAC_UM_VIRTUAL + RSBAC_LIST_DEF_DATA | +#endif + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + gen_user_get_conv, + &def_aci, + RSBAC_GEN_ACI_USER_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_uid, + NULL); + if (err) { + registration_error(err, "USER General"); + } + } +#if defined(CONFIG_RSBAC_MAC) + { + struct rsbac_mac_user_aci_t def_aci = DEFAULT_MAC_U_ACI; + + list_info_p->version = RSBAC_MAC_USER_ACI_VERSION; + list_info_p->key = RSBAC_MAC_USER_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_uid_t); + list_info_p->data_size = + sizeof(struct rsbac_mac_user_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &user_handles.mac, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | +#ifndef CONFIG_RSBAC_UM_VIRTUAL + RSBAC_LIST_DEF_DATA | +#endif + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + mac_user_get_conv, &def_aci, + RSBAC_MAC_ACI_USER_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_uid, + NULL); + if (err) { + registration_error(err, "USER MAC"); + } else + if (!rsbac_no_defaults + && !rsbac_list_count(user_handles.mac)) { + struct rsbac_mac_user_aci_t sysadm_aci = + DEFAULT_MAC_U_SYSADM_ACI; + struct rsbac_mac_user_aci_t secoff_aci = + DEFAULT_MAC_U_SECOFF_ACI; + struct rsbac_mac_user_aci_t auditor_aci = + DEFAULT_MAC_U_AUDITOR_ACI; + rsbac_uid_t user; + + rsbac_printk(KERN_WARNING "rsbac_do_init(): USER MAC ACI could not be read - generating standard entries!\n"); + user = RSBAC_SYSADM_UID; + if (rsbac_list_add + (user_handles.mac, &user, &sysadm_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SYSADM USER MAC entry could not be added!\n"); + user = RSBAC_SECOFF_UID; + if (rsbac_list_add + (user_handles.mac, &user, &secoff_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SECOFF USER MAC entry could not be added!\n"); + user = RSBAC_AUDITOR_UID; + if (rsbac_list_add + (user_handles.mac, &user, &auditor_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): AUDITOR USER MAC entry could not be added!\n"); + } + } +#endif +#if defined(CONFIG_RSBAC_DAZ) + { + rsbac_system_role_int_t def_aci = SR_user; + + list_info_p->version = RSBAC_DAZ_USER_ACI_VERSION; + list_info_p->key = RSBAC_DAZ_USER_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_uid_t); + list_info_p->data_size = sizeof(rsbac_system_role_int_t); + list_info_p->max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &user_handles.daz, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif +#ifndef CONFIG_RSBAC_UM_VIRTUAL + RSBAC_LIST_DEF_DATA | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_DEF_DATA, + NULL, + daz_user_get_conv, + &def_aci, + RSBAC_DAZ_ACI_USER_NAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "USER DAZ"); + } else + if (!rsbac_no_defaults + && !rsbac_list_count(user_handles.daz)) { + rsbac_uid_t user; + rsbac_system_role_int_t role; + + rsbac_printk(KERN_WARNING "rsbac_do_init(): USER DAZ ACI could not be read - generating standard entries!\n"); + user = RSBAC_SYSADM_UID; + role = SR_administrator; + if (rsbac_list_add(user_handles.daz, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SYSADM USER DAZ entry could not be added!\n"); + user = RSBAC_SECOFF_UID; + role = SR_security_officer; + if (rsbac_list_add(user_handles.daz, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SECOFF USER DAZ entry could not be added!\n"); + } + } +#endif +#if defined(CONFIG_RSBAC_FF) + { + rsbac_system_role_int_t def_aci = SR_user; + + list_info_p->version = RSBAC_FF_USER_ACI_VERSION; + list_info_p->key = RSBAC_FF_USER_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_uid_t); + list_info_p->data_size = sizeof(rsbac_system_role_int_t); + list_info_p->max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &user_handles.ff, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif +#ifndef CONFIG_RSBAC_UM_VIRTUAL + RSBAC_LIST_DEF_DATA | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_DEF_DATA, + NULL, + ff_user_get_conv, + &def_aci, RSBAC_FF_ACI_USER_NAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "USER FF"); + } else + if (!rsbac_no_defaults + && !rsbac_list_count(user_handles.ff)) { + rsbac_uid_t user; + rsbac_system_role_int_t role; + + rsbac_printk(KERN_WARNING "rsbac_do_init(): USER FF ACI could not be read - generating standard entries!\n"); + user = RSBAC_SYSADM_UID; + role = SR_administrator; + if (rsbac_list_add(user_handles.ff, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SYSADM USER FF entry could not be added!\n"); + user = RSBAC_SECOFF_UID; + role = SR_security_officer; + if (rsbac_list_add(user_handles.ff, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SECOFF USER FF entry could not be added!\n"); + user = RSBAC_AUDITOR_UID; + role = SR_auditor; + if (rsbac_list_add(user_handles.ff, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): AUDITOR USER FF entry could not be added!\n"); + } + } +#endif +#if defined(CONFIG_RSBAC_CAP) + { + struct rsbac_cap_user_aci_t def_aci = DEFAULT_CAP_U_ACI; + + list_info_p->version = RSBAC_CAP_USER_ACI_VERSION; + list_info_p->key = RSBAC_CAP_USER_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_uid_t); + list_info_p->data_size = + sizeof(struct rsbac_cap_user_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &user_handles.cap, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | +#ifndef CONFIG_RSBAC_UM_VIRTUAL + RSBAC_LIST_DEF_DATA | +#endif + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + cap_user_get_conv, + &def_aci, + RSBAC_CAP_ACI_USER_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_uid, + NULL); + if (err) { + registration_error(err, "USER CAP"); + } else + if (!rsbac_no_defaults + && !rsbac_list_count(user_handles.cap)) { + struct rsbac_cap_user_aci_t sysadm_aci = + DEFAULT_CAP_U_SYSADM_ACI; + struct rsbac_cap_user_aci_t secoff_aci = + DEFAULT_CAP_U_SECOFF_ACI; + struct rsbac_cap_user_aci_t auditor_aci = + DEFAULT_CAP_U_AUDITOR_ACI; + rsbac_uid_t user; + + rsbac_printk(KERN_WARNING "rsbac_do_init(): USER CAP ACI could not be read - generating standard entries!\n"); + rsbac_printk(KERN_WARNING "rsbac_do_init(): USER CAP ACI could not be read - generating standard entries!\n"); + user = RSBAC_SYSADM_UID; + if (rsbac_list_add + (user_handles.cap, &user, &sysadm_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SYSADM USER CAP entry could not be added!\n"); + user = RSBAC_SECOFF_UID; + if (rsbac_list_add + (user_handles.cap, &user, &secoff_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SECOFF USER CAP entry could not be added!\n"); + user = RSBAC_AUDITOR_UID; + if (rsbac_list_add + (user_handles.cap, &user, &auditor_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): AUDITOR USER CAP entry could not be added!\n"); + } + } +#endif +#if defined(CONFIG_RSBAC_UDF) + { + rsbac_system_role_int_t def_aci = SR_user; + + list_info_p->version = RSBAC_UDF_USER_ACI_VERSION; + list_info_p->key = RSBAC_UDF_USER_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_uid_t); + list_info_p->data_size = sizeof(rsbac_system_role_int_t); + list_info_p->max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &user_handles.udf, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif +#ifndef CONFIG_RSBAC_UM_VIRTUAL + RSBAC_LIST_DEF_DATA | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_DEF_DATA, + NULL, + NULL, + &def_aci, + RSBAC_UDF_ACI_USER_NAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "USER UDF"); + } else + if (!rsbac_no_defaults + && !rsbac_list_count(user_handles.udf)) { + rsbac_uid_t user; + rsbac_system_role_int_t role; + + rsbac_printk(KERN_WARNING "rsbac_do_init(): USER UDF ACI could not be read - generating standard entries!\n"); + user = RSBAC_SYSADM_UID; + role = SR_administrator; + if (rsbac_list_add(user_handles.udf, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SYSADM USER UDF entry could not be added!\n"); + user = RSBAC_SECOFF_UID; + role = SR_security_officer; + if (rsbac_list_add(user_handles.udf, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SECOFF USER UDF entry could not be added!\n"); + } + } +#endif + + rsbac_kfree(list_info_p); + return err; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int register_user_lists2(void) +#else +static int __init register_user_lists2(void) +#endif +{ + int err = 0; + struct rsbac_list_info_t *list_info_p; + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } + +#if defined(CONFIG_RSBAC_RC) + { + struct rsbac_rc_user_aci_t def_aci = DEFAULT_RC_U_ACI; + + list_info_p->version = RSBAC_RC_USER_ACI_VERSION; + list_info_p->key = RSBAC_RC_USER_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_uid_t); + list_info_p->data_size = + sizeof(struct rsbac_rc_user_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &user_handles.rc, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | +#ifndef CONFIG_RSBAC_UM_VIRTUAL + RSBAC_LIST_DEF_DATA | +#endif + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + rc_user_get_conv, &def_aci, + RSBAC_RC_ACI_USER_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_uid, + NULL); + if (err) { + registration_error(err, "USER RC"); + } else + if (!rsbac_no_defaults + && !rsbac_list_count(user_handles.rc)) { + rsbac_uid_t user; + struct rsbac_rc_user_aci_t sysadm_aci = + DEFAULT_RC_U_SYSADM_ACI; + struct rsbac_rc_user_aci_t secoff_aci = + DEFAULT_RC_U_SECOFF_ACI; + struct rsbac_rc_user_aci_t auditor_aci = + DEFAULT_RC_U_AUDITOR_ACI; + + rsbac_printk(KERN_WARNING "rsbac_do_init(): USER RC ACI could not be read - generating standard entries!\n"); + user = RSBAC_SYSADM_UID; + if (rsbac_list_add + (user_handles.rc, &user, &sysadm_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SYSADM USER RC entry could not be added!\n"); + user = RSBAC_SECOFF_UID; + if (rsbac_list_add + (user_handles.rc, &user, &secoff_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SECOFF USER RC entry could not be added!\n"); + user = RSBAC_AUDITOR_UID; + if (rsbac_list_add + (user_handles.rc, &user, &auditor_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): AUDITOR USER RC entry could not be added!\n"); + } + } +#endif +#if defined(CONFIG_RSBAC_AUTH) + { + rsbac_system_role_int_t def_aci = SR_user; + + list_info_p->version = RSBAC_AUTH_USER_ACI_VERSION; + list_info_p->key = RSBAC_AUTH_USER_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_uid_t); + list_info_p->data_size = sizeof(rsbac_system_role_int_t); + list_info_p->max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &user_handles.auth, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif +#ifndef CONFIG_RSBAC_UM_VIRTUAL + RSBAC_LIST_DEF_DATA | +#endif + RSBAC_LIST_PERSIST, + NULL, + auth_user_get_conv, + &def_aci, + RSBAC_AUTH_ACI_USER_NAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "USER AUTH"); + } else + if (!rsbac_no_defaults + && !rsbac_list_count(user_handles.auth)) { + rsbac_uid_t user; + rsbac_system_role_int_t role; + + rsbac_printk(KERN_WARNING "rsbac_do_init(): USER AUTH ACI could not be read - generating standard entries!\n"); + user = RSBAC_SYSADM_UID; + role = SR_administrator; + if (rsbac_list_add + (user_handles.auth, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SYSADM USER AUTH entry could not be added!\n"); + user = RSBAC_SECOFF_UID; + role = SR_security_officer; + if (rsbac_list_add + (user_handles.auth, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SECOFF USER AUTH entry could not be added!\n"); + user = RSBAC_AUDITOR_UID; + role = SR_auditor; + if (rsbac_list_add + (user_handles.auth, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): AUDITOR USER AUTH entry could not be added!\n"); + } + } +#endif /* AUTH */ +#if defined(CONFIG_RSBAC_JAIL) + { + rsbac_system_role_int_t def_aci = SR_user; + + list_info_p->version = RSBAC_JAIL_USER_ACI_VERSION; + list_info_p->key = RSBAC_JAIL_USER_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_uid_t); + list_info_p->data_size = sizeof(rsbac_system_role_int_t); + list_info_p->max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &user_handles.jail, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif +#ifndef CONFIG_RSBAC_UM_VIRTUAL + RSBAC_LIST_DEF_DATA | +#endif + RSBAC_LIST_PERSIST, + NULL, + jail_user_get_conv, + &def_aci, + RSBAC_JAIL_ACI_USER_NAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "USER JAIL"); + } else + if (!rsbac_no_defaults + && !rsbac_list_count(user_handles.jail)) { + rsbac_uid_t user; + rsbac_system_role_int_t role; + + rsbac_printk(KERN_WARNING "rsbac_do_init(): USER JAIL ACI could not be read - generating standard entries!\n"); + user = RSBAC_SYSADM_UID; + role = SR_administrator; + if (rsbac_list_add + (user_handles.jail, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SYSADM USER JAIL entry could not be added!\n"); + user = RSBAC_SECOFF_UID; + role = SR_security_officer; + if (rsbac_list_add + (user_handles.jail, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SECOFF USER JAIL entry could not be added!\n"); + } + } +#endif +#if defined(CONFIG_RSBAC_RES) + { + list_info_p->version = RSBAC_RES_USER_ACI_VERSION; + list_info_p->key = RSBAC_RES_USER_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_uid_t); + list_info_p->data_size = + sizeof(struct rsbac_res_user_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &user_handles.res, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST, + NULL, + res_user_get_conv, + NULL, + RSBAC_RES_ACI_USER_NAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "USER RES"); + } else + if (!rsbac_no_defaults + && !rsbac_list_count(user_handles.res)) { + struct rsbac_res_user_aci_t sysadm_aci = + DEFAULT_RES_U_SYSADM_ACI; + struct rsbac_res_user_aci_t secoff_aci = + DEFAULT_RES_U_SECOFF_ACI; + rsbac_uid_t user; + + rsbac_printk(KERN_WARNING "rsbac_do_init(): USER RES ACI could not be read - generating standard entries!\n"); + rsbac_printk(KERN_WARNING "rsbac_do_init(): USER RES ACI could not be read - generating standard entries!\n"); + user = RSBAC_SYSADM_UID; + if (rsbac_list_add + (user_handles.res, &user, &sysadm_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SYSADM USER RES entry could not be added!\n"); + user = RSBAC_SECOFF_UID; + if (rsbac_list_add + (user_handles.res, &user, &secoff_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SECOFF USER RES entry could not be added!\n"); + } + } +#endif +#if defined(CONFIG_RSBAC_PAX) + { + rsbac_system_role_int_t def_aci = SR_user; + + list_info_p->version = RSBAC_PAX_USER_ACI_VERSION; + list_info_p->key = RSBAC_PAX_USER_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_uid_t); + list_info_p->data_size = sizeof(rsbac_system_role_int_t); + list_info_p->max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &user_handles.pax, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif +#ifndef CONFIG_RSBAC_UM_VIRTUAL + RSBAC_LIST_DEF_DATA | +#endif + RSBAC_LIST_PERSIST, + NULL, + pax_user_get_conv, + &def_aci, + RSBAC_PAX_ACI_USER_NAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "USER PAX"); + } else + if (!rsbac_no_defaults + && !rsbac_list_count(user_handles.pax)) { + rsbac_uid_t user; + rsbac_system_role_int_t role; + + rsbac_printk(KERN_WARNING "rsbac_do_init(): USER PAX ACI could not be read - generating standard entries!\n"); + user = RSBAC_SYSADM_UID; + role = SR_administrator; + if (rsbac_list_add(user_handles.pax, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SYSADM USER PAX entry could not be added!\n"); + user = RSBAC_SECOFF_UID; + role = SR_security_officer; + if (rsbac_list_add(user_handles.pax, &user, &role)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): SECOFF USER PAX entry could not be added!\n"); + } + } +#endif + + rsbac_kfree(list_info_p); + return err; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int register_process_lists(void) +#else +static int __init register_process_lists(void) +#endif +{ + int err = 0; + struct rsbac_list_info_t *list_info_p; + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } + rsbac_pr_debug(ds, "registering PROCESS lists\n"); + { + struct rsbac_gen_process_aci_t def_aci = DEFAULT_GEN_P_ACI; + + list_info_p->version = RSBAC_GEN_PROCESS_ACI_VERSION; + list_info_p->key = RSBAC_GEN_PROCESS_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_pid_t); + list_info_p->data_size = + sizeof(struct rsbac_gen_process_aci_t); + list_info_p->max_age = 0; + gen_nr_p_hash_bits = RSBAC_P_LIST_HASH_BITS; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &process_handles.gen, + list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + NULL, &def_aci, + RSBAC_GEN_ACI_PROCESS_NAME, + RSBAC_AUTO_DEV, + gen_nr_p_hash_bits, + rsbac_list_hash_pid, + NULL); + if (err) { + registration_error(err, "PROCESS GEN"); + } + } +#if defined(CONFIG_RSBAC_MAC) + { + struct rsbac_mac_process_aci_t def_aci = DEFAULT_MAC_P_ACI; + + list_info_p->version = RSBAC_MAC_PROCESS_ACI_VERSION; + list_info_p->key = RSBAC_MAC_PROCESS_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_pid_t); + list_info_p->data_size = + sizeof(struct rsbac_mac_process_aci_t); + list_info_p->max_age = 0; + mac_nr_p_hash_bits = RSBAC_P_LIST_HASH_BITS; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &process_handles.mac, + list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + NULL, &def_aci, + RSBAC_MAC_ACI_PROCESS_NAME, + RSBAC_AUTO_DEV, + mac_nr_p_hash_bits, + rsbac_list_hash_pid, + NULL); + if (err) { + registration_error(err, "PROCESS MAC"); + } + } +#endif +#if defined(CONFIG_RSBAC_DAZ) + { + struct rsbac_daz_process_aci_t def_aci = DEFAULT_DAZ_P_ACI; + + list_info_p->version = RSBAC_DAZ_PROCESS_ACI_VERSION; + list_info_p->key = RSBAC_DAZ_PROCESS_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_pid_t); + list_info_p->data_size = + sizeof(struct rsbac_daz_process_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &process_handles.daz, + list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + &def_aci, + RSBAC_DAZ_ACI_PROCESS_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_pid, + NULL); + if (err) { + registration_error(err, "PROCESS DAZ"); + } + } +#endif +#if defined(CONFIG_RSBAC_RC) + { + struct rsbac_rc_process_aci_t def_aci = DEFAULT_RC_P_ACI; + + list_info_p->version = RSBAC_RC_PROCESS_ACI_VERSION; + list_info_p->key = RSBAC_RC_PROCESS_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_pid_t); + list_info_p->data_size = + sizeof(struct rsbac_rc_process_aci_t); + list_info_p->max_age = 0; + rc_nr_p_hash_bits = RSBAC_P_LIST_HASH_BITS; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &process_handles.rc, + list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + NULL, &def_aci, + RSBAC_RC_ACI_PROCESS_NAME, + RSBAC_AUTO_DEV, + rc_nr_p_hash_bits, + rsbac_list_hash_pid, + NULL); + if (err) { + registration_error(err, "PROCESS RC"); + } + } +#endif +#if defined(CONFIG_RSBAC_AUTH) + { + struct rsbac_auth_process_aci_t def_aci = DEFAULT_AUTH_P_ACI; + + list_info_p->version = RSBAC_AUTH_PROCESS_ACI_VERSION; + list_info_p->key = RSBAC_AUTH_PROCESS_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_pid_t); + list_info_p->data_size = + sizeof(struct rsbac_auth_process_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &process_handles.auth, + list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + &def_aci, + RSBAC_AUTH_ACI_PROCESS_NAME, + RSBAC_AUTO_DEV, +#if defined(CONFIG_RSBAC_AUTH_LEARN) + RSBAC_LIST_MIN_MAX_HASH_BITS, +#else + 0, +#endif + rsbac_list_hash_pid, + NULL); + if (err) { + registration_error(err, "PROCESS AUTH"); + } + } +#endif +#if defined(CONFIG_RSBAC_CAP) + { + struct rsbac_cap_process_aci_t def_aci = DEFAULT_CAP_P_ACI; + +#if defined(CONFIG_RSBAC_CAP_PROC_HIDE) + if (rsbac_cap_process_hiding) + def_aci.cap_process_hiding = PH_from_other_users; +#endif + list_info_p->version = RSBAC_CAP_PROCESS_ACI_VERSION; + list_info_p->key = RSBAC_CAP_PROCESS_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_pid_t); + list_info_p->data_size = + sizeof(struct rsbac_cap_process_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &process_handles.cap, + list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + &def_aci, + RSBAC_CAP_ACI_PROCESS_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_pid, + NULL); + if (err) { + registration_error(err, "PROCESS CAP"); + } + } +#endif +#if defined(CONFIG_RSBAC_JAIL) + { + struct rsbac_jail_process_aci_t def_aci = + DEFAULT_JAIL_P_ACI; + + list_info_p->version = RSBAC_JAIL_PROCESS_ACI_VERSION; + list_info_p->key = RSBAC_JAIL_PROCESS_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_pid_t); + list_info_p->data_size = + sizeof(struct rsbac_jail_process_aci_t); + list_info_p->max_age = 0; + jail_nr_p_hash_bits = RSBAC_P_LIST_HASH_BITS; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &process_handles.jail, + list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + NULL, &def_aci, + RSBAC_JAIL_ACI_PROCESS_NAME, + RSBAC_AUTO_DEV, + jail_nr_p_hash_bits, + rsbac_list_hash_pid, + NULL); + if (err) { + registration_error(err, "PROCESS JAIL"); + } + } +#endif +#if defined(CONFIG_RSBAC_UDF) + { + struct rsbac_udf_process_aci_t def_aci = DEFAULT_UDF_P_ACI; + + list_info_p->version = RSBAC_UDF_PROCESS_ACI_VERSION; + list_info_p->key = RSBAC_UDF_PROCESS_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_pid_t); + list_info_p->data_size = + sizeof(struct rsbac_udf_process_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &process_handles.udf, + list_info_p, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + &def_aci, + RSBAC_UDF_ACI_PROCESS_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_pid, + NULL); + if (err) { + registration_error(err, "PROCESS UDF"); + } + } +#endif + + rsbac_kfree(list_info_p); + return err; +} + +#ifdef CONFIG_RSBAC_UM +#ifdef CONFIG_RSBAC_INIT_DELAY +static int register_group_lists(void) +#else +static int __init register_group_lists(void) +#endif +{ + int err = 0; + struct rsbac_list_info_t *list_info_p; + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } + rsbac_pr_debug(ds, "registering GROUP lists\n"); +#if defined(CONFIG_RSBAC_RC_UM_PROT) + { + rsbac_rc_type_id_t def_aci = RSBAC_RC_GENERAL_TYPE; + + list_info_p->version = RSBAC_RC_GROUP_ACI_VERSION; + list_info_p->key = RSBAC_RC_GROUP_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_gid_t); + list_info_p->data_size = sizeof(rsbac_rc_type_id_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &group_handles.rc, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | +#ifndef CONFIG_RSBAC_UM_VIRTUAL + RSBAC_LIST_DEF_DATA | +#endif + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, + &def_aci, + RSBAC_RC_ACI_GROUP_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_gid, + NULL); + if (err) { + registration_error(err, "GROUP RC"); + } + } +#endif + + rsbac_kfree(list_info_p); + return err; +} +#endif /* UM */ + +#ifdef CONFIG_RSBAC_NET_DEV +#ifdef CONFIG_RSBAC_INIT_DELAY +static int register_netdev_lists(void) +#else +static int __init register_netdev_lists(void) +#endif +{ + int err = 0; + struct rsbac_list_info_t *list_info_p; + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } + rsbac_pr_debug(ds, "registering NETDEV lists\n"); +#if defined(CONFIG_RSBAC_IND_NETDEV_LOG) + { + struct rsbac_gen_netdev_aci_t def_aci = + DEFAULT_GEN_NETDEV_ACI; + + list_info_p->version = RSBAC_GEN_NETDEV_ACI_VERSION; + list_info_p->key = RSBAC_GEN_NETDEV_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_netdev_id_t); + list_info_p->data_size = + sizeof(struct rsbac_gen_netdev_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &netdev_handles.gen, + list_info_p, + RSBAC_LIST_BACKUP | + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA, + netdev_compare, NULL, &def_aci, + RSBAC_GEN_ACI_NETDEV_NAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "NETDEV General"); + } + } +#endif +#if defined(CONFIG_RSBAC_RC) + { + rsbac_rc_type_id_t def_aci = RSBAC_RC_GENERAL_TYPE; + + list_info_p->version = RSBAC_RC_NETDEV_ACI_VERSION; + list_info_p->key = RSBAC_RC_NETDEV_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_netdev_id_t); + list_info_p->data_size = sizeof(rsbac_rc_type_id_t); + list_info_p->max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &netdev_handles.rc, + list_info_p, + RSBAC_LIST_BACKUP | + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA, + netdev_compare, NULL, &def_aci, + RSBAC_RC_ACI_NETDEV_NAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "NETDEV RC"); + } + } +#endif + + rsbac_kfree(list_info_p); + return err; +} +#endif /* NET_DEV */ + +#ifdef CONFIG_RSBAC_NET_OBJ +#ifdef CONFIG_RSBAC_INIT_DELAY +static void fill_default_nettemp(void) +#else +static void __init fill_default_nettemp(void) +#endif +{ + rsbac_net_temp_id_t id; + struct rsbac_net_temp_data_t data; + + id = RSBAC_NET_TEMP_LNET_ID; + memset(&data, 0, sizeof(data)); + data.address_family = AF_INET; + data.type = RSBAC_NET_ANY; + data.protocol = RSBAC_NET_ANY; + strcpy(data.name, "Localnet"); + data.address.inet.nr_addr = 1; + data.address.inet.valid_bits[0] = 8; + rsbac_net_str_to_inet(RSBAC_NET_TEMP_LNET_ADDRESS, + &data.address.inet.addr[0]); + data.ports.nr_ports = 0; + rsbac_list_add(net_temp_handle, &id, &data); + + id = RSBAC_NET_TEMP_LAN_ID; + memset(&data, 0, sizeof(data)); + data.address_family = AF_INET; + data.type = RSBAC_NET_ANY; + data.protocol = RSBAC_NET_ANY; + strcpy(data.name, "Internal LAN"); + data.address.inet.nr_addr = 1; + data.address.inet.valid_bits[0] = 16; + rsbac_net_str_to_inet(RSBAC_NET_TEMP_LAN_ADDRESS, + &data.address.inet.addr[0]); + data.ports.nr_ports = 0; + rsbac_list_add(net_temp_handle, &id, &data); + + id = RSBAC_NET_TEMP_AUTO_ID; + memset(&data, 0, sizeof(data)); + data.address_family = AF_INET; + data.type = RSBAC_NET_ANY; + data.protocol = RSBAC_NET_ANY; + strcpy(data.name, "Auto-IPv4"); + data.address.inet.nr_addr = 1; + data.address.inet.valid_bits[0] = 32; + data.ports.nr_ports = 0; + rsbac_list_add(net_temp_handle, &id, &data); + + id = RSBAC_NET_TEMP_INET_ID; + memset(&data, 0, sizeof(data)); + data.address_family = AF_INET; + data.type = RSBAC_NET_ANY; + data.protocol = RSBAC_NET_ANY; + strcpy(data.name, "AF_INET"); + data.address.inet.nr_addr = 1; + data.address.inet.valid_bits[0] = 0; + data.ports.nr_ports = 0; + rsbac_list_add(net_temp_handle, &id, &data); + + id = RSBAC_NET_TEMP_INET_ID; + memset(&data, 0, sizeof(data)); + data.address_family = RSBAC_NET_ANY; + data.type = RSBAC_NET_ANY; + data.protocol = RSBAC_NET_ANY; + strcpy(data.name, "ALL"); + data.ports.nr_ports = 0; + rsbac_list_add(net_temp_handle, &id, &data); +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int register_nettemp_list(void) +#else +static int __init register_nettemp_list(void) +#endif +{ + int err = 0; + struct rsbac_list_info_t *list_info_p; + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } + rsbac_pr_debug(ds, "registering network template list\n"); + list_info_p->version = RSBAC_NET_TEMP_VERSION; + list_info_p->key = RSBAC_NET_TEMP_KEY; + list_info_p->desc_size = sizeof(rsbac_net_temp_id_t); + list_info_p->data_size = sizeof(struct rsbac_net_temp_data_t); + list_info_p->max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &net_temp_handle, + list_info_p, + RSBAC_LIST_BACKUP | + RSBAC_LIST_PERSIST, + rsbac_list_compare_u32, + net_temp_get_conv, + NULL, + RSBAC_NET_TEMP_NAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "Network Template"); + } else + if (!rsbac_no_defaults && !rsbac_list_count(net_temp_handle)) { + rsbac_printk(KERN_WARNING "rsbac_do_init(): Network Templates could not be read - generating standard entries!\n"); + fill_default_nettemp(); + } + rsbac_kfree(list_info_p); + return err; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int register_nettemp_aci_lists(void) +#else +static int __init register_nettemp_aci_lists(void) +#endif +{ + int err = 0; + struct rsbac_list_info_t *list_info_p; + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } + rsbac_pr_debug(ds, "registering NETTEMP lists\n"); +#if defined(CONFIG_RSBAC_IND_NETOBJ_LOG) + { + list_info_p->version = RSBAC_GEN_NETOBJ_ACI_VERSION; + list_info_p->key = RSBAC_GEN_NETOBJ_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_net_temp_id_t); + list_info_p->data_size = + sizeof(struct rsbac_gen_netobj_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &nettemp_handles.gen, + list_info_p, + RSBAC_LIST_BACKUP | + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, + &def_gen_netobj_aci, + RSBAC_GEN_ACI_NETTEMP_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_nettemp, + NULL); + if (err) { + registration_error(err, "NETTEMP GEN"); + } + } +#endif +#if defined(CONFIG_RSBAC_MAC) + { + struct rsbac_mac_netobj_aci_t def_aci = + DEFAULT_MAC_NETOBJ_ACI; + + list_info_p->version = RSBAC_MAC_NETOBJ_ACI_VERSION; + list_info_p->key = RSBAC_MAC_NETOBJ_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_net_temp_id_t); + list_info_p->data_size = + sizeof(struct rsbac_mac_netobj_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &nettemp_handles.mac, + list_info_p, + RSBAC_LIST_BACKUP | + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, + &def_aci, + RSBAC_MAC_ACI_NETTEMP_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_nettemp, + NULL); + if (err) { + registration_error(err, "NETTEMP MAC"); + } + } +#endif +#if defined(CONFIG_RSBAC_RC) + { + struct rsbac_rc_nettemp_aci_t def_aci = + DEFAULT_RC_NETTEMP_ACI; + + list_info_p->version = RSBAC_RC_NETOBJ_ACI_VERSION; + list_info_p->key = RSBAC_RC_NETOBJ_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_net_temp_id_t); + list_info_p->data_size = + sizeof(struct rsbac_rc_nettemp_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &nettemp_handles.rc, + list_info_p, + RSBAC_LIST_BACKUP | + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, + &def_aci, + RSBAC_RC_ACI_NETTEMP_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_nettemp, + NULL); + if (err) { + registration_error(err, "NETTEMP RC"); + } + } +#endif + + rsbac_kfree(list_info_p); + return err; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int register_netobj_lists(void) +#else +static int __init register_netobj_lists(void) +#endif +{ + int err = 0; + struct rsbac_list_info_t *list_info_p; + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } + rsbac_pr_debug(ds, "registering local NETOBJ lists\n"); +#if defined(CONFIG_RSBAC_MAC) + { + struct rsbac_mac_netobj_aci_t def_aci = + DEFAULT_MAC_NETOBJ_ACI; + + list_info_p->version = RSBAC_MAC_NETOBJ_ACI_VERSION; + list_info_p->key = RSBAC_MAC_NETOBJ_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_net_obj_id_t); + list_info_p->data_size = + sizeof(struct rsbac_mac_netobj_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &lnetobj_handles.mac, + list_info_p, + RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + NULL, + &def_aci, + RSBAC_MAC_ACI_LNETOBJ_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_netobj, + NULL); + if (err) { + registration_error(err, "LNETOBJ MAC"); + } + } +#endif +#if defined(CONFIG_RSBAC_RC) + { + rsbac_rc_type_id_t def_aci = RSBAC_RC_GENERAL_TYPE; + + list_info_p->version = RSBAC_RC_NETOBJ_ACI_VERSION; + list_info_p->key = RSBAC_RC_NETOBJ_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_net_obj_id_t); + list_info_p->data_size = sizeof(rsbac_rc_type_id_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &lnetobj_handles.rc, + list_info_p, + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + &def_aci, + RSBAC_RC_ACI_LNETOBJ_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_netobj, + NULL); + if (err) { + registration_error(err, "LNETOBJ RC"); + } + } +#endif + rsbac_pr_debug(ds, "registering remote NETOBJ lists\n"); +#if defined(CONFIG_RSBAC_MAC) + { + struct rsbac_mac_netobj_aci_t def_aci = + DEFAULT_MAC_NETOBJ_ACI; + + list_info_p->version = RSBAC_MAC_NETOBJ_ACI_VERSION; + list_info_p->key = RSBAC_MAC_NETOBJ_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_net_obj_id_t); + list_info_p->data_size = + sizeof(struct rsbac_mac_netobj_aci_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &rnetobj_handles.mac, + list_info_p, + RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + NULL, + &def_aci, + RSBAC_MAC_ACI_RNETOBJ_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_netobj, + NULL); + if (err) { + registration_error(err, "RNETOBJ MAC"); + } + } +#endif +#if defined(CONFIG_RSBAC_RC) + { + rsbac_rc_type_id_t def_aci = RSBAC_RC_GENERAL_TYPE; + + list_info_p->version = RSBAC_RC_NETOBJ_ACI_VERSION; + list_info_p->key = RSBAC_RC_NETOBJ_ACI_KEY; + list_info_p->desc_size = sizeof(rsbac_net_obj_id_t); + list_info_p->data_size = sizeof(rsbac_rc_type_id_t); + list_info_p->max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &rnetobj_handles.rc, + list_info_p, + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + &def_aci, + RSBAC_RC_ACI_RNETOBJ_NAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_netobj, + NULL); + if (err) { + registration_error(err, "RNETOBJ RC"); + } + } +#endif + + rsbac_kfree(list_info_p); + return err; +} +#endif /* NET_OBJ */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int rsbac_do_init(void) +#else +static int __init rsbac_do_init(void) +#endif +{ + int err = 0; + struct rsbac_device_list_item_t *device_p; + struct rsbac_device_list_item_t *new_device_p; + struct rsbac_list_info_t *list_info_p; + struct vfsmount *vfsmount_p; + u_int i; + + rsbac_pr_debug(stack, "free stack: %lu\n", rsbac_stack_free_space()); + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) + delayed_kfree_item_slab = rsbac_slab_create("rsbac_delayed_kfree", + sizeof(struct rsbac_delayed_kfree_list_t)); + if (!delayed_kfree_item_slab) + rsbac_printk(KERN_WARNING "rsbac_do_init(): Failed to create rsbac_delayed_kfree slab\n"); +#endif + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } +#ifdef CONFIG_RSBAC_INIT_DELAY + if (rsbac_root_vfsmount_p) + vfsmount_p = rsbac_root_vfsmount_p; + else +#endif + { + spin_lock(¤t->fs->lock); + vfsmount_p = mntget(current->fs->root.mnt); + spin_unlock(¤t->fs->lock); + } + compiled_modules[0] = (char) 0; +#ifdef CONFIG_RSBAC_REG + strcat(compiled_modules, " REG"); +#endif +#ifdef CONFIG_RSBAC_MAC +#ifdef CONFIG_RSBAC_MAC_LIGHT + strcat(compiled_modules, " MAC-L"); +#else + strcat(compiled_modules, " MAC"); +#endif +#endif +#ifdef CONFIG_RSBAC_DAZ + strcat(compiled_modules, " DAZ"); +#endif +#ifdef CONFIG_RSBAC_FF + strcat(compiled_modules, " FF"); +#endif +#ifdef CONFIG_RSBAC_RC + strcat(compiled_modules, " RC"); +#endif +#ifdef CONFIG_RSBAC_AUTH + strcat(compiled_modules, " AUTH"); +#endif +#ifdef CONFIG_RSBAC_ACL + strcat(compiled_modules, " ACL"); +#endif +#ifdef CONFIG_RSBAC_CAP + strcat(compiled_modules, " CAP"); +#endif +#ifdef CONFIG_RSBAC_JAIL + strcat(compiled_modules, " JAIL"); +#endif +#ifdef CONFIG_RSBAC_RES + strcat(compiled_modules, " RES"); +#endif +#ifdef CONFIG_RSBAC_PAX + strcat(compiled_modules, " PAX"); +#endif +#ifdef CONFIG_RSBAC_DAZ + strcat(compiled_modules, " UDF"); +#endif + rsbac_printk(KERN_INFO "rsbac_do_init(): Initializing RSBAC %s on device %02u:%02u\n", + RSBAC_VERSION, + RSBAC_MAJOR(vfsmount_p->mnt_sb->s_dev), + RSBAC_MINOR(vfsmount_p->mnt_sb->s_dev)); + /* Print banner we are initializing */ +#ifdef CONFIG_RSBAC_RMSG_NOSYSLOG + if (rsbac_nosyslog) +#endif + printk(KERN_INFO + "rsbac_do_init(): Initializing RSBAC %s\n", + RSBAC_VERSION); + + rsbac_printk(KERN_INFO "rsbac_do_init(): compiled modules:%s\n", + compiled_modules); + + device_item_slab = rsbac_slab_create_rcu("rsbac_device_item", + sizeof(struct rsbac_device_list_item_t)); + + for (i = 0; i < RSBAC_NR_DEVICE_LISTS; i++) { + device_head_p[i] = rsbac_kmalloc_clear_unlocked(sizeof(*device_head_p[i])); + if (!device_head_p[i]) { + rsbac_printk(KERN_WARNING + "rsbac_do_init(): Failed to allocate device_list_heads[%s]\n", i); + return -ENOMEM; + } + spin_lock_init(&device_list_locks[i]); + init_srcu_struct(&device_list_srcu[i]); + lockdep_set_class(&device_list_locks[i], &device_list_lock_class); + } + +#if defined(CONFIG_RSBAC_PROC) + rsbac_pr_debug(stack, "free stack before registering proc dir: %lu\n", + rsbac_stack_free_space()); + rsbac_printk(KERN_INFO "rsbac_do_init(): Registering RSBAC proc dir\n"); + register_all_rsbac_proc(); +#endif + rsbac_pr_debug(stack, "free stack before get_super: %lu\n", + rsbac_stack_free_space()); + /* read fd aci from root device */ + rsbac_pr_debug(ds, "reading aci from device " + "number %02u:%02u\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + /* create a private device item */ + new_device_p = create_device_item(vfsmount_p); + if (!new_device_p) { + rsbac_printk(KERN_CRIT + "rsbac_do_init(): Could not alloc device item!\n"); + err = -RSBAC_ECOULDNOTADDDEVICE; + goto out; + } + /* Add new_device_p to device list */ + /* OK, go on */ + device_p = add_device_item(new_device_p); + if (!device_p) { + rsbac_printk(KERN_CRIT + "rsbac_do_init(): Could not add device!\n"); + clear_device_item(new_device_p); + err = -RSBAC_ECOULDNOTADDDEVICE; + goto out; + } + + /* init lists - we need the root device_p to be initialized, but no generic list registered */ + rsbac_printk(KERN_INFO "rsbac_do_init(): Initializing generic lists\n"); + rsbac_list_init(); + + rsbac_pr_debug(stack, "free stack before init_debug: %lu\n", + rsbac_stack_free_space()); + rsbac_init_debug(); + +#ifdef CONFIG_RSBAC_FD_CACHE + if (rsbac_want_cache(device_p)) + register_fd_cache_lists(device_p); +#endif + + rsbac_printk(KERN_INFO "rsbac_do_init(): reading FD attributes from root dev\n"); + rsbac_pr_debug(stack, "free stack before reading FD lists: %lu\n", + rsbac_stack_free_space()); + + /* no locking needed, device_p is known and there can be no parallel init! */ + if ((err = register_fd_lists(device_p, rsbac_root_dev))) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_do_init(): File/Dir lists registration failed for dev %02u:%02u, err %s!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev), + get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } + rsbac_pr_debug(stack, "free stack before DEV lists registration: %lu\n", + rsbac_stack_free_space()); + register_dev_lists(); + rsbac_pr_debug(stack, "free stack before registering IPC lists: %lu\n", + rsbac_stack_free_space()); + register_ipc_lists(); + rsbac_pr_debug(stack, "free stack before registering USER lists 1: %lu\n", + rsbac_stack_free_space()); + register_user_lists1(); + rsbac_pr_debug(stack, "free stack before registering USER lists 2: %lu\n", + rsbac_stack_free_space()); + register_user_lists2(); + rsbac_pr_debug(stack, "free stack before registering PROCESS aci: %lu\n", + rsbac_stack_free_space()); + register_process_lists(); + + +#ifdef CONFIG_RSBAC_UM + rsbac_pr_debug(stack, "free stack before GROUP lists registration: %lu\n", + rsbac_stack_free_space()); + register_group_lists(); +#endif /* CONFIG_RSBAC_UM */ + +#ifdef CONFIG_RSBAC_NET_DEV + register_netdev_lists(); +#endif + +#ifdef CONFIG_RSBAC_NET_OBJ + register_nettemp_list(); + register_nettemp_aci_lists(); + register_netobj_lists(); +#endif /* NET_OBJ */ + +/* Call other init functions */ +#if defined(CONFIG_RSBAC_MAC) + rsbac_pr_debug(stack, "free stack before init_mac: %lu\n", + rsbac_stack_free_space()); + rsbac_init_mac(); +#endif + +#if defined(CONFIG_RSBAC_DAZ) + rsbac_pr_debug(stack, "free stack before init_daz: %lu\n", + rsbac_stack_free_space()); + rsbac_init_daz(); +#endif + +#if defined(CONFIG_RSBAC_RC) + rsbac_pr_debug(stack, "free stack before init_rc: %lu\n", + rsbac_stack_free_space()); + rsbac_init_rc(); +#endif + +#if defined(CONFIG_RSBAC_AUTH) + rsbac_pr_debug(stack, "free stack before init_auth: %lu\n", + rsbac_stack_free_space()); + rsbac_init_auth(); + if (rsbac_auth_enable_login) { + struct dentry *t_dentry; + struct dentry *dir_dentry = NULL; + struct rsbac_auth_fd_aci_t auth_fd_aci = + DEFAULT_AUTH_FD_ACI; + rsbac_old_inode_nr_t inode_nr; + void * inode_nr_p; + + rsbac_printk(KERN_WARNING "rsbac_do_init(): auth_enable_login is set: setting auth_may_setuid for %s\n", + RSBAC_AUTH_LOGIN_PATH); + + /* lookup filename */ + if (vfsmount_p) { + inode_lock(vfsmount_p->mnt_sb->s_root->d_inode); + dir_dentry = + rsbac_lookup_one_len(RSBAC_AUTH_LOGIN_PATH_DIR, + vfsmount_p->mnt_sb->s_root, + strlen + (RSBAC_AUTH_LOGIN_PATH_DIR)); + inode_unlock(vfsmount_p->mnt_sb->s_root->d_inode); + } + if (!dir_dentry) { + err = -RSBAC_ENOTFOUND; + rsbac_printk(KERN_WARNING "rsbac_do_init(): call to rsbac_lookup_one_len for /%s failed\n", + RSBAC_AUTH_LOGIN_PATH_DIR); + goto auth_out; + } + if (IS_ERR(dir_dentry)) { + err = PTR_ERR(dir_dentry); + rsbac_printk(KERN_WARNING "rsbac_do_init(): call to rsbac_lookup_one_len for /%s returned %i\n", + RSBAC_AUTH_LOGIN_PATH_DIR, err); + goto auth_out; + } + if (!dir_dentry->d_inode) { + err = -RSBAC_ENOTFOUND; + rsbac_printk(KERN_WARNING "rsbac_do_init(): call to rsbac_lookup_one_len for /%s failed\n", + RSBAC_AUTH_LOGIN_PATH_DIR); + dput(dir_dentry); + goto auth_out; + } + + inode_lock(dir_dentry->d_inode); + t_dentry = rsbac_lookup_one_len(RSBAC_AUTH_LOGIN_PATH_FILE, + dir_dentry, + strlen + (RSBAC_AUTH_LOGIN_PATH_FILE)); + inode_unlock(dir_dentry->d_inode); + + if (!t_dentry) { + err = -RSBAC_ENOTFOUND; + rsbac_printk(KERN_WARNING "rsbac_do_init(): call to rsbac_lookup_one_len for /%s/%s failed\n", + RSBAC_AUTH_LOGIN_PATH_DIR, + RSBAC_AUTH_LOGIN_PATH_FILE); + goto auth_out; + } + if (IS_ERR(t_dentry)) { + err = PTR_ERR(t_dentry); + rsbac_printk(KERN_WARNING "rsbac_do_init(): call to rsbac_lookup_one_len for /%s/%s returned %i\n", + RSBAC_AUTH_LOGIN_PATH_DIR, + RSBAC_AUTH_LOGIN_PATH_FILE, err); + goto auth_out; + } + if (!t_dentry->d_inode) { + err = -RSBAC_ENOTFOUND; + rsbac_printk(KERN_WARNING "rsbac_do_init(): call to rsbac_lookup_one_len for /%s/%s failed\n", + RSBAC_AUTH_LOGIN_PATH_DIR, + RSBAC_AUTH_LOGIN_PATH_FILE); + dput(t_dentry); + goto auth_out; + } + + if (!t_dentry->d_inode) { + rsbac_printk(KERN_WARNING "rsbac_do_init(): file %s not found\n", + RSBAC_AUTH_LOGIN_PATH); + err = -RSBAC_EINVALIDTARGET; + goto auth_out_dput; + } + /* is inode of type file? */ + if (!S_ISREG(t_dentry->d_inode->i_mode)) { + rsbac_printk(KERN_WARNING "rsbac_do_init(): %s is no file\n", + RSBAC_AUTH_LOGIN_PATH); + err = -RSBAC_EINVALIDTARGET; + goto auth_out_dput; + } + if (device_p->persist) { + inode_nr = t_dentry->d_inode->i_ino; + inode_nr_p = &inode_nr; + } else + inode_nr_p = &t_dentry->d_inode->i_ino; + rsbac_list_get_data(device_p->handles.auth, + inode_nr_p, + &auth_fd_aci); + auth_fd_aci.auth_may_setuid = TRUE; + if (rsbac_list_add(device_p->handles.auth, inode_nr_p, &auth_fd_aci)) { /* Adding failed! */ + rsbac_printk(KERN_WARNING "rsbac_do_init(): Could not add AUTH file/dir item!\n"); + err = -RSBAC_ECOULDNOTADDITEM; + } + + auth_out_dput: + auth_out: + { + } + } +#endif + +#if defined(CONFIG_RSBAC_ACL) + rsbac_pr_debug(stack, "free stack before init_acl: %lu\n", + rsbac_stack_free_space()); + rsbac_init_acl(); +#endif + +#if defined(CONFIG_RSBAC_UDF) + rsbac_pr_debug(stack, "free stack before init_udf: %lu\n", + rsbac_stack_free_space()); + rsbac_init_udf(); +#endif + +#if defined(CONFIG_RSBAC_UM) + rsbac_pr_debug(stack, "free stack before init_um: %lu\n", + rsbac_stack_free_space()); + rsbac_init_um(); +#endif + rsbac_pr_debug(stack, "free stack before init_adf: %lu\n", + rsbac_stack_free_space()); + rsbac_init_adf(); + +#if defined(CONFIG_RSBAC_PAX) && defined(CONFIG_PAX_HOOK_ACL_FLAGS) + pax_set_initial_flags_func = rsbac_pax_set_flags_func; +#endif + +/* Tell that rsbac is initialized */ + rsbac_allow_mounts = TRUE; + +/* Add initrd mount */ +#if 0 && defined(CONFIG_BLK_DEV_INITRD) + if (initrd_start) { + sb_p = user_get_super(MKDEV(RAMDISK_MAJOR, 0)); + if (sb_p) { + rsbac_mount(sb_p, NULL); + drop_super(sb_p); + } + sb_p = user_get_super(MKDEV(RAMDISK_MAJOR, INITRD_MINOR)); + if (sb_p) { + rsbac_mount(sb_p, NULL); + drop_super(sb_p); + } + } +#endif + +/* Add delayed mounts */ + if (rsbac_mount_list) { + u_int hash; + int srcu_idx; + struct rsbac_mount_list_t * mount_p = rsbac_mount_list; + + while (mount_p) { + /* skip root dev */ + hash = device_hash(mount_p->vfsmount_p->mnt_sb->s_dev); + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(mount_p->vfsmount_p->mnt_sb->s_dev, hash); + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + if(!device_p) { + rsbac_printk(KERN_INFO "rsbac_do_init(): mounting delayed device %02u:%02u, fs-type %s\n", + MAJOR(mount_p->vfsmount_p->mnt_sb->s_dev), + MINOR(mount_p->vfsmount_p->mnt_sb->s_dev), + mount_p->vfsmount_p->mnt_sb->s_type->name); + rsbac_mount(mount_p->vfsmount_p); + } else { + mntput(mount_p->vfsmount_p); + } + rsbac_mount_list = mount_p; + mount_p = mount_p->next; + kfree(rsbac_mount_list); + } + rsbac_mount_list = NULL; + } + +/* Tell that rsbac is initialized */ + rsbac_initialized = TRUE; + +/* Force a check, if configured */ +#ifdef CONFIG_RSBAC_INIT_CHECK + rsbac_pr_debug(stack, "free stack before rsbac_check: %lu\n", + rsbac_stack_free_space()); + rsbac_printk(KERN_INFO "rsbac_do_init(): Forcing consistency check.\n"); + rsbac_check_lists(1); +#if defined(CONFIG_RSBAC_ACL) + rsbac_check_acl(1); +#endif +#endif + + if (!current->fs) { + rsbac_printk(KERN_WARNING "rsbac_do_init(): current->fs is invalid!\n"); + err = -RSBAC_EINVALIDPOINTER; + } else { + err = 0; + } + +out: + /* We are up and running */ + rsbac_printk(KERN_INFO "rsbac_do_init(): Ready.\n"); + + kfree(list_info_p); + return err; +} + + +#ifdef CONFIG_RSBAC_INIT_THREAD +/* rsbac kernel daemon for init */ +static int rsbac_initd(void *dummy) +{ + rsbac_printk(KERN_INFO "rsbac_initd(): Initializing.\n"); + +/* Dead loop for timeout testing */ +/* while(1) { } */ + + rsbac_pr_debug(stack, "free stack before rsbac_do_init(): %lu\n", + rsbac_stack_free_space()); + /* init RSBAC */ + rsbac_do_init(); + + rsbac_pr_debug(stack, "free stack after rsbac_do_init(): %lu\n", + rsbac_stack_free_space()); + /* wake up init process */ + wake_up(&rsbacd_wait); + /* ready */ + rsbac_printk(KERN_INFO "rsbac_initd(): Exiting.\n"); + do_exit(0); + return 0; +} +#endif + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +/* rsbac kernel daemon for auto-write */ +static int rsbacd(void *dummy) +{ + struct task_struct *tsk = current; + char *name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + unsigned long list_check_time = jiffies + HZ * rsbac_list_check_interval; + + rsbac_printk(KERN_INFO "rsbacd(): Initializing.\n"); + + sys_close(0); + sys_close(1); + sys_close(2); + + rsbac_pr_debug(auto, "rsbacd(): wake up every %us\n", auto_interval / HZ); + rsbac_pr_debug(stack, "free stack: %lu\n", rsbac_stack_free_space()); + ignore_signals(tsk); + wait_event_interruptible_timeout(rsbacd_wait, 0, auto_interval); + for (;;) { + wait_event_interruptible_timeout(rsbacd_wait, 0, auto_interval); +#ifdef CONFIG_PM + if (try_to_freeze()) + continue; +#endif + + /* Cleanup lists regularly */ + if (time_after_eq(jiffies, list_check_time)) { + list_check_time = jiffies + HZ * rsbac_list_check_interval; + rsbac_pr_debug(auto, "cleaning up lists\n"); + rsbac_check_lists(1); + } + /* Write lists */ + if (rsbac_initialized && !rsbac_debug_no_write) { + int err = 0; + /* rsbac_pr_debug(auto, "calling rsbac_write()\n"); */ + down(&rsbac_write_sem); + if (!rsbac_debug_no_write) { + up(&rsbac_write_sem); + err = rsbac_write(); + } else + up(&rsbac_write_sem); + if (err < 0) { + if (name) + rsbac_printk(KERN_WARNING "rsbacd(): rsbac_write returned error %s!\n", + get_error_name(name, + err)); + else + rsbac_printk(KERN_WARNING "rsbacd(): rsbac_write returned error %i!\n", + err); + } else if (err > 0) + rsbac_pr_debug(auto, "rsbac_write() wrote %i " + "lists\n", err); + } + walk_delayed_kfree(); + } + return 0; +} +#endif + +/************************************************* */ +/* Init function */ +/************************************************* */ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac_error.h. */ + +struct rsbac_kthread_t { + struct list_head list; + rsbac_pid_t pid; +}; +struct rsbac_kthread_t * rsbac_kthread; +DEFINE_SPINLOCK(rsbac_kthread_lock); + +int rsbac_kthreads_init(void) +{ + rsbac_kthread = kmalloc(sizeof(struct rsbac_kthread_t), GFP_ATOMIC); + INIT_LIST_HEAD(&rsbac_kthread->list); + return 0; +} + +int rsbac_mark_kthread(rsbac_pid_t pid) +{ + struct rsbac_kthread_t * rsbac_kthread_new; + + if (rsbac_initialized) + return 0; + rsbac_kthread_new = kmalloc(sizeof(struct rsbac_kthread_t), GFP_ATOMIC); + rsbac_kthread_new->pid = pid; + spin_lock(&rsbac_kthread_lock); + list_add(&rsbac_kthread_new->list, &rsbac_kthread->list); + spin_unlock(&rsbac_kthread_lock); + return 0; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_init(kdev_t root_dev) +#else +int __init rsbac_init(kdev_t root_dev) +#endif +{ +#ifdef CONFIG_RSBAC_RC + struct rsbac_rc_process_aci_t rc_init_p_aci = DEFAULT_RC_P_INIT_ACI; +#endif +#ifdef CONFIG_RSBAC_INIT_THREAD + struct task_struct * rsbac_init_thread; +#endif + struct task_struct * rsbacd_thread; +#if defined(CONFIG_RSBAC_MAC) || defined(CONFIG_RSBAC_RC) + rsbac_pid_t init_pid; + struct rsbac_kthread_t * rsbac_kthread_entry; + struct list_head * p; +#endif + +#if defined(CONFIG_RSBAC_AUTO_WRITE) \ + || defined(CONFIG_RSBAC_INIT_THREAD) || defined(CONFIG_RSBAC_NO_WRITE) + rsbac_pid_t rsbacd_pid; +#endif + + if (rsbac_initialized) { + rsbac_printk(KERN_WARNING "rsbac_init(): RSBAC already initialized\n"); + return -RSBAC_EREINIT; + } + if (!current->fs) { + rsbac_printk(KERN_WARNING "rsbac_init(): current->fs is invalid!\n"); + return -RSBAC_EINVALIDPOINTER; + } + + rsbac_root_dev = root_dev; + +#if (defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0)) \ + || defined(CONFIG_RSBAC_INIT_THREAD) + /* init the rsbacd wait queue head */ + init_waitqueue_head(&rsbacd_wait); +#endif + +#ifdef CONFIG_RSBAC_INIT_THREAD +/* trigger dependency */ +#ifdef CONFIG_RSBAC_MAX_INIT_TIME +#endif + rsbac_printk(KERN_INFO "rsbac_init(): Setting init timeout to %u seconds (%u jiffies).\n", + RSBAC_MAX_INIT_TIME, RSBAC_MAX_INIT_TIME * HZ); + +/* Start rsbac thread for init */ + rsbac_init_thread = kthread_create(rsbac_initd, NULL, "rsbac_initd"); + if (IS_ERR(rsbac_init_thread)) + goto panic; + rsbacd_pid = task_pid(rsbac_init_thread); + wake_up_process(rsbac_init_thread); + rsbac_printk(KERN_INFO "rsbac_init(): Started rsbac_initd thread with pid %u\n", + pid_nr(rsbacd_pid)); + + if (!wait_event_interruptible_timeout(rsbacd_wait, rsbac_initialized, RSBAC_MAX_INIT_TIME * HZ)) { + rsbac_printk(KERN_ERR + "rsbac_init(): *** RSBAC init timed out - RSBAC not correctly initialized! ***\n"); + rsbac_printk(KERN_ERR + "rsbac_init(): *** Killing rsbac_initd! ***\n"); + sys_kill(pid_nr(rsbacd_pid), SIGKILL); + rsbac_initialized = FALSE; + } +#else + rsbac_do_init(); +#endif + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) + if (rsbac_initialized) { + /* Start rsbacd thread for auto write */ + rsbacd_thread = kthread_create(rsbacd, NULL, "rsbacd"); + if (IS_ERR(rsbacd_thread)) { + rsbac_printk(KERN_ERR + "rsbac_init(): *** Starting rsbacd thread failed with error %i! ***\n", + PTR_ERR(rsbacd_thread)); + } else { + rsbacd_pid = task_pid(rsbacd_thread); + wake_up_process(rsbacd_thread); + rsbac_printk(KERN_INFO "rsbac_init(): Started rsbacd thread with pid %u\n", + pid_nr(rsbacd_pid)); + } + } +#endif + +/* Ready. */ +#ifdef CONFIG_RSBAC_INIT_THREAD + sys_wait4(-1, NULL, WNOHANG, NULL); +#endif + +/* Add all processes to list of processes as init processes */ +#if defined(CONFIG_RSBAC_MAC) || defined(CONFIG_RSBAC_RC) + { +#ifdef CONFIG_RSBAC_MAC + struct rsbac_mac_user_aci_t * mac_u_aci_p; +#endif +#ifdef CONFIG_RSBAC_RC + struct rsbac_rc_user_aci_t * rc_u_aci_p; +#endif + rsbac_uid_t user = RSBAC_SYSADM_UID; + rsbac_pid_t pid = find_pid_ns(1, &init_pid_ns); + struct task_struct *p; + +#ifdef CONFIG_RSBAC_RC + union rsbac_target_id_t k_tid; + union rsbac_attribute_value_t k_attr_val; +#endif + + rsbac_printk(KERN_INFO "rsbac_init(): Adjusting attributes of existing processes\n"); +/* Prepare entries: change standard values to root's values */ +#ifdef CONFIG_RSBAC_MAC + mac_u_aci_p = rsbac_kmalloc_unlocked(sizeof(*mac_u_aci_p)); + if (mac_u_aci_p) { + if(!rsbac_list_get_data + (user_handles.mac, &user, mac_u_aci_p)) { + mac_init_p_aci.owner_sec_level = + mac_u_aci_p->security_level; + mac_init_p_aci.owner_initial_sec_level = + mac_u_aci_p->initial_security_level; + mac_init_p_aci.current_sec_level = + mac_u_aci_p->initial_security_level; + mac_init_p_aci.owner_min_sec_level = + mac_u_aci_p->min_security_level; + mac_init_p_aci.mac_owner_categories = + mac_u_aci_p->mac_categories; + mac_init_p_aci.mac_owner_initial_categories = + mac_u_aci_p->mac_initial_categories; + mac_init_p_aci.mac_curr_categories = + mac_u_aci_p->mac_initial_categories; + mac_init_p_aci.mac_owner_min_categories = + mac_u_aci_p->mac_min_categories; + mac_init_p_aci.min_write_open = + mac_u_aci_p->security_level; + mac_init_p_aci.max_read_open = + mac_u_aci_p->min_security_level; + mac_init_p_aci.min_write_categories = + mac_u_aci_p->mac_categories; + mac_init_p_aci.max_read_categories = + mac_u_aci_p->mac_min_categories; + mac_init_p_aci.mac_process_flags = + (mac_u_aci_p-> + mac_user_flags & RSBAC_MAC_P_FLAGS) | + RSBAC_MAC_DEF_INIT_P_FLAGS; + } + rsbac_kfree(mac_u_aci_p); + } +#endif + +/* Set process aci - first init */ +#ifdef CONFIG_RSBAC_MAC + if (rsbac_list_add + (process_handles.mac, &pid, + &mac_init_p_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): MAC ACI for Init process 1 could not be added!"); +#endif +#ifdef CONFIG_RSBAC_RC + /* Get boot role */ + if (rsbac_rc_get_boot_role(&rc_init_p_aci.rc_role)) { /* none: use root's role */ + rc_u_aci_p = rsbac_kmalloc_unlocked(sizeof(*rc_u_aci_p)); + if (rc_u_aci_p) { + if (!rsbac_list_get_data + (user_handles.rc, &user, rc_u_aci_p)) { + rc_init_p_aci.rc_role = rc_u_aci_p->rc_role; + } else { /* last resort: general role */ + rsbac_ds_get_error("rsbac_do_init", + A_rc_def_role); + rc_init_p_aci.rc_role = + RSBAC_RC_GENERAL_ROLE; + } + rsbac_kfree(rc_u_aci_p); + } + } + rc_kernel_p_aci.rc_role = rc_init_p_aci.rc_role; + if (rsbac_list_add + (process_handles.rc, &pid, + &rc_init_p_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): RC ACI for Init process 1 could not be added!"); +#endif + read_lock(&tasklist_lock); + for_each_process(p) + { + /* not for kernel and init though... */ + if ((!p->pid) || (p->pid == 1)) + continue; + pid = task_pid(p); + rsbac_pr_debug(ds, "setting aci for process %u (%s)\n", pid, p->comm); +#ifdef CONFIG_RSBAC_MAC + if (rsbac_list_add + (process_handles.mac, &pid, + &mac_init_p_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): MAC ACI for Init process %u could not be added!\n", + pid); +#endif +#ifdef CONFIG_RSBAC_RC + k_tid.process = pid; + if (rsbac_get_attr(SW_GEN, T_PROCESS, + k_tid, + A_kernel_thread, + &k_attr_val, + FALSE)) { + rsbac_printk(KERN_WARNING "rsbac_do_init(): RC ACI for Kernel thread %u could not be added!\n", pid); + } + if (k_attr_val.kernel_thread) { + if (rsbac_list_add + (process_handles.rc, + &pid, &rc_kernel_p_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): RC ACI for Kernel thread %u could not be added!\n", + pid); + } +#endif + } + read_unlock(&tasklist_lock); + } + list_for_each(p, &rsbac_kthread->list) { + rsbac_kthread_entry = list_entry(p, + struct rsbac_kthread_t, list); + if (pid_nr(rsbac_kthread_entry->pid) != 1 + && rsbac_kthread_entry->pid != rsbacd_pid) + { + read_lock(&tasklist_lock); + if(pid_task(rsbac_kthread_entry->pid, PIDTYPE_PID)) { + read_unlock(&tasklist_lock); + rsbac_pr_debug(ds, "Setting for kthread %u\n", pid_nr(rsbac_kthread_entry->pid)); + rsbac_kthread_notify(rsbac_kthread_entry->pid); + } + else { + read_unlock(&tasklist_lock); + rsbac_pr_debug(ds, "rsbac_do_init(): skipping gone away pid %u\n", + pid_nr(rsbac_kthread_entry->pid)); + } + /* kernel list implementation is for exclusive + * wizards use, let's not free it now till + * i know why it oops. consume about no + * memory anyway. michal. + */ + + /* list_del(&rsbac_kthread_entry->list); + * kfree(rsbac_kthread_entry);*/ + } + } /* explicitly mark init and rsbacd */ + init_pid = find_pid_ns(1, &init_pid_ns); +#ifdef CONFIG_RSBAC_MAC + if (rsbac_list_add(process_handles.mac, &init_pid, &mac_init_p_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): MAC ACI for \"init\" process could not be added!"); + if (rsbac_list_add(process_handles.mac, &rsbacd_pid, &mac_init_p_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): MAC ACI for \"rsbacd\" process could not be added!"); +#endif +#ifdef CONFIG_RSBAC_RC + if (rsbac_list_add(process_handles.rc, &init_pid, &rc_init_p_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): RC ACI for \"init\" process could not be added"); + if (rsbac_list_add(process_handles.rc, &rsbacd_pid, &rc_kernel_p_aci)) + rsbac_printk(KERN_WARNING "rsbac_do_init(): RC ACI for \"rsbacd\" process could not be added"); +#endif + + /*kfree(rsbac_kthread);*/ +#endif /* MAC or RC */ + + rsbac_printk(KERN_INFO "rsbac_init(): Ready.\n"); + return 0; + +#ifdef CONFIG_RSBAC_INIT_THREAD +panic: + rsbac_printk(KERN_ERR "rsbac_init(): *** RSBAC init failed to start - RSBAC not correctly initialized! ***\n"); + /* let's panic - but only when in secure mode, warn otherwise */ +#ifdef CONFIG_RSBAC_SOFTMODE + if (!rsbac_softmode) +#endif + panic("RSBAC: rsbac_init(): *** Unable to initialize - PANIC ***\n"); + return -RSBAC_EINVALIDVALUE; +#endif +} + +int rsbac_kthread_notify(rsbac_pid_t pid) +{ + if (!rsbac_initialized) + return 0; +// rsbac_printk(KERN_DEBUG "rsbac_kthread_notify: marking pid %u!\n", +// pid); +/* Set process aci */ +#ifdef CONFIG_RSBAC_MAC + if (rsbac_list_add + (process_handles.mac, &pid, &mac_init_p_aci)) + rsbac_printk(KERN_WARNING "rsbac_kthread_notify(): MAC ACI for kernel process %u could not be added!", + pid_nr(pid)); +#endif +#ifdef CONFIG_RSBAC_RC + if (rsbac_list_add + (process_handles.rc, &pid, &rc_kernel_p_aci)) + rsbac_printk(KERN_WARNING "rsbac_kthread_notify(): RC ACI for kernel process %u could not be added!", + pid_nr(pid)); +#endif + return 0; +} + +/* When mounting a device, its ACI must be read and added to the ACI lists. */ + +EXPORT_SYMBOL(rsbac_mount); +int rsbac_mount(struct vfsmount * vfsmount_p) +{ + int err = 0; + struct rsbac_device_list_item_t *device_p; + struct rsbac_device_list_item_t *new_device_p; + rsbac_boolean_t old_no_write; + u_int hash; + int srcu_idx; + + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_mount(): called from interrupt, process %u(%s)!\n", + current->pid, current->comm); + return -RSBAC_EFROMINTERRUPT; + } + if (!vfsmount_p || !vfsmount_p->mnt_sb) { + rsbac_printk(KERN_WARNING "rsbac_mount(): called with NULL pointer\n"); + return -RSBAC_EINVALIDPOINTER; + } + if (!rsbac_allow_mounts) { + struct rsbac_mount_list_t * mount_p; + +#ifdef CONFIG_RSBAC_INIT_DELAY + if (!RSBAC_MAJOR(rsbac_delayed_root) + && !RSBAC_MINOR(rsbac_delayed_root) + && rsbac_delayed_root_str[0] + ) { /* translate string to kdev_t */ + char *p = rsbac_delayed_root_str; + u_int major = 0; + u_int minor = 0; + + major = simple_strtoul(p, NULL, 0); + while ((*p != ':') && (*p != '\0')) + p++; + if (*p) { + p++; + minor = simple_strtoul(p, NULL, 0); + } + rsbac_delayed_root = RSBAC_MKDEV(major, minor); + } + if (!rsbac_no_delay_init + && ((!RSBAC_MAJOR(rsbac_delayed_root) + && !RSBAC_MINOR(rsbac_delayed_root) + && (MAJOR(vfsmount_p->mnt_sb->s_dev) > 1) + ) + || ((RSBAC_MAJOR(rsbac_delayed_root) + || RSBAC_MINOR(rsbac_delayed_root) + ) + && + ((MAJOR(vfsmount_p->mnt_sb->s_dev) == + RSBAC_MAJOR(rsbac_delayed_root)) + && (!RSBAC_MINOR(rsbac_delayed_root) + || (MINOR(vfsmount_p->mnt_sb->s_dev) == + RSBAC_MINOR(rsbac_delayed_root)) + ) + ) + ) + ) + ) { + if (RSBAC_MAJOR(rsbac_delayed_root) + || RSBAC_MINOR(rsbac_delayed_root)) { + rsbac_printk(KERN_INFO "rsbac_mount(): forcing delayed RSBAC init on DEV %02u:%02u, matching %02u:%02u!\n", + MAJOR(vfsmount_p->mnt_sb->s_dev), + MINOR(vfsmount_p->mnt_sb->s_dev), + RSBAC_MAJOR + (rsbac_delayed_root), + RSBAC_MINOR + (rsbac_delayed_root)); + } else { + rsbac_printk(KERN_INFO "rsbac_mount(): forcing delayed RSBAC init on DEV %02u:%02u!\n", + MAJOR(vfsmount_p->mnt_sb->s_dev), + MINOR(vfsmount_p->mnt_sb->s_dev)); + } + rsbac_root_vfsmount_p = vfsmount_p; + rsbac_init(vfsmount_p->mnt_sb->s_dev); + return 0; + } +#endif + + rsbac_printk(KERN_WARNING "rsbac_mount(): RSBAC not initialized while mounting DEV %02u:%02u, fs-type %s, delaying\n", + MAJOR(vfsmount_p->mnt_sb->s_dev), MINOR(vfsmount_p->mnt_sb->s_dev), + vfsmount_p->mnt_sb->s_type->name); + mount_p = kmalloc(sizeof(*mount_p), GFP_KERNEL); + if (mount_p) { + mount_p->vfsmount_p = mntget(vfsmount_p); + mount_p->next = rsbac_mount_list; + rsbac_mount_list = mount_p; + } + + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(ds, "mounting device %02u:%02u\n", + MAJOR(vfsmount_p->mnt_sb->s_dev), MINOR(vfsmount_p->mnt_sb->s_dev)); + rsbac_pr_debug(stack, "free stack: %lu\n", rsbac_stack_free_space()); + down(&rsbac_write_sem); + old_no_write = rsbac_debug_no_write; + rsbac_debug_no_write = TRUE; + up(&rsbac_write_sem); + hash = device_hash(vfsmount_p->mnt_sb->s_dev); + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(vfsmount_p->mnt_sb->s_dev, hash); + /* repeated mount? */ + if (device_p) { + rsbac_printk(KERN_INFO "rsbac_mount: repeated mount %u of device %02u:%02u\n", + device_p->mount_count, MAJOR(vfsmount_p->mnt_sb->s_dev), + MINOR(vfsmount_p->mnt_sb->s_dev)); + device_p->mount_count++; + if (!device_p->vfsmount_p) + device_p->vfsmount_p = mntget(vfsmount_p); + else + if ( real_mount(device_p->vfsmount_p)->mnt_mountpoint + && (real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_sb->s_dev == device_p->vfsmount_p->mnt_sb->s_dev) + ) { + mntput(device_p->vfsmount_p); + device_p->vfsmount_p = mntget(vfsmount_p); + } + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + } else { + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + /* OK, go on */ + new_device_p = create_device_item(vfsmount_p); + rsbac_pr_debug(stack, "after creating device item: free stack: %lu\n", + rsbac_stack_free_space()); + if (!new_device_p) { + rsbac_debug_no_write = old_no_write; + return -RSBAC_ECOULDNOTADDDEVICE; + } + + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + /* make sure to only add, if this device item has not been added in the meantime */ + device_p = lookup_device(vfsmount_p->mnt_sb->s_dev, hash); + if (device_p) { + rsbac_printk(KERN_WARNING "rsbac_mount(): mount race for device %02u:%02u detected!\n", + MAJOR(vfsmount_p->mnt_sb->s_dev), + MINOR(vfsmount_p->mnt_sb->s_dev)); + device_p->mount_count++; + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + clear_device_item(new_device_p); + } else { + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + device_p = add_device_item(new_device_p); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_mount: adding device %02u:%02u failed!\n", + MAJOR(vfsmount_p->mnt_sb->s_dev), + MINOR(vfsmount_p->mnt_sb->s_dev)); + clear_device_item(new_device_p); + rsbac_debug_no_write = old_no_write; + return -RSBAC_ECOULDNOTADDDEVICE; + } + + mntget(device_p->vfsmount_p); + } + +#ifdef CONFIG_RSBAC_FD_CACHE + if (rsbac_want_cache(new_device_p)) + register_fd_cache_lists(new_device_p); +#endif + + /* we do not lock device head - we know the device_p and hope for the best... */ + /* also, we are within kernel mount sem */ + if ((err = register_fd_lists(new_device_p, vfsmount_p->mnt_sb->s_dev))) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_mount(): File/Dir ACI registration failed for dev %02u:%02u, err %s!\n", + MAJOR(vfsmount_p->mnt_sb->s_dev), + MINOR(vfsmount_p->mnt_sb->s_dev), + get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } + rsbac_pr_debug(stack, "after registering fd lists: free stack: %lu\n", + rsbac_stack_free_space()); + } + +/* call other mount functions */ +#if defined(CONFIG_RSBAC_MAC) + rsbac_mount_mac(vfsmount_p->mnt_sb->s_dev); + rsbac_pr_debug(stack, "after mount_mac: free stack: %lu\n", + rsbac_stack_free_space()); +#endif +#if defined(CONFIG_RSBAC_AUTH) + rsbac_mount_auth(vfsmount_p->mnt_sb->s_dev); + rsbac_pr_debug(stack, "after mount_auth: free stack: %lu\n", + rsbac_stack_free_space()); +#endif +#if defined(CONFIG_RSBAC_ACL) + rsbac_mount_acl(vfsmount_p->mnt_sb->s_dev); + rsbac_pr_debug(stack, "after mount_acl: free stack: %lu\n", + rsbac_stack_free_space()); +#endif +#if defined(CONFIG_RSBAC_REG) + rsbac_mount_reg(vfsmount_p->mnt_sb->s_dev); + rsbac_pr_debug(stack, "after mount_reg: free stack: %lu\n", + rsbac_stack_free_space()); +#endif /* REG */ + + rsbac_debug_no_write = old_no_write; + return err; +} + +/* When umounting a device, its ACI must be removed from the ACI lists. */ +/* Removing the device ACI should be no problem. */ + +EXPORT_SYMBOL(rsbac_umount); +int rsbac_umount(struct vfsmount *vfsmount_p) +{ + struct rsbac_device_list_item_t *device_p; + kdev_t kdev; + u_int hash; + + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_umount(): called from interrupt, process %u(%s)!\n", + current->pid, current->comm); + return -RSBAC_EFROMINTERRUPT; + } + if (!vfsmount_p) { + rsbac_printk(KERN_WARNING "rsbac_umount(): called with NULL pointer\n"); + return -RSBAC_EINVALIDPOINTER; + } + if (!rsbac_initialized) { + rsbac_printk(KERN_WARNING "rsbac_umount(): RSBAC not initialized\n"); + if (rsbac_mount_list) { + struct rsbac_mount_list_t * mount_p; + struct rsbac_mount_list_t * prev_mount_p; + + mount_p = rsbac_mount_list; + prev_mount_p = NULL; + while (mount_p) { + if (mount_p->vfsmount_p == vfsmount_p) { + mntput(vfsmount_p); + rsbac_printk(KERN_WARNING "rsbac_umount(): found delayed mount for device %02u:%02u, removing\n", + RSBAC_MAJOR(vfsmount_p->mnt_sb->s_dev), RSBAC_MINOR(vfsmount_p->mnt_sb->s_dev)); + if (prev_mount_p) { + prev_mount_p->next = mount_p->next; + kfree (mount_p); + mount_p = prev_mount_p->next; + } else { + rsbac_mount_list = mount_p->next; + kfree (mount_p); + mount_p = rsbac_mount_list; + } + } else { + prev_mount_p = mount_p; + mount_p = mount_p->next; + } + } + } + + return -RSBAC_ENOTINITIALIZED; + } + kdev = vfsmount_p->mnt_sb->s_dev; + rsbac_pr_debug(ds, "umounting device %02u:%02u\n", + MAJOR(kdev), MINOR(kdev)); + + /* sync attribute lists */ +#if defined(CONFIG_RSBAC_AUTO_WRITE) + if (!rsbac_debug_no_write) { + down(&rsbac_write_sem); + /* recheck no_write with lock - might have been set in between */ + if (!rsbac_debug_no_write) { + up(&rsbac_write_sem); + rsbac_write(); + } else + up(&rsbac_write_sem); + } +#endif +/* call other umount functions */ +#if defined(CONFIG_RSBAC_MAC) + rsbac_umount_mac(kdev); +#endif +#if defined(CONFIG_RSBAC_AUTH) + rsbac_umount_auth(kdev); +#endif +#if defined(CONFIG_RSBAC_ACL) + rsbac_umount_acl(kdev); +#endif +#if defined(CONFIG_RSBAC_REG) + rsbac_umount_reg(kdev); +#endif + + hash = device_hash(kdev); + /* wait for write access to device_list_head */ + spin_lock(&device_list_locks[hash]); + while (!RSBAC_IS_AUTO_DEV(umount_device_in_progress)) { + DECLARE_WAIT_QUEUE_HEAD(auto_wait); + + spin_unlock(&device_list_locks[hash]); + wait_event_interruptible_timeout(auto_wait, !RSBAC_IS_AUTO_DEV(umount_device_in_progress), HZ); + spin_lock(&device_list_locks[hash]); + } + umount_device_in_progress = kdev; + device_p = lookup_device_locked(kdev, hash); + if (device_p) { + if (device_p->mount_count == 1) { + /* remove_device_item unlocks device_list_locks[hash]! */ + remove_device_item(kdev); +#ifdef CONFIG_RSBAC_FD_CACHE + unregister_fd_cache_lists(device_p); +#endif + aci_detach_fd_lists(device_p); + if (device_p->vfsmount_p) + mntput(device_p->vfsmount_p); + clear_device_item(device_p); + spin_lock(&device_list_locks[hash]); + } else { + if (device_p->mount_count > 1) { + device_p->mount_count--; + if (device_p->vfsmount_p == vfsmount_p) { + if (device_p->rsbac_dir_dentry_p) { + down(&rsbac_write_sem); + dput(device_p->rsbac_dir_dentry_p); + device_p->rsbac_dir_dentry_p = NULL; + up(&rsbac_write_sem); + } + device_p->vfsmount_p = NULL; + spin_unlock(&device_list_locks[hash]); + mntput(vfsmount_p); + rsbac_printk(KERN_WARNING "rsbac_umount: removed primary mount for device %02u:%02u, inheritance broken!\n", + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev)); + spin_lock(&device_list_locks[hash]); + } + } else { + rsbac_printk(KERN_WARNING "rsbac_umount: device %02u:%02u has mount_count < 1!\n", + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev)); + } + } + } + umount_device_in_progress = RSBAC_AUTO_DEV; + spin_unlock(&device_list_locks[hash]); + + return 0; +} + +/* On pivot_root, we must unblock the dentry tree of the old root */ +/* by putting all cached rsbac.dat dentries */ + +int rsbac_free_dat_dentries(void) +{ + struct rsbac_device_list_item_t *device_p; + u_int i; + + if (!rsbac_initialized) { + rsbac_printk(KERN_WARNING "rsbac_free_dat_dentry(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + + rsbac_printk(KERN_INFO "rsbac_free_dat_dentry(): freeing dat dir dentries\n"); + + for (i = 0; i < RSBAC_NR_DEVICE_LISTS; i++) { + spin_lock(&device_list_locks[i]); + device_p = device_head_p[i]->head; + while (device_p) { + if (device_p->rsbac_dir_dentry_p) { + dput(device_p->rsbac_dir_dentry_p); + device_p->rsbac_dir_dentry_p = NULL; + } + device_p = device_p->next; + } + spin_unlock(&device_list_locks[i]); + } + return 0; +} + +/***************************************************/ +/* We also need some status information... */ + +int rsbac_stats(void) +{ + struct rsbac_device_list_head_t *head_p; + struct rsbac_device_list_item_t *device_p; + long fd_count; + u_long fd_sum = 0; + u_long dev_sum = 0; + u_long ipc_sum = 0; + u_long user_sum = 0; + u_long process_sum = 0; +#if defined(CONFIG_RSBAC_UM) + u_long group_sum = 0; +#endif +#if defined(CONFIG_RSBAC_NET_OBJ) + u_long nettemp_sum = 0; + u_long lnetobj_sum = 0; + u_long rnetobj_sum = 0; +#endif + u_long total_sum = 0; + long tmp_count = 0; + u_int i; + int srcu_idx; + + if (!rsbac_initialized) { + rsbac_printk(KERN_WARNING "rsbac_stats(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + for (i = 0; i < RSBAC_NR_DEVICE_LISTS; i++) { + srcu_idx = srcu_read_lock(&device_list_srcu[i]); + head_p = srcu_dereference(device_head_p[i], &device_list_srcu[i]); + device_p = srcu_dereference(head_p->head, &device_list_srcu[i]); + while (device_p) { /* for all sublists */ + fd_count = rsbac_list_count(device_p->handles.gen); + if (fd_count > 0) { + rsbac_printk(", %lu GEN", fd_count); + fd_sum += fd_count; + } + +#if defined(CONFIG_RSBAC_MAC) + fd_count = rsbac_list_count(device_p->handles.mac); + if (fd_count > 0) { + rsbac_printk(", %lu MAC", fd_count); + fd_sum += fd_count; + } +#endif + +#if defined(CONFIG_RSBAC_DAZ) + fd_count = rsbac_list_count(device_p->handles.daz); + if (fd_count > 0) { + rsbac_printk(", %lu DAZ", fd_count); + fd_sum += fd_count; + } +#if defined(CONFIG_RSBAC_DAZ_CACHE) + fd_count = rsbac_list_count(device_p->handles.dazs); + if (fd_count > 0) { + rsbac_printk(", %lu DAZ SCANNED", fd_count); + fd_sum += fd_count; + } +#endif +#endif + +#if defined(CONFIG_RSBAC_FF) + fd_count = rsbac_list_count(device_p->handles.ff); + if (fd_count > 0) { + rsbac_printk(", %lu FF", fd_count); + fd_sum += fd_count; + } +#endif + +#if defined(CONFIG_RSBAC_RC) + fd_count = rsbac_list_count(device_p->handles.rc); + if (fd_count > 0) { + rsbac_printk(", %lu RC", fd_count); + fd_sum += fd_count; + } +#endif + +#if defined(CONFIG_RSBAC_AUTH) + fd_count = rsbac_list_count(device_p->handles.auth); + if (fd_count > 0) { + rsbac_printk(", %lu AUTH", fd_count); + fd_sum += fd_count; + } +#endif + +#if defined(CONFIG_RSBAC_CAP) + fd_count = rsbac_list_count(device_p->handles.cap); + if (fd_count > 0) { + rsbac_printk(", %lu CAP", fd_count); + fd_sum += fd_count; + } +#endif +#if defined(CONFIG_RSBAC_RES) + fd_count = rsbac_list_count(device_p->handles.res); + if (fd_count > 0) { + rsbac_printk(", %lu RES", fd_count); + fd_sum += fd_count; + } +#endif +#if defined(CONFIG_RSBAC_PAX) + fd_count = rsbac_list_count(device_p->handles.pax); + if (fd_count > 0) { + rsbac_printk(", %lu PAX", fd_count); + fd_sum += fd_count; + } +#endif + +#if defined(CONFIG_RSBAC_UDF) + fd_count = rsbac_list_count(device_p->handles.udf); + if (fd_count > 0) { + rsbac_printk(", %lu UDF", fd_count); + fd_sum += fd_count; + } +#if defined(CONFIG_RSBAC_DAZ_CACHE) + fd_count = rsbac_list_count(device_p->handles.udfc); + if (fd_count > 0) { + rsbac_printk(", %lu UDF CHECKED", fd_count); + fd_sum += fd_count; + } +#endif +#endif + + rsbac_printk("\n"); + device_p = srcu_dereference(device_p->next, &device_list_srcu[i]); + } + tmp_count += device_head_p[i]->count; + srcu_read_unlock(&device_list_srcu[i], srcu_idx); + } + rsbac_printk(KERN_INFO "rsbac_stats(): Sum of %u Devices with %lu fd-items\n", + tmp_count, fd_sum); + /* free access to device_list_head */ + total_sum += fd_sum; + + /* dev lists */ + tmp_count = rsbac_list_count(dev_handles.gen); + rsbac_printk(KERN_INFO "DEV items: %lu GEN", tmp_count); + dev_sum += tmp_count; +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(dev_handles.mac); + rsbac_printk(", %lu MAC", tmp_count); + dev_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(dev_major_handles.rc); + rsbac_printk(", %lu major RC", tmp_count); + dev_sum += tmp_count; + tmp_count = rsbac_list_count(dev_handles.rc); + rsbac_printk(", %lu RC", tmp_count); + dev_sum += tmp_count; +#endif + rsbac_printk("\n"); + rsbac_printk(KERN_INFO "Sum of %lu DEV items\n", dev_sum); + total_sum += dev_sum; + + /* ipc lists */ + rsbac_printk(KERN_INFO "IPC items: no GEN"); +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(ipc_handles.mac); + rsbac_printk(", %lu MAC", tmp_count); + ipc_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(ipc_handles.rc); + rsbac_printk(", %lu RC", tmp_count); + ipc_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_JAIL) + tmp_count = rsbac_list_count(ipc_handles.jail); + rsbac_printk(", %lu JAIL", tmp_count); + ipc_sum += tmp_count; +#endif + rsbac_printk("\n"); + rsbac_printk(KERN_INFO "Sum of %lu IPC items\n", ipc_sum); + total_sum += ipc_sum; + + /* user lists */ + tmp_count = rsbac_list_count(user_handles.gen); + rsbac_printk(KERN_INFO "USER items: %lu GEN", tmp_count); + user_sum += tmp_count; +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(user_handles.mac); + rsbac_printk(", %lu MAC", tmp_count); + user_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_DAZ) + tmp_count = rsbac_list_count(user_handles.daz); + rsbac_printk(", %lu DAZ", tmp_count); + user_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(user_handles.rc); + rsbac_printk(", %lu RC", tmp_count); + user_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_AUTH) + tmp_count = rsbac_list_count(user_handles.auth); + rsbac_printk(", %lu AUTH", tmp_count); + user_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_CAP) + tmp_count = rsbac_list_count(user_handles.cap); + rsbac_printk(", %lu CAP", tmp_count); + user_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_JAIL) + tmp_count = rsbac_list_count(user_handles.jail); + rsbac_printk(", %lu JAIL", tmp_count); + user_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RES) + tmp_count = rsbac_list_count(user_handles.res); + rsbac_printk(", %lu RES", tmp_count); + user_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_PAX) + tmp_count = rsbac_list_count(user_handles.pax); + rsbac_printk(", %lu PAX", tmp_count); + user_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_UDF) + tmp_count = rsbac_list_count(user_handles.udf); + rsbac_printk(", %lu UDF", tmp_count); + user_sum += tmp_count; +#endif + rsbac_printk("\n"); + rsbac_printk(KERN_INFO "Sum of %lu USER items\n", user_sum); + total_sum += user_sum; + + /* process lists */ + tmp_count = rsbac_list_count(process_handles.gen); + rsbac_printk(KERN_INFO "PROCESS items: %lu GEN", tmp_count); + process_sum += tmp_count; +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(process_handles.mac); + rsbac_printk(", %lu MAC", tmp_count); + process_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_DAZ) + tmp_count = rsbac_list_count(process_handles.daz); + rsbac_printk(", %lu DAZ", tmp_count); + process_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(process_handles.rc); + rsbac_printk(", %lu RC", tmp_count); + process_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_AUTH) + tmp_count = rsbac_list_count(process_handles.auth); + rsbac_printk(", %lu AUTH", tmp_count); + process_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_CAP) + tmp_count = rsbac_list_count(process_handles.cap); + rsbac_printk(", %lu CAP", tmp_count); + process_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_JAIL) + tmp_count = rsbac_list_count(process_handles.jail); + rsbac_printk(", %lu JAIL", tmp_count); + process_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_UDF) + tmp_count = rsbac_list_count(process_handles.udf); + rsbac_printk(", %lu UDF", tmp_count); + process_sum += tmp_count; +#endif + rsbac_printk("\n"); + rsbac_printk(KERN_INFO "Sum of %lu PROCESS items\n", process_sum); + total_sum += process_sum; + +#if defined(CONFIG_RSBAC_UM) + /* group lists */ + rsbac_printk(KERN_INFO "GROUP items: "); +#if defined(CONFIG_RSBAC_RC_UM_PROT) + tmp_count = rsbac_list_count(group_handles.rc); + rsbac_printk("%lu RC", tmp_count); + user_sum += tmp_count; +#endif + rsbac_printk("\n"); + rsbac_printk(KERN_INFO "Sum of %lu GROUP items\n", group_sum); + total_sum += group_sum; +#endif + +#if defined(CONFIG_RSBAC_NET_OBJ) + /* nettemp lists */ + rsbac_printk(KERN_INFO "NETTEMP items: "); +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(nettemp_handles.mac); + rsbac_printk("%lu MAC, ", tmp_count); + nettemp_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(nettemp_handles.rc); + rsbac_printk("%lu RC, ", tmp_count); + nettemp_sum += tmp_count; +#endif + rsbac_printk("\n"); + rsbac_printk(KERN_INFO "Sum of %lu NETTEMP items\n", nettemp_sum); + total_sum += nettemp_sum; + + /* local netobj lists */ + rsbac_printk(KERN_INFO "Local NETOBJ items:"); +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(lnetobj_handles.mac); + rsbac_printk(" %lu MAC,", tmp_count); + lnetobj_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(lnetobj_handles.rc); + rsbac_printk(" %lu RC", tmp_count); + lnetobj_sum += tmp_count; +#endif + rsbac_printk("\n"); + rsbac_printk(KERN_INFO "Sum of %lu Local NETOBJ items\n", + lnetobj_sum); + total_sum += lnetobj_sum; + + /* remote netobj lists */ + rsbac_printk(KERN_INFO "Remote NETOBJ items:"); +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_list_count(rnetobj_handles.mac); + rsbac_printk(" %lu MAC,", tmp_count); + rnetobj_sum += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_list_count(rnetobj_handles.rc); + rsbac_printk(" %lu RC", tmp_count); + rnetobj_sum += tmp_count; +#endif + rsbac_printk("\n"); + rsbac_printk(KERN_INFO "Sum of %lu Remote NETOBJ items\n", + rnetobj_sum); + total_sum += rnetobj_sum; +#endif /* NET_OBJ */ + + rsbac_printk(KERN_INFO "Total of %lu registered rsbac-items\n", total_sum); + + rsbac_printk(KERN_INFO "adf_request calls: file: %lu, dir: %lu, fifo: %lu, symlink: %lu, dev: %lu, ipc: %lu, scd: %lu, user: %lu, process: %lu, netdev: %lu, nettemp: %lu, netobj: %lu, unixsock: %lu\n", + rsbac_adf_request_count[T_FILE], + rsbac_adf_request_count[T_DIR], + rsbac_adf_request_count[T_FIFO], + rsbac_adf_request_count[T_SYMLINK], + rsbac_adf_request_count[T_DEV], + rsbac_adf_request_count[T_IPC], + rsbac_adf_request_count[T_SCD], + rsbac_adf_request_count[T_USER], + rsbac_adf_request_count[T_PROCESS], + rsbac_adf_request_count[T_NETDEV], + rsbac_adf_request_count[T_NETTEMP], + rsbac_adf_request_count[T_NETOBJ], + rsbac_adf_request_count[T_UNIXSOCK]); + rsbac_printk(KERN_INFO "adf_set_attr calls: file: %lu, dir: %lu, fifo: %lu, symlink: %lu, dev: %lu, ipc: %lu, scd: %lu, user: %lu, process: %lu, netdev: %lu, nettemp: %lu, netobj: %lu, unixsock: %lu\n", + rsbac_adf_set_attr_count[T_FILE], + rsbac_adf_set_attr_count[T_DIR], + rsbac_adf_set_attr_count[T_FIFO], + rsbac_adf_set_attr_count[T_SYMLINK], + rsbac_adf_set_attr_count[T_DEV], + rsbac_adf_set_attr_count[T_IPC], + rsbac_adf_set_attr_count[T_SCD], + rsbac_adf_set_attr_count[T_USER], + rsbac_adf_set_attr_count[T_PROCESS], + rsbac_adf_set_attr_count[T_NETDEV], + rsbac_adf_set_attr_count[T_NETTEMP], + rsbac_adf_set_attr_count[T_NETOBJ], + rsbac_adf_set_attr_count[T_UNIXSOCK]); + +#if defined(CONFIG_RSBAC_RC) + rsbac_stats_rc(); +#endif +#if defined(CONFIG_RSBAC_AUTH) + rsbac_stats_auth(); +#endif +#if defined(CONFIG_RSBAC_ACL) + rsbac_stats_acl(); +#endif + return 0; +} + +/***************************************************/ +/* rsbac_write() to write all dirty lists to disk */ +/* returns no. of lists written */ + +#if defined(CONFIG_RSBAC_AUTO_WRITE) +int rsbac_write() +{ + int err = 0; + u_int count = 0; + int subcount; + + if (!rsbac_initialized) { + rsbac_printk(KERN_WARNING "rsbac_write(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (rsbac_debug_no_write) + return 0; + + subcount = rsbac_write_lists(); + if (subcount > 0) { + count += subcount; + } else if (subcount < 0) { + err = subcount; + if (err != -RSBAC_ENOTWRITABLE) { + rsbac_printk(KERN_WARNING "rsbac_write(): rsbac_write_lists() returned error %i\n", + err); + } + } + +#if defined(CONFIG_RSBAC_REG) + subcount = rsbac_write_reg(); + if (subcount > 0) { + count += subcount; + } else if (subcount < 0) { + err = subcount; + if (err != -RSBAC_ENOTWRITABLE) { + rsbac_printk(KERN_WARNING "rsbac_write(): rsbac_write_reg() returned error %i\n", + err); + } + } +#endif + + if (count > 0) + rsbac_pr_debug(write, "total of %u lists written\n", count); + return count; +} +#endif + +/************************************************* */ +/* Attribute functions */ +/************************************************* */ + +/* A rsbac_set_attr() call for a non-existing object, user */ +/* or process entry will first add the target and then set the attribute. */ +/* Invalid combinations and trying to set security_level to or from */ +/* SL_rsbac_internal return an error. */ +/* A rsbac_get_attr() call for a non-existing target will return the */ +/* default value stored in def_aci, which should be the first enum item.*/ + +/* All these procedures handle the rw-spinlocks to protect the targets during */ +/* access. */ + +#if 0 +static int rsbac_get_parent_kdev(struct vfsmount * vfsmount_p, kdev_t * kdev_p) +{ + if (!kdev_p) + return -RSBAC_EINVALIDPOINTER; + + if ( !vfsmount_p + || !real_mount(vfsmount_p)->mnt_mountpoint + || !real_mount(vfsmount_p)->mnt_mountpoint->d_parent + || (real_mount(vfsmount_p)->mnt_mountpoint->d_parent == real_mount(vfsmount_p)->mnt_mountpoint) + || !real_mount(vfsmount_p)->mnt_mountpoint->d_sb + || !real_mount(vfsmount_p)->mnt_mountpoint->d_sb->s_dev + ) { + *kdev_p = RSBAC_ZERO_DEV; + return -RSBAC_ENOTFOUND; + } + + *kdev_p = real_mount(vfsmount_p)->mnt_mountpoint->d_sb->s_dev; + return 0; +} +#endif + +/* get the parent of a target + * returns -RSBAC_EINVALIDTARGET for non-fs targets + * and -RSBAC_ENOTFOUND, if no parent available + * In kernels >= 2.4.0, device_p->d_covers is used and the device_p item is + * properly locked for reading, so never call with a write lock held on + * device_p! + */ +#if defined(CONFIG_RSBAC_REG) +EXPORT_SYMBOL(rsbac_get_parent); +#endif +int rsbac_get_parent(enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_target_t *parent_target_p, + union rsbac_target_id_t *parent_tid_p) +{ + int srcu_idx; + + if (!parent_target_p || !parent_tid_p) + return -RSBAC_EINVALIDPOINTER; +/* + rsbac_pr_debug(ds, "Getting file/dir/fifo/symlink " + "parent for device %02u:%02u, inode %lu, dentry_p %p\n", + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), + (u_long)tid.file.inode, tid.file.dentry_p); +*/ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + break; + default: + return -RSBAC_EINVALIDTARGET; + } + + if (!tid.file.dentry_p) + return -RSBAC_ENOTFOUND; + +#ifdef CONFIG_RSBAC_XSTATS + get_parent_count++; +#endif + *parent_target_p = T_DIR; + /* Is this dentry root of a mounted device? */ + if (tid.file.dentry_p->d_sb + && (tid.file.dentry_p->d_sb->s_root == tid.file.dentry_p) + ) { + struct rsbac_device_list_item_t *device_p; + u_int hash; + + if (tid.file.device == rsbac_root_dev) + return -RSBAC_ENOTFOUND; + hash = device_hash(tid.file.device); + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(tid.file.device, hash); + if (!device_p + || !device_p->vfsmount_p + || !real_mount(device_p->vfsmount_p)->mnt_mountpoint + || !real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_parent + || (real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_parent == real_mount(device_p->vfsmount_p)->mnt_mountpoint) + || !real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_parent->d_inode + || !real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_parent->d_inode->i_ino + || !real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_sb + || !real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_sb->s_dev + || (real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_sb->s_dev == tid.file.device)) { + /* free access to device_list_head */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + return -RSBAC_ENOTFOUND; + } + parent_tid_p->dir.device = + real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_parent->d_sb->s_dev; + parent_tid_p->dir.inode = + real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_parent->d_inode->i_ino; + parent_tid_p->dir.dentry_p = real_mount(device_p->vfsmount_p)->mnt_mountpoint->d_parent; + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + } else { /* no root of filesystem -> use d_parent, dev keeps unchanged */ + if (!tid.file.dentry_p->d_parent) { + rsbac_printk(KERN_DEBUG "rsbac_get_parent(): oops - d_parent is NULL!\n"); + return -RSBAC_ENOTFOUND; + } + if (tid.file.dentry_p == tid.file.dentry_p->d_parent) { + // rsbac_printk(KERN_DEBUG "rsbac_get_parent(): oops - d_parent == dentry_p!\n"); + return -RSBAC_ENOTFOUND; + } + if (!tid.file.dentry_p->d_parent->d_inode) { + rsbac_printk(KERN_DEBUG "rsbac_get_parent(): oops - d_parent has no d_inode!\n"); + return -RSBAC_ENOTFOUND; + } + if (!tid.file.dentry_p->d_parent->d_inode->i_ino) + { + rsbac_printk(KERN_DEBUG "rsbac_get_parent(): oops - d_parent d_inode->i_ino is 0!\n"); + return -RSBAC_ENOTFOUND; + } + parent_tid_p->dir.device = tid.file.device; + parent_tid_p->dir.inode = + tid.file.dentry_p->d_parent->d_inode->i_ino; + parent_tid_p->dir.dentry_p = tid.file.dentry_p->d_parent; + } + return 0; +} + +static int get_attr_fd(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value_p, + rsbac_boolean_t inherit) +{ + int err = 0; + struct rsbac_device_list_item_t *device_p; +#ifdef CONFIG_RSBAC_FD_CACHE + kdev_t firstdev = RSBAC_ZERO_DEV; + rsbac_inode_nr_t firstinode = 0; +#endif +#if defined(CONFIG_RSBAC_FF) + rsbac_ff_flags_t ff_flags = 0; + rsbac_ff_flags_t ff_tmp_flags; + rsbac_ff_flags_t ff_mask = -1; +#endif + u_int hash; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr; + + /* use loop for inheritance - used to be recursive calls */ + for (;;) { +/* rsbac_pr_debug(ds, "Getting file/dir/fifo/" + "symlink attribute %u for device %02u:%02u, " + "inode %lu, dentry_p %p\n", attr, + RSBAC_MAJOR(tid_p->file.device), + RSBAC_MINOR(tid_p->file.device), + tid_p->file.inode, + tid_p->file.dentry_p); */ + hash = device_hash(tid_p->file.device); + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(tid_p->file.device, hash); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_get_attr(): unknown device %02u:%02u\n", + RSBAC_MAJOR(tid_p->file.device), + RSBAC_MINOR(tid_p->file.device)); + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + return -RSBAC_EINVALIDDEV; + } + +#ifdef CONFIG_RSBAC_FD_CACHE + if (inherit && !ta_number && device_p->fd_cache_handle[module]) { + rsbac_enum_t cache_attr = attr; + + if (!rsbac_list_lol_get_subdata(device_p->fd_cache_handle[module], + &tid_p->file.inode, &cache_attr, + value_p)) { +#ifdef CONFIG_RSBAC_DEBUG + char * attr_name = NULL; + char * attr_val_name = NULL; + + if (rsbac_debug_fdcache) { + attr_name = rsbac_kmalloc(32); + attr_val_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + } + if (rsbac_debug_fdcache > 1) + rsbac_pr_debug(fdcache, "Found fd cache item device %02u:%02u inode %lu module %u attr %s value %s\n", + RSBAC_MAJOR(tid_p->file.device), RSBAC_MINOR(tid_p->file.device), + tid_p->file.inode, module, get_attribute_name(attr_name, attr), get_attribute_value_name(attr_val_name, attr, value_p)); +#endif +#if defined(CONFIG_RSBAC_FF) + /* FF ff_flags is special, result needs some cleaning, if inherited */ + if (attr == A_ff_flags) + value_p->ff_flags = (value_p->ff_flags & ff_mask ) | ff_flags; +#endif + if (!RSBAC_IS_ZERO_DEV(firstdev) && firstinode) { + if (firstdev != tid_p->file.device) { + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + hash = device_hash(firstdev); + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(firstdev, hash); + } + if (device_p && device_p->fd_cache_handle[module]) { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_fdcache) { + union rsbac_attribute_value_t tmp_value; + + if (!rsbac_list_lol_get_subdata(device_p->fd_cache_handle[module], + &firstinode, &cache_attr, + &tmp_value)) { + rsbac_pr_debug(fdcache, "fd cache item already in cache: device %02u:%02u inode %lu module %u attr %s value %s (parent device %02u:%02u inode %lu was in cache)\n", + RSBAC_MAJOR(firstdev), RSBAC_MINOR(firstdev), + firstinode, module, get_attribute_name(attr_name, attr), get_attribute_value_name(attr_val_name, attr, &tmp_value), + RSBAC_MAJOR(tid_p->file.device), RSBAC_MINOR(tid_p->file.device), + tid_p->file.inode); + } + } +#endif + rsbac_pr_debug(fdcache, "Adding fd cache item device %02u:%02u inode %lu module %u attr %s value %s (parent device %02u:%02u inode %lu was in cache)\n", + RSBAC_MAJOR(firstdev), RSBAC_MINOR(firstdev), + firstinode, module, get_attribute_name(attr_name, attr), get_attribute_value_name(attr_val_name, attr, value_p), + RSBAC_MAJOR(tid_p->file.device), RSBAC_MINOR(tid_p->file.device), + tid_p->file.inode); + err = rsbac_list_lol_subadd_ttl(device_p->fd_cache_handle[module], + rsbac_fd_cache_ttl, + &firstinode, &cache_attr, + value_p); +#ifdef CONFIG_RSBAC_DEBUG + if (err && rsbac_debug_fdcache) { + rsbac_pr_debug(fdcache, "Adding fd cache item device %02u:%02u inode %lu module %u attr %s value %s (parent device %02u:%02u inode %lu was in cache) failed with error %i\n", + RSBAC_MAJOR(firstdev), RSBAC_MINOR(firstdev), + firstinode, module, get_attribute_name(attr_name, attr), get_attribute_value_name(attr_val_name, attr, value_p), + RSBAC_MAJOR(tid_p->file.device), RSBAC_MINOR(tid_p->file.device), + tid_p->file.inode, + err); + } +#endif +#ifdef CONFIG_RSBAC_XSTATS + device_p->fd_cache_misses[module]++; +#endif + } +#ifdef CONFIG_RSBAC_DEBUG + else { + if (rsbac_debug_fdcache > 1) + rsbac_pr_debug(fdcache, "Not adding fd cache item device %02u:%02u inode %lu module %u attr %s value %s (parent device %02u:%02u inode %lu was in cache)\n", + RSBAC_MAJOR(firstdev), RSBAC_MINOR(firstdev), + firstinode, module, get_attribute_name(attr_name, attr), get_attribute_value_name(attr_val_name, attr, value_p), + RSBAC_MAJOR(tid_p->file.device), RSBAC_MINOR(tid_p->file.device), + tid_p->file.inode); + } +#endif +#ifdef CONFIG_RSBAC_XSTATS + } else { + device_p->fd_cache_hits[module]++; +#endif + } +#ifdef CONFIG_RSBAC_DEBUG + if (attr_name) + rsbac_kfree(attr_name); + if (attr_val_name) + rsbac_kfree(attr_val_name); +#endif + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + return 0; + } + } +#endif + + inode_nr = tid_p->file.inode; + + switch (module) { + case SW_GEN: + { + struct rsbac_gen_fd_aci_t aci = + DEFAULT_GEN_FD_ACI; + + if (attr == A_internal) { + if (!device_p->rsbac_dir_inode + || !tid_p->file.inode) + value_p->internal = FALSE; + else if (device_p-> + rsbac_dir_inode == + tid_p->file.inode) + value_p->internal = TRUE; + else if (inherit) { + enum rsbac_target_t + parent_target; + union rsbac_target_id_t + parent_tid; + + /* inheritance possible? */ + if (!rsbac_get_parent(target, *tid_p, &parent_target, &parent_tid)) { /* yes: inherit this single level */ + if (device_p-> + rsbac_dir_inode + == + parent_tid. + file.inode) + value_p-> + internal + = TRUE; + else + value_p-> + internal + = + FALSE; + } else { + value_p->internal = + FALSE; + } + } else { + value_p->internal = FALSE; + } + + /* free access to device_list_head */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + return 0; + } + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.gen, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_log_array_low: + value_p->log_array_low = + aci.log_array_low; + break; + case A_log_array_high: + value_p->log_array_high = + aci.log_array_high; + break; + case A_log_program_based: + value_p->log_program_based = + aci.log_program_based; + break; + case A_symlink_add_remote_ip: + value_p->symlink_add_remote_ip = + aci.symlink_add_remote_ip; + break; + case A_symlink_add_uid: + value_p->symlink_add_uid = + aci.symlink_add_uid; + break; + case A_symlink_add_mac_level: + value_p->symlink_add_mac_level = + aci.symlink_add_mac_level; + break; + case A_symlink_add_rc_role: + value_p->symlink_add_rc_role = + aci.symlink_add_rc_role; + break; + case A_allow_write_exec: + value_p->allow_write_exec = + aci.allow_write_exec; + if ((value_p->allow_write_exec == + AWX_inherit) && inherit) { + enum rsbac_target_t + parent_target; + union rsbac_target_id_t + parent_tid; + + /* inheritance possible? */ + if (!rsbac_get_parent + (target, *tid_p, + &parent_target, + &parent_tid)) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (RSBAC_IS_ZERO_DEV(firstdev)) { + firstdev = device_p->id; + firstinode = tid_p->file.inode; + } +#endif + /* free access to device_list_head - see above */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + target = parent_target; + *tid_p = parent_tid; + continue; + } else { + value_p->allow_write_exec = + def_gen_root_dir_aci.allow_write_exec; + err = 0; + break; + } + } + break; + case A_fake_root_uid: + value_p->fake_root_uid = + aci.fake_root_uid; + break; + case A_auid_exempt: + value_p->auid_exempt = + aci.auid_exempt; + break; + case A_vset: + value_p->vset = aci.vset; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; + +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_fd_aci_t aci = + DEFAULT_MAC_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.mac, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_security_level: + value_p->security_level = + aci.sec_level; + if ((value_p->security_level == + SL_inherit) && inherit) { + enum rsbac_target_t + parent_target; + union rsbac_target_id_t + parent_tid; + + /* inheritance possible? */ + if (!rsbac_get_parent + (target, *tid_p, + &parent_target, + &parent_tid)) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (RSBAC_IS_ZERO_DEV(firstdev)) { + firstdev = device_p->id; + firstinode = tid_p->file.inode; + } +#endif + /* free access to device_list_head - see above */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + target = parent_target; + *tid_p = parent_tid; + continue; + } else { + value_p-> + security_level + = + def_mac_root_dir_aci. + sec_level; + err = 0; + break; + } + } + break; + case A_mac_categories: + value_p->mac_categories = + aci.mac_categories; + if ((value_p->mac_categories == + RSBAC_MAC_INHERIT_CAT_VECTOR) + && inherit) { + enum rsbac_target_t + parent_target; + union rsbac_target_id_t + parent_tid; + + /* inheritance possible? */ + if (!rsbac_get_parent + (target, *tid_p, + &parent_target, + &parent_tid)) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (RSBAC_IS_ZERO_DEV(firstdev)) { + firstdev = device_p->id; + firstinode = tid_p->file.inode; + } +#endif + /* free access to device_list_head - see above */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + target = parent_target; + *tid_p = parent_tid; + continue; + } else { + value_p-> mac_categories = def_mac_root_dir_aci.mac_categories; + err = 0; + break; + } + } + break; + case A_mac_auto: + value_p->mac_auto = aci.mac_auto; + if ((value_p->mac_auto == MA_inherit) + && inherit) { + enum rsbac_target_t + parent_target; + union rsbac_target_id_t + parent_tid; + + /* inheritance possible? */ + if (!rsbac_get_parent + (target, *tid_p, + &parent_target, + &parent_tid)) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (RSBAC_IS_ZERO_DEV(firstdev)) { + firstdev = device_p->id; + firstinode = tid_p->file.inode; + } +#endif + /* free access to device_list_head - see above */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + target = parent_target; + *tid_p = parent_tid; + continue; + } else { + value_p->mac_auto = def_mac_root_dir_aci.mac_auto; + err = 0; + break; + } + } + break; + case A_mac_prop_trusted: + value_p->mac_prop_trusted = + aci.mac_prop_trusted; + break; + case A_mac_file_flags: + value_p->mac_file_flags = + aci.mac_file_flags; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* MAC */ + +#if defined(CONFIG_RSBAC_DAZ) + case SW_DAZ: + { +#if defined(CONFIG_RSBAC_DAZ_CACHE) + if (attr == A_daz_scanned) { + err = rsbac_ta_list_get_data_ttl + (ta_number, + device_p->handles.dazs, + NULL, +#ifdef CONFIG_RSBAC_DAZ_PERSIST + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, +#else + &tid_p->file.inode, +#endif + &value_p->daz_scanned); + } else +#endif + { + struct rsbac_daz_fd_aci_t aci = + DEFAULT_DAZ_FD_ACI; + + rsbac_ta_list_get_data_ttl + (ta_number, + device_p->handles.daz, + NULL, device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_daz_scanner: + value_p->daz_scanner = + aci.daz_scanner; + break; + case A_daz_do_scan: + value_p->daz_do_scan = aci.daz_do_scan; + if( (value_p->daz_do_scan == DAZ_inherit) + && inherit) { + enum rsbac_target_t parent_target; + union rsbac_target_id_t parent_tid; + + if(!rsbac_get_parent(target, *tid_p, &parent_target, &parent_tid)) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (RSBAC_IS_ZERO_DEV(firstdev)) { + firstdev = device_p->id; + firstinode = tid_p->file.inode; + } +#endif + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + target = parent_target; + *tid_p = parent_tid; + continue; + } else { + value_p->daz_do_scan = def_daz_root_dir_aci.daz_do_scan; + err = 0; + break; + } + } + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + } + break; +#endif /* DAZ */ + +#if defined(CONFIG_RSBAC_FF) + case SW_FF: + { + switch (attr) { + case A_ff_flags: + ff_tmp_flags = RSBAC_FF_DEF; + rsbac_ta_list_get_data_ttl + (ta_number, + device_p->handles.ff, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &ff_tmp_flags); + ff_flags |= ff_tmp_flags & ff_mask; + value_p->ff_flags = ff_flags; + if ( (ff_tmp_flags & FF_add_inherited) + && inherit) { + enum rsbac_target_t parent_target; + union rsbac_target_id_t parent_tid; + + /* inheritance possible? */ + if (!rsbac_get_parent + (target, *tid_p, + &parent_target, + &parent_tid)) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (RSBAC_IS_ZERO_DEV(firstdev)) { + firstdev = device_p->id; + firstinode = tid_p->file.inode; + } +#endif + /* free access to device_list_head - see above */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + target = parent_target; + *tid_p = parent_tid; + ff_mask &= ~ (FF_no_delete_or_rename | FF_add_inherited); + ff_flags &= ~(FF_add_inherited); + continue; + } else + value_p->ff_flags &= ~(FF_add_inherited); + } + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* FF */ + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + struct rsbac_rc_fd_aci_t aci = + DEFAULT_RC_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.rc, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_rc_type_fd: + value_p->rc_type_fd = aci.rc_type_fd; + if (value_p->rc_type_fd == + RC_type_inherit_parent + && inherit) { + enum rsbac_target_t + parent_target; + union rsbac_target_id_t + parent_tid; + + /* inheritance possible? */ + if (!rsbac_get_parent + (target, *tid_p, + &parent_target, + &parent_tid)) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (RSBAC_IS_ZERO_DEV(firstdev)) { + firstdev = device_p->id; + firstinode = tid_p->file.inode; + } +#endif + /* free access to device_list_head - see above */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + target = parent_target; + *tid_p = parent_tid; + continue; + } else { + value_p->rc_type_fd = def_rc_root_dir_aci.rc_type_fd; + err = 0; + break; + } + } + break; + case A_rc_force_role: + value_p->rc_force_role = + aci.rc_force_role; + if (value_p->rc_force_role == + RC_role_inherit_parent + && inherit) { + enum rsbac_target_t + parent_target; + union rsbac_target_id_t + parent_tid; + + /* inheritance possible? */ + if (!rsbac_get_parent + (target, *tid_p, + &parent_target, + &parent_tid)) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (RSBAC_IS_ZERO_DEV(firstdev)) { + firstdev = device_p->id; + firstinode = tid_p->file.inode; + } +#endif + /* free access to device_list_head - see above */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + target = parent_target; + *tid_p = parent_tid; + continue; + } else { + value_p->rc_force_role = def_rc_root_dir_aci.rc_force_role; + err = 0; + break; + } + } + break; + case A_rc_initial_role: + value_p->rc_initial_role = + aci.rc_initial_role; + if (value_p->rc_initial_role == + RC_role_inherit_parent + && inherit) { + enum rsbac_target_t + parent_target; + union rsbac_target_id_t + parent_tid; + + /* inheritance possible? */ + if (!rsbac_get_parent + (target, *tid_p, + &parent_target, + &parent_tid)) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (RSBAC_IS_ZERO_DEV(firstdev)) { + firstdev = device_p->id; + firstinode = tid_p->file.inode; + } +#endif + /* free access to device_list_head - see above */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + target = parent_target; + *tid_p = parent_tid; + continue; + } else { + value_p->rc_initial_role = def_rc_root_dir_aci.rc_initial_role; + err = 0; + break; + } + } + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* RC */ + +#if defined(CONFIG_RSBAC_AUTH) + case SW_AUTH: + { + struct rsbac_auth_fd_aci_t aci = + DEFAULT_AUTH_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.auth, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_auth_may_setuid: + value_p->auth_may_setuid = + aci.auth_may_setuid; + break; + case A_auth_may_set_cap: + value_p->auth_may_set_cap = + aci.auth_may_set_cap; + break; + case A_auth_learn: + value_p->auth_learn = aci.auth_learn; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* AUTH */ + +#if defined(CONFIG_RSBAC_CAP) + case SW_CAP: + { + struct rsbac_cap_fd_aci_t aci = + DEFAULT_CAP_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.cap, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_min_caps: + value_p->min_caps.cap[0] = aci.min_caps.cap[0]; + value_p->min_caps.cap[1] = aci.min_caps.cap[1]; + break; + case A_max_caps: + value_p->max_caps.cap[0] = aci.max_caps.cap[0]; + value_p->max_caps.cap[1] = aci.max_caps.cap[1]; + break; + case A_cap_ld_env: + value_p->cap_ld_env = aci.cap_ld_env; + if ((value_p->cap_ld_env == LD_inherit) && inherit) { + enum rsbac_target_t parent_target; + union rsbac_target_id_t parent_tid; + if (!rsbac_get_parent(target, + *tid_p, + &parent_target, + &parent_tid)) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (RSBAC_IS_ZERO_DEV(firstdev)) { + firstdev = device_p->id; + firstinode = tid_p->file.inode; + } +#endif + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + target = parent_target; + *tid_p = parent_tid; + continue; + } else { + value_p->cap_ld_env = LD_deny; + err = 0; + break; + } + } + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* CAP */ + +#if defined(CONFIG_RSBAC_RES) + case SW_RES: + { + struct rsbac_res_fd_aci_t aci = + DEFAULT_RES_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.res, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_res_min: + memcpy(&value_p->res_array, + &aci.res_min, + sizeof(aci.res_min)); + break; + case A_res_max: + memcpy(&value_p->res_array, + &aci.res_max, + sizeof(aci.res_max)); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* RES */ + +#if defined(CONFIG_RSBAC_PAX) + case SW_PAX: + { + switch (attr) { + case A_pax_flags: + value_p->pax_flags = + RSBAC_PAX_DEF_FLAGS; + rsbac_ta_list_get_data_ttl + (ta_number, + device_p->handles.pax, + NULL, device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &value_p->pax_flags); + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* PAX */ + +#if defined(CONFIG_RSBAC_UDF) + case SW_UDF: + { +#if defined(CONFIG_RSBAC_UDF_CACHE) + if (attr == A_udf_checked) { + err = rsbac_ta_list_get_data_ttl + (ta_number, + device_p->handles.udfc, + NULL, +#ifdef CONFIG_RSBAC_UDF_PERSIST + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, +#else + &tid_p->file.inode, +#endif + &value_p->udf_checked); + } else +#endif + { + struct rsbac_udf_fd_aci_t aci = + DEFAULT_UDF_FD_ACI; + + rsbac_ta_list_get_data_ttl + (ta_number, + device_p->handles.udf, + NULL, device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_udf_checker: + value_p->udf_checker = + aci.udf_checker; + break; + case A_udf_do_check: + value_p->udf_do_check = aci.udf_do_check; + if( (value_p->udf_do_check == UDF_inherit) + && inherit) { + enum rsbac_target_t parent_target; + union rsbac_target_id_t parent_tid; + + if(!rsbac_get_parent(target, *tid_p, &parent_target, &parent_tid)) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (RSBAC_IS_ZERO_DEV(firstdev)) { + firstdev = device_p->id; + firstinode = tid_p->file.inode; + } +#endif + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + target = parent_target; + *tid_p = parent_tid; + continue; + } else { + value_p->udf_do_check + = def_udf_root_dir_aci.udf_do_check; + err = 0; + break; + } + } + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + } + break; +#endif /* UDF */ + + default: + err = -RSBAC_EINVALIDMODULE; + } +#ifdef CONFIG_RSBAC_FD_CACHE + if (!err && inherit && !ta_number) { + rsbac_enum_t cache_attr = attr; +#ifdef CONFIG_RSBAC_DEBUG + char * attr_name = NULL; + char * attr_val_name = NULL; + if (rsbac_debug_fdcache) { + attr_name = rsbac_kmalloc(32); + attr_val_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + } +#endif + if (!RSBAC_IS_ZERO_DEV(firstdev)) { + if (firstdev != tid_p->file.device) { + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + hash = device_hash(firstdev); + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(firstdev, hash); + tid_p->file.device = firstdev; + } + } + if (device_p && device_p->fd_cache_handle[module]) { + if (firstinode) + tid_p->file.inode = firstinode; + rsbac_pr_debug(fdcache, "Adding fd cache item device %02u:%02u inode %lu module %u attr %s value %s (no parent was in cache)\n", + RSBAC_MAJOR(tid_p->file.device), RSBAC_MINOR(tid_p->file.device), + tid_p->file.inode, module, get_attribute_name(attr_name, attr), get_attribute_value_name(attr_val_name, attr, value_p)); + err = rsbac_list_lol_subadd_ttl(device_p->fd_cache_handle[module], + rsbac_fd_cache_ttl, + &tid_p->file.inode, &cache_attr, + value_p); + if (err) { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_fdcache) { + rsbac_pr_debug(fdcache, "Adding fd cache item device %02u:%02u inode %lu module %u attr %s value %s (parent device %02u:%02u inode %lu was in cache) failed with error %i\n", + RSBAC_MAJOR(firstdev), RSBAC_MINOR(firstdev), + firstinode, module, get_attribute_name(attr_name, attr), get_attribute_value_name(attr_val_name, attr, value_p), + RSBAC_MAJOR(tid_p->file.device), RSBAC_MINOR(tid_p->file.device), + tid_p->file.inode, + err); + } +#endif + err = 0; + } +#ifdef CONFIG_RSBAC_XSTATS + device_p->fd_cache_misses[module]++; +#endif + } +#ifdef CONFIG_RSBAC_DEBUG + else { + if (rsbac_debug_fdcache > 1) + rsbac_pr_debug(fdcache, "Not adding fd cache item device %02u:%02u inode %lu module %u attr %s value %s (no parent was in cache)\n", + RSBAC_MAJOR(tid_p->file.device), RSBAC_MINOR(tid_p->file.device), + tid_p->file.inode, module, get_attribute_name(attr_name, attr), get_attribute_value_name(attr_val_name, attr, value_p)); + } + if (attr_name) + rsbac_kfree(attr_name); + if (attr_val_name) + rsbac_kfree(attr_val_name); +#endif + } +#endif /* CONFIG_RSBAC_FD_CACHE */ + + /* free access to device_list_head */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + /* and return */ + return err; + } /* end of for(;;) loop for inheritance */ +} + +static int get_attr_dev(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + struct rsbac_dev_desc_t dev, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value, + rsbac_boolean_t inherit) +{ + int err = 0; +/* rsbac_pr_debug(ds, "Getting dev attribute\n"); */ + switch (module) { + case SW_GEN: + { + struct rsbac_gen_dev_aci_t aci = + DEFAULT_GEN_DEV_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + dev_handles.gen, + NULL, &dev, &aci); + switch (attr) { + case A_log_array_low: + value->log_array_low = aci.log_array_low; + break; + case A_log_array_high: + value->log_array_high = aci.log_array_high; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; + +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_dev_aci_t aci = + DEFAULT_MAC_DEV_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + dev_handles.mac, + NULL, &dev, &aci); + switch (attr) { + case A_security_level: + value->security_level = aci.sec_level; + break; + case A_mac_categories: + value->mac_categories = aci.mac_categories; + break; + case A_mac_check: + value->mac_check = aci.mac_check; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* MAC */ + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + rsbac_rc_type_id_t type = RSBAC_RC_GENERAL_TYPE; + + switch (dev.type) { + case D_char: + case D_block: + if (rsbac_ta_list_get_data_ttl(ta_number, + dev_handles. + rc, NULL, + &dev, &type) + || ((type == RC_type_inherit_parent) + && inherit) + ) { + dev.minor = 0; + rsbac_ta_list_get_data_ttl + (ta_number, + dev_major_handles.rc, NULL, + &dev, &type); + } + break; + case D_char_major: + case D_block_major: + dev.type -= (D_block_major - D_block); + dev.minor = 0; + rsbac_ta_list_get_data_ttl(ta_number, + dev_major_handles. + rc, NULL, &dev, + &type); + break; + default: + return -RSBAC_EINVALIDTARGET; + } + switch (attr) { + case A_rc_type: + value->rc_type = type; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* RC */ + + default: + err = -RSBAC_EINVALIDMODULE; + } + /* and return */ + return err; +} + +static int get_attr_ipc(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value, + rsbac_boolean_t inherit) +{ + int err = 0; + /* rsbac_pr_debug(ds, "Getting ipc attribute\n"); */ + /* lookup only, if not sock or (sock-id != NULL), OK with NULL fifo */ + switch (module) { +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_ipc_aci_t aci = + DEFAULT_MAC_IPC_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + ipc_handles.mac, + NULL, + &tid_p->ipc, &aci); + switch (attr) { + case A_security_level: + value->security_level = aci.sec_level; + break; + case A_mac_categories: + value->mac_categories = aci.mac_categories; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* MAC */ + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + rsbac_rc_type_id_t type = RSBAC_RC_GENERAL_TYPE; + + rsbac_ta_list_get_data_ttl(ta_number, + ipc_handles.rc, + NULL, + &tid_p->ipc, &type); + switch (attr) { + case A_rc_type: + value->rc_type = type; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* RC */ + +#if defined(CONFIG_RSBAC_JAIL) + case SW_JAIL: + { + rsbac_jail_id_t id = RSBAC_JAIL_DEF_ID; + + rsbac_ta_list_get_data_ttl(ta_number, + ipc_handles.jail, + NULL, &tid_p->ipc, &id); + switch (attr) { + case A_jail_id: + value->jail_id = id; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* JAIL */ + + default: + err = -RSBAC_EINVALIDMODULE; + } + /* and return */ + return err; +} + +static int get_attr_user(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value, + rsbac_boolean_t inherit) +{ + int err = 0; +#if defined(CONFIG_RSBAC_UM_VIRTUAL) || defined(CONFIG_RSBAC_RES) + rsbac_uid_t all_user; +#endif + + /* rsbac_pr_debug(ds, "Getting user attribute\n"); */ + switch (module) { + case SW_GEN: + { + struct rsbac_gen_user_aci_t aci = + DEFAULT_GEN_U_ACI; + +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + err = rsbac_ta_list_get_data_ttl(ta_number, + user_handles.gen, + NULL, + &tid_p->user, &aci); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if(inherit) { + all_user = RSBAC_GEN_UID(RSBAC_UID_SET(tid_p->user), RSBAC_ALL_USERS); + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.gen, + NULL, + &all_user, + &aci); + } + } +#else + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.gen, + NULL, + &tid_p->user, &aci); +#endif + switch (attr) { + case A_pseudo: + value->pseudo = aci.pseudo; + break; + case A_log_user_based: + value->log_user_based = aci.log_user_based; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; + +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_user_aci_t aci = + DEFAULT_MAC_U_ACI; + +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + err = rsbac_ta_list_get_data_ttl(ta_number, + user_handles.mac, + NULL, + &tid_p->user, &aci); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if(inherit) { + all_user = RSBAC_GEN_UID(RSBAC_UID_SET(tid_p->user), RSBAC_ALL_USERS); + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.mac, + NULL, + &all_user, + &aci); + } + } +#else + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.mac, + NULL, + &tid_p->user, &aci); +#endif + switch (attr) { + case A_security_level: + value->security_level = aci.security_level; + break; + case A_initial_security_level: + value->security_level = + aci.initial_security_level; + break; + case A_min_security_level: + value->security_level = + aci.min_security_level; + break; + case A_mac_categories: + value->mac_categories = aci.mac_categories; + break; + case A_mac_initial_categories: + value->mac_categories = + aci.mac_initial_categories; + break; + case A_mac_min_categories: + value->mac_categories = + aci.mac_min_categories; + break; + case A_system_role: + case A_mac_role: + value->system_role = aci.system_role; + break; + case A_mac_user_flags: + value->mac_user_flags = aci.mac_user_flags; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* MAC */ + +#if defined(CONFIG_RSBAC_DAZ) + case SW_DAZ: + { + rsbac_system_role_int_t role = SR_user; + +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + err = rsbac_ta_list_get_data_ttl(ta_number, + user_handles.daz, + NULL, + &tid_p->user, &role); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if(inherit) { + all_user = RSBAC_GEN_UID(RSBAC_UID_SET(tid_p->user), RSBAC_ALL_USERS); + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.daz, + NULL, + &all_user, + &role); + } + } +#else + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.daz, + NULL, + &tid_p->user, &role); +#endif + switch (attr) { + case A_system_role: + case A_daz_role: + value->system_role = role; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* DAZ */ + +#if defined(CONFIG_RSBAC_FF) + case SW_FF: + { + rsbac_system_role_int_t role = SR_user; + +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + err = rsbac_ta_list_get_data_ttl(ta_number, + user_handles.ff, + NULL, + &tid_p->user, &role); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if(inherit) { + all_user = RSBAC_GEN_UID(RSBAC_UID_SET(tid_p->user), RSBAC_ALL_USERS); + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.ff, + NULL, + &all_user, + &role); + } + } +#else + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.ff, + NULL, + &tid_p->user, &role); +#endif + switch (attr) { + case A_system_role: + case A_ff_role: + value->system_role = role; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* FF */ + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + struct rsbac_rc_user_aci_t aci = DEFAULT_RC_U_ACI; + +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + err = rsbac_ta_list_get_data_ttl(ta_number, + user_handles.rc, + NULL, + &tid_p->user, &aci); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if(inherit) { + all_user = RSBAC_GEN_UID(RSBAC_UID_SET(tid_p->user), RSBAC_ALL_USERS); + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.rc, + NULL, + &all_user, + &aci); + } + } +#else + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.rc, + NULL, + &tid_p->user, &aci); +#endif + switch (attr) { + case A_rc_def_role: + value->rc_def_role = aci.rc_role; + break; + case A_rc_type: + value->rc_type = aci.rc_type; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* RC */ + +#if defined(CONFIG_RSBAC_AUTH) + case SW_AUTH: + { + rsbac_system_role_int_t role = SR_user; + +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + err = rsbac_ta_list_get_data_ttl(ta_number, + user_handles.auth, + NULL, + &tid_p->user, &role); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if(inherit) { + all_user = RSBAC_GEN_UID(RSBAC_UID_SET(tid_p->user), RSBAC_ALL_USERS); + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.auth, + NULL, + &all_user, + &role); + } + } +#else + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.auth, + NULL, + &tid_p->user, &role); +#endif + switch (attr) { + case A_system_role: + case A_auth_role: + value->system_role = role; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* AUTH */ + +#if defined(CONFIG_RSBAC_CAP) + case SW_CAP: + { + struct rsbac_cap_user_aci_t aci = + DEFAULT_CAP_U_ACI; + +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + err = rsbac_ta_list_get_data_ttl(ta_number, + user_handles.cap, + NULL, + &tid_p->user, &aci); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if(inherit) { + all_user = RSBAC_GEN_UID(RSBAC_UID_SET(tid_p->user), RSBAC_ALL_USERS); + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.cap, + NULL, + &all_user, + &aci); + } + } +#else + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.cap, + NULL, + &tid_p->user, &aci); +#endif + switch (attr) { + case A_system_role: + case A_cap_role: + value->system_role = aci.cap_role; + break; + case A_min_caps: + value->min_caps.cap[0] = aci.min_caps.cap[0]; + value->min_caps.cap[1] = aci.min_caps.cap[1]; + break; + case A_max_caps: + value->max_caps.cap[0] = aci.max_caps.cap[0]; + value->max_caps.cap[1] = aci.max_caps.cap[1]; + break; + case A_cap_ld_env: + value->cap_ld_env = aci.cap_ld_env; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* CAP */ + +#if defined(CONFIG_RSBAC_JAIL) + case SW_JAIL: + { + rsbac_system_role_int_t role = SR_user; + +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + err = rsbac_ta_list_get_data_ttl(ta_number, + user_handles.jail, + NULL, + &tid_p->user, &role); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if(inherit) { + all_user = RSBAC_GEN_UID(RSBAC_UID_SET(tid_p->user), RSBAC_ALL_USERS); + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.jail, + NULL, + &all_user, + &role); + } + } +#else + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.jail, + NULL, + &tid_p->user, &role); +#endif + switch (attr) { + case A_system_role: + case A_jail_role: + value->system_role = role; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* JAIL */ + +#if defined(CONFIG_RSBAC_RES) + case SW_RES: + { + struct rsbac_res_user_aci_t aci = + DEFAULT_RES_U_ACI; + + err = rsbac_ta_list_get_data_ttl(ta_number, + user_handles.res, + NULL, + &tid_p->user, &aci); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if(inherit) { + all_user = RSBAC_GEN_UID(RSBAC_UID_SET(tid_p->user), RSBAC_ALL_USERS); + err = rsbac_ta_list_get_data_ttl(ta_number, + user_handles.res, + NULL, + &all_user, + &aci); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if (RSBAC_UID_SET(tid_p->user)) { + all_user = RSBAC_ALL_USERS; + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.res, + NULL, + &all_user, + &aci); + } + } + } + } + switch (attr) { + case A_system_role: + case A_res_role: + value->system_role = aci.res_role; + break; + case A_res_min: + memcpy(&value->res_array, &aci.res_min, + sizeof(aci.res_min)); + break; + case A_res_max: + memcpy(&value->res_array, &aci.res_max, + sizeof(aci.res_max)); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* RES */ + +#if defined(CONFIG_RSBAC_PAX) + case SW_PAX: + { + rsbac_system_role_int_t role = SR_user; + +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + err = rsbac_ta_list_get_data_ttl(ta_number, + user_handles.pax, + NULL, + &tid_p->user, &role); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if(inherit) { + all_user = RSBAC_GEN_UID(RSBAC_UID_SET(tid_p->user), RSBAC_ALL_USERS); + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.pax, + NULL, + &all_user, + &role); + } + } +#else + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.pax, + NULL, + &tid_p->user, &role); +#endif + switch (attr) { + case A_system_role: + case A_pax_role: + value->system_role = role; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* PAX */ + +#if defined(CONFIG_RSBAC_UDF) + case SW_UDF: + { + rsbac_system_role_int_t role = SR_user; + +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + err = rsbac_ta_list_get_data_ttl(ta_number, + user_handles.udf, + NULL, + &tid_p->user, &role); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if(inherit) { + all_user = RSBAC_GEN_UID(RSBAC_UID_SET(tid_p->user), RSBAC_ALL_USERS); + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.udf, + NULL, + &all_user, + &role); + } + } +#else + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.udf, + NULL, + &tid_p->user, &role); +#endif + switch (attr) { + case A_system_role: + case A_udf_role: + value->system_role = role; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* UDF */ + + default: + err = -RSBAC_EINVALIDMODULE; + } + /* and return */ + return err; +} + +static int get_attr_process(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value, + rsbac_boolean_t inherit) +{ + int err = 0; +/* rsbac_pr_debug(ds, "Getting process attribute"); */ + switch (module) { + case SW_GEN: + { + struct rsbac_gen_process_aci_t aci = + DEFAULT_GEN_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.gen, + NULL, &tid_p->process, + &aci); + switch (attr) { + case A_vset: + value->vset = aci.vset; + break; +#ifdef CONFIG_RSBAC_MPROTECT + case A_allow_write_exec: + value->allow_write_exec = aci.allow_write_exec; + break; +#endif + case A_log_program_based: + value->log_program_based = + aci.log_program_based; + break; + case A_fake_root_uid: + value->fake_root_uid = aci.fake_root_uid; + break; + case A_audit_uid: + value->audit_uid = aci.audit_uid; + break; + case A_auid_exempt: + value->auid_exempt = aci.auid_exempt; + break; + case A_remote_ip: + value->remote_ip = aci.remote_ip; + break; + case A_kernel_thread: + value->kernel_thread = aci.kernel_thread; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; + +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_process_aci_t aci = + DEFAULT_MAC_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.mac, + NULL, &tid_p->process, + &aci); + switch (attr) { + case A_security_level: + value->security_level = + aci.owner_sec_level; + break; + case A_initial_security_level: + value->security_level = + aci.owner_initial_sec_level; + break; + case A_min_security_level: + value->security_level = + aci.owner_min_sec_level; + break; + case A_mac_categories: + value->mac_categories = + aci.mac_owner_categories; + break; + case A_mac_initial_categories: + value->mac_categories = + aci.mac_owner_initial_categories; + break; + case A_mac_min_categories: + value->mac_categories = + aci.mac_owner_min_categories; + break; + case A_current_sec_level: + value->current_sec_level = + aci.current_sec_level; + break; + case A_mac_curr_categories: + value->mac_categories = + aci.mac_curr_categories; + break; + case A_min_write_open: + value->min_write_open = aci.min_write_open; + break; + case A_min_write_categories: + value->mac_categories = + aci.min_write_categories; + break; + case A_max_read_open: + value->max_read_open = aci.max_read_open; + break; + case A_max_read_categories: + value->mac_categories = + aci.max_read_categories; + break; + case A_mac_process_flags: + value->mac_process_flags = + aci.mac_process_flags; + break; + case A_mac_auto: + if (aci.mac_process_flags & MAC_auto) + value->mac_auto = TRUE; + else + value->mac_auto = FALSE; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* MAC */ + +#if defined(CONFIG_RSBAC_DAZ) + case SW_DAZ: + { + struct rsbac_daz_process_aci_t aci = + DEFAULT_DAZ_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.daz, + NULL, + &tid_p->process, &aci); + switch (attr) { + case A_daz_scanner: + value->daz_scanner = aci.daz_scanner; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* DAZ */ + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + struct rsbac_rc_process_aci_t aci = + DEFAULT_RC_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.rc, + NULL, &tid_p->process, + &aci); + switch (attr) { + case A_rc_role: + value->rc_role = aci.rc_role; + break; + case A_rc_type: + value->rc_type = aci.rc_type; + break; + case A_rc_select_type: + value->rc_select_type = aci.rc_select_type; + break; + case A_rc_force_role: + value->rc_force_role = aci.rc_force_role; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* RC */ + +#if defined(CONFIG_RSBAC_AUTH) + case SW_AUTH: + { + struct rsbac_auth_process_aci_t aci = + DEFAULT_AUTH_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.auth, + NULL, + &tid_p->process, &aci); + switch (attr) { + case A_auth_may_setuid: + value->auth_may_setuid = + aci.auth_may_setuid; + break; + case A_auth_may_set_cap: + value->auth_may_set_cap = + aci.auth_may_set_cap; + break; +#if defined(CONFIG_RSBAC_AUTH_LEARN) + case A_auth_start_uid: + value->auth_start_uid = aci.auth_start_uid; + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + case A_auth_start_euid: + value->auth_start_euid = + aci.auth_start_euid; + break; +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + case A_auth_start_gid: + value->auth_start_gid = aci.auth_start_gid; + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case A_auth_start_egid: + value->auth_start_egid = + aci.auth_start_egid; + break; +#endif +#endif + case A_auth_learn: + value->auth_learn = aci.auth_learn; + break; +#else + case A_auth_learn: + value->auth_learn = FALSE; + break; +#endif + case A_auth_last_auth: + value->auth_last_auth = aci.auth_last_auth; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* AUTH */ + +#if defined(CONFIG_RSBAC_CAP) + case SW_CAP: + { + struct rsbac_cap_process_aci_t aci = + DEFAULT_CAP_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.cap, + NULL, + &tid_p->process, &aci); + switch (attr) { + case A_cap_process_hiding: + value->cap_process_hiding = + aci.cap_process_hiding; + break; +#if defined(CONFIG_RSBAC_CAP_LOG_MISSING) || defined(CONFIG_RSBAC_CAP_LEARN) + case A_max_caps_user: + value->max_caps_user.cap[0] = aci.max_caps_user.cap[0]; + value->max_caps_user.cap[1] = aci.max_caps_user.cap[1]; + break; + case A_max_caps_program: + value->max_caps_program.cap[0] = aci.max_caps_program.cap[0]; + value->max_caps_program.cap[1] = aci.max_caps_program.cap[1]; + break; +#endif + case A_cap_ld_env: + value->cap_ld_env = aci.cap_ld_env; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* CAP */ + +#if defined(CONFIG_RSBAC_JAIL) + case SW_JAIL: + { + struct rsbac_jail_process_aci_t aci = + DEFAULT_JAIL_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.jail, + NULL, &tid_p->process, + &aci); + switch (attr) { + case A_jail_id: + value->jail_id = aci.id; + break; + case A_jail_parent: + value->jail_parent = aci.parent; + break; + case A_jail_ip: + value->jail_ip = aci.ip; + break; + case A_jail_flags: + value->jail_flags = aci.flags; + break; + case A_jail_max_caps: + value->jail_max_caps.cap[0] = aci.max_caps.cap[0]; + value->jail_max_caps.cap[1] = aci.max_caps.cap[1]; + break; + case A_jail_scd_get: + value->jail_scd_get = aci.scd_get; + break; + case A_jail_scd_modify: + value->jail_scd_modify = aci.scd_modify; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* JAIL */ + +#if defined(CONFIG_RSBAC_PAX) + case SW_PAX: + { + struct task_struct *task_p; + + switch (attr) { + case A_pax_flags: + task_p = get_pid_task(tid_p->process, PIDTYPE_PID); + if (task_p) { + if (pid_alive(task_p)) { +#if defined(CONFIG_PAX_NOEXEC) || defined(CONFIG_PAX_ASLR) + if (task_p->mm) + value->pax_flags = + task_p->mm-> + pax_flags & + RSBAC_PAX_ALL_FLAGS; + else +#endif + value->pax_flags = 0; + } else { + value->pax_flags = 0; + } + put_task_struct(task_p); + } else + err = -RSBAC_EINVALIDTARGET; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* PAX */ + +#if defined(CONFIG_RSBAC_UDF) + case SW_UDF: + { + struct rsbac_udf_process_aci_t aci = + DEFAULT_UDF_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.udf, + NULL, + &tid_p->process, &aci); + switch (attr) { + case A_udf_checker: + value->udf_checker = aci.udf_checker; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* UDF */ + + default: + err = -RSBAC_EINVALIDMODULE; + } + return err; +} + +#ifdef CONFIG_RSBAC_UM +static int get_attr_group(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value, + rsbac_boolean_t inherit) +{ + int err = 0; + + /* rsbac_pr_debug(ds, "Getting group attribute\n"); */ + switch (module) { +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case SW_RC: + { + rsbac_rc_type_id_t type = RSBAC_RC_GENERAL_TYPE; + +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + err = rsbac_ta_list_get_data_ttl(ta_number, + group_handles.rc, + NULL, + &tid_p->group, &type); + if (err == -RSBAC_ENOTFOUND) { + err = 0; + if(inherit) { + rsbac_gid_t all_group; + + all_group = RSBAC_GEN_GID(RSBAC_GID_SET(tid_p->group), RSBAC_ALL_GROUPS); + rsbac_ta_list_get_data_ttl(ta_number, + group_handles.rc, + NULL, + &all_group, + &type); + } + } +#else + rsbac_ta_list_get_data_ttl(ta_number, + group_handles.rc, + NULL, + &tid_p->group, &type); +#endif + switch (attr) { + case A_rc_type: + value->rc_type = type; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* RC */ + + default: + err = -RSBAC_EINVALIDMODULE; + } + /* and return */ + return err; +} +#endif + +#ifdef CONFIG_RSBAC_NET_DEV +static int get_attr_netdev(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value, + rsbac_boolean_t inherit) +{ + int err = 0; + /* rsbac_pr_debug(ds, "Getting netdev attribute\n"); */ + switch (module) { +#if defined(CONFIG_RSBAC_IND_NETDEV_LOG) + case SW_GEN: + { + struct rsbac_gen_netdev_aci_t aci = + DEFAULT_GEN_NETDEV_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + netdev_handles.gen, + NULL, + &tid_p->netdev, &aci); + switch (attr) { + case A_log_array_low: + value->log_array_low = aci.log_array_low; + break; + case A_log_array_high: + value->log_array_high = aci.log_array_high; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + rsbac_rc_type_id_t type = RSBAC_RC_GENERAL_TYPE; + + rsbac_ta_list_get_data_ttl(ta_number, + netdev_handles.rc, + NULL, + &tid_p->netdev, &type); + switch (attr) { + case A_rc_type: + value->rc_type = type; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* RC */ + + default: + err = -RSBAC_EINVALIDMODULE; + } + /* and return */ + return err; +} +#endif + +#ifdef CONFIG_RSBAC_NET_OBJ +static int get_attr_nettemp(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value, + rsbac_boolean_t inherit) +{ + int err = 0; + /* rsbac_pr_debug(ds, "Getting nettemp attribute"); */ + if (tid_p->nettemp + && !rsbac_ta_list_exist(ta_number, net_temp_handle, &tid_p->nettemp) + ) + return -RSBAC_EINVALIDTARGET; + switch (module) { +#if defined(CONFIG_RSBAC_IND_NETOBJ_LOG) + case SW_GEN: + { + struct rsbac_gen_fd_aci_t aci = + DEFAULT_GEN_NETOBJ_ACI; + + if (tid_p->nettemp) + rsbac_ta_list_get_data_ttl(ta_number, + nettemp_handles. + gen, NULL, + &tid_p->nettemp, + &aci); + switch (attr) { + case A_log_array_low: + value->log_array_low = aci.log_array_low; + break; + case A_log_array_high: + value->log_array_high = aci.log_array_high; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_netobj_aci_t aci = + DEFAULT_MAC_NETOBJ_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + nettemp_handles.mac, + NULL, + &tid_p->nettemp, &aci); + switch (attr) { + case A_security_level: + value->security_level = aci.sec_level; + break; + case A_mac_categories: + value->mac_categories = aci.mac_categories; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* MAC */ + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + struct rsbac_rc_nettemp_aci_t aci = + DEFAULT_RC_NETTEMP_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + nettemp_handles.rc, + NULL, + &tid_p->nettemp, &aci); + switch (attr) { + case A_rc_type: + value->rc_type = aci.netobj_type; + break; + + case A_rc_type_nt: + value->rc_type = aci.nettemp_type; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* RC */ + + default: + err = -RSBAC_EINVALIDMODULE; + } + return err; +} + +static int get_attr_netobj(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value, + rsbac_boolean_t inherit) +{ + int err = 0; + /* rsbac_pr_debug(ds, "Getting netobj attribute"); */ + switch (module) { +#if defined(CONFIG_RSBAC_IND_NETOBJ_LOG) + case SW_GEN: + { + struct rsbac_gen_netobj_aci_t aci = + DEFAULT_GEN_NETOBJ_ACI; + rsbac_net_temp_id_t temp; + + switch (attr) { + case A_local_log_array_low: + case A_local_log_array_high: + if(!ta_number && tid_p->netobj.local_temp) + temp = tid_p->netobj.local_temp; + else + rsbac_ta_net_lookup_templates(ta_number, + &tid_p-> + netobj, + &temp, NULL); + break; + case A_remote_log_array_low: + case A_remote_log_array_high: + if(!ta_number && tid_p->netobj.remote_temp) + temp = tid_p->netobj.remote_temp; + else + rsbac_ta_net_lookup_templates(ta_number, + &tid_p-> + netobj, NULL, + &temp); + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + if (temp) + rsbac_ta_list_get_data_ttl(ta_number, + nettemp_handles. + gen, NULL, + &temp, &aci); + switch (attr) { + case A_local_log_array_low: + case A_remote_log_array_low: + value->log_array_low = aci.log_array_low; + break; + case A_local_log_array_high: + case A_remote_log_array_high: + value->log_array_high = aci.log_array_high; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_netobj_aci_t aci = + DEFAULT_MAC_NETOBJ_ACI; + + switch (attr) { + case A_local_sec_level: + case A_local_mac_categories: + if (rsbac_ta_list_get_data_ttl(ta_number, lnetobj_handles.mac, NULL, &tid_p->netobj.sock_p, &aci)) { /* not found -> fallback to template */ + rsbac_net_temp_id_t temp = 0; + + if(!ta_number && tid_p->netobj.local_temp) + temp = tid_p->netobj.local_temp; + else + rsbac_ta_net_lookup_templates + (ta_number, &tid_p->netobj, + &temp, NULL); + if (temp) + rsbac_ta_list_get_data_ttl + (ta_number, + nettemp_handles.mac, + NULL, &temp, &aci); + } + break; + + case A_remote_sec_level: + case A_remote_mac_categories: + if (rsbac_ta_list_get_data_ttl(ta_number, rnetobj_handles.mac, NULL, &tid_p->netobj.sock_p, &aci)) { /* not found -> fallback to template */ + rsbac_net_temp_id_t temp = 0; + + if(!ta_number && tid_p->netobj.remote_temp) + temp = tid_p->netobj.remote_temp; + else + rsbac_ta_net_lookup_templates + (ta_number, &tid_p->netobj, + NULL, &temp); + if (temp) + rsbac_ta_list_get_data_ttl + (ta_number, + nettemp_handles.mac, + NULL, &temp, &aci); + } + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + if (err) + break; + switch (attr) { + case A_local_sec_level: + case A_remote_sec_level: + value->security_level = aci.sec_level; + break; + case A_local_mac_categories: + case A_remote_mac_categories: + value->mac_categories = aci.mac_categories; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* MAC */ + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + rsbac_rc_type_id_t type = RSBAC_RC_GENERAL_TYPE; + + switch (attr) { + case A_local_rc_type: + if (rsbac_ta_list_get_data_ttl(ta_number, lnetobj_handles.rc, NULL, &tid_p->netobj.sock_p, &type)) { /* not found -> fallback to template */ + rsbac_net_temp_id_t temp = 0; + struct rsbac_rc_nettemp_aci_t aci; + + if(!ta_number && tid_p->netobj.local_temp) + temp = tid_p->netobj.local_temp; + else + rsbac_ta_net_lookup_templates + (ta_number, &tid_p->netobj, + &temp, NULL); + if (temp) { + if (!rsbac_ta_list_get_data_ttl(ta_number, nettemp_handles.rc, NULL, &temp, &aci)) + type = aci.netobj_type; + } + } + break; + + case A_remote_rc_type: + if (rsbac_ta_list_get_data_ttl(ta_number, rnetobj_handles.rc, NULL, &tid_p->netobj.sock_p, &type)) { /* not found -> fallback to template */ + rsbac_net_temp_id_t temp = 0; + struct rsbac_rc_nettemp_aci_t aci; + + if(!ta_number && tid_p->netobj.remote_temp) + temp = tid_p->netobj.remote_temp; + else + rsbac_ta_net_lookup_templates + (ta_number, &tid_p->netobj, + NULL, &temp); + if (temp) { + if (!rsbac_ta_list_get_data_ttl(ta_number, nettemp_handles.rc, NULL, &temp, &aci)) + type = + aci. + netobj_type; + } + } + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) + value->rc_type = type; + } + break; +#endif /* RC */ + + default: + err = -RSBAC_EINVALIDMODULE; + } + return err; +} +#endif /* NET_OBJ */ + +#ifdef CONFIG_RSBAC_FD_CACHE +int rsbac_fd_cache_invalidate(struct rsbac_fs_file_t * file_p) +{ + int i; + struct rsbac_device_list_item_t *device_p; + u_int hash; + int srcu_idx; + + if (!file_p) + return -RSBAC_EINVALIDPOINTER; + if (RSBAC_MAJOR(file_p->device) <= 1) + return 0; + + rsbac_pr_debug(fdcache, "Invalidating fd cache item device %02u:%02u inode %lu\n", + RSBAC_MAJOR(file_p->device), RSBAC_MINOR(file_p->device), + file_p->inode); + + hash = device_hash(file_p->device); + + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(file_p->device, hash); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_fd_cache_invalidate(): No entry for device %02u:%02u\n", + MAJOR(file_p->device), MINOR(file_p->device)); + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + return -RSBAC_EINVALIDDEV; + } + + for (i = 0; i < SW_NONE; i++) { + if (device_p->fd_cache_handle[i]) + rsbac_list_lol_remove(device_p->fd_cache_handle[i], &file_p->inode); + } +#ifdef CONFIG_RSBAC_XSTATS + device_p->fd_cache_invalidates++; +#endif + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + return 0; +} + +int rsbac_fd_cache_invalidate_device(kdev_t kdev) +{ + int i; + struct rsbac_device_list_item_t *device_p; + u_int hash; + int srcu_idx; + + if (RSBAC_MAJOR(kdev) <= 1) + return 0; + rsbac_pr_debug(fdcache, "Invalidating fd cache for device %02u:%02u\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + + hash = device_hash(kdev); + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(kdev, hash); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_fd_cache_invalidate(): No entry for device %02u:%02u\n", + MAJOR(kdev), MINOR(kdev)); + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + return -RSBAC_EINVALIDDEV; + } + + for (i = 0; i < SW_NONE; i++) { + if (device_p->fd_cache_handle[i]) + rsbac_list_lol_remove_all(device_p->fd_cache_handle[i]); + } +#ifdef CONFIG_RSBAC_XSTATS + device_p->fd_cache_invalidate_alls++; +#endif + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + return 0; +} + +int rsbac_fd_cache_invalidate_all(void) +{ + struct rsbac_device_list_head_t *head_p; + struct rsbac_device_list_item_t *device_p; + u_int i, j; + int srcu_idx; + + rsbac_pr_debug(fdcache, "Invalidating fd cache completely\n"); + + for (i = 0; i < RSBAC_NR_DEVICE_LISTS; i++) { + srcu_idx = srcu_read_lock(&device_list_srcu[i]); + head_p = srcu_dereference(device_head_p[i], &device_list_srcu[i]); + device_p = srcu_dereference(head_p->head, &device_list_srcu[i]); + while (device_p) { /* for all sublists */ + for (j = 0; j < SW_NONE; j++) { + if (device_p->fd_cache_handle[j]) + rsbac_list_lol_remove_all(device_p->fd_cache_handle[j]); + } +#ifdef CONFIG_RSBAC_XSTATS + device_p->fd_cache_invalidate_alls++; +#endif + device_p = srcu_dereference(device_p->next, &device_list_srcu[i]); + } + srcu_read_unlock(&device_list_srcu[i], srcu_idx); + } + return 0; +} +#endif + +/* The value parameter to rsbac_get_attr(s) and rsbac_set_attr() is a pointer */ +/* to the appropiate data structure holding the attribute value. */ + +int rsbac_ta_get_attr(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value_p, + rsbac_boolean_t inherit) +{ + int err = 0; + + if (!rsbac_initialized) { + rsbac_printk(KERN_WARNING "rsbac_get_attr(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (!value_p) + return -RSBAC_EINVALIDPOINTER; + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_get_attr(): called from interrupt, process %u(%s)!\n", + current->pid, current->comm); + return -RSBAC_EFROMINTERRUPT; + } +#ifdef CONFIG_RSBAC_XSTATS + get_attr_count[target]++; +#endif + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + return get_attr_fd(ta_number, module, target, &tid, + attr, value_p, inherit); + + case T_DEV: + return get_attr_dev(ta_number, module, target, tid.dev, + attr, value_p, inherit); + + case T_IPC: + return get_attr_ipc(ta_number, module, target, &tid, + attr, value_p, inherit); + + case T_USER: + return get_attr_user(ta_number, module, target, &tid, + attr, value_p, inherit); + + case T_PROCESS: + return get_attr_process(ta_number, module, target, &tid, + attr, value_p, inherit); + +#ifdef CONFIG_RSBAC_UM + case T_GROUP: + return get_attr_group(ta_number, module, target, &tid, + attr, value_p, inherit); +#endif /* CONFIG_RSBAC_UM */ + +#ifdef CONFIG_RSBAC_NET_DEV + case T_NETDEV: + return get_attr_netdev(ta_number, module, target, &tid, + attr, value_p, inherit); +#endif + +#ifdef CONFIG_RSBAC_NET_OBJ + case T_NETTEMP: + return get_attr_nettemp(ta_number, module, target, &tid, + attr, value_p, inherit); + + case T_NETOBJ: + return get_attr_netobj(ta_number, module, target, &tid, + attr, value_p, inherit); +#endif + + /* switch target: no valid target */ + default: + return -RSBAC_EINVALIDTARGET; + } + + return err; +} + +/************************************************************************** */ + +static int set_attr_fd(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value_p) +{ + int err = 0; + struct rsbac_device_list_item_t *device_p; + u_int hash; + int srcu_idx; + int need_set = 0; + rsbac_old_inode_nr_t inode_nr = tid_p->file.inode; +#ifdef CONFIG_RSBAC_FD_CACHE + int need_flush = 0; +#endif + + /* rsbac_pr_debug(ds, "Setting file/dir/fifo/symlink " + "attribute %u for device %02u:%02u, inode %lu, " + "dentry_p %p\n", attr, + RSBAC_MAJOR(tid_p->file.device), + RSBAC_MINOR(tid_p->file.device), + (u_long)tid_p->file.inode, tid_p->file.dentry_p); */ + hash = device_hash(tid_p->file.device); + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + device_p = lookup_device(tid_p->file.device, hash); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_set_attr(): unknown device %02u:%02u\n", + RSBAC_MAJOR(tid_p->file. + device), + RSBAC_MINOR(tid_p->file. + device)); + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + return -RSBAC_EINVALIDDEV; + } + switch (module) { + case SW_GEN: + { + struct rsbac_gen_fd_aci_t aci = DEFAULT_GEN_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.gen, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_log_array_low: + aci.log_array_low = value_p->log_array_low; + break; + case A_log_array_high: + aci.log_array_high = + value_p->log_array_high; + break; + case A_log_program_based: + aci.log_program_based = + value_p->log_program_based; + break; + case A_symlink_add_remote_ip: + aci.symlink_add_remote_ip = + value_p->symlink_add_remote_ip; + break; + case A_symlink_add_uid: + aci.symlink_add_uid = + value_p->symlink_add_uid; + break; + case A_symlink_add_mac_level: + aci.symlink_add_mac_level = + value_p->symlink_add_mac_level; + break; + case A_symlink_add_rc_role: + aci.symlink_add_rc_role = + value_p->symlink_add_rc_role; + break; + case A_allow_write_exec: + if (aci.allow_write_exec != value_p->allow_write_exec) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (target == T_DIR) + need_flush = 1; +#endif + aci.allow_write_exec = value_p->allow_write_exec; + } + break; + case A_fake_root_uid: + aci.fake_root_uid = value_p->fake_root_uid; + break; + case A_auid_exempt: + aci.auid_exempt = value_p->auid_exempt; + break; + case A_vset: + aci.vset = value_p->vset; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + device_p->handles.gen, + 0, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); +#ifdef CONFIG_RSBAC_FD_CACHE + need_set = 1; +#endif + } + } + break; + +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_fd_aci_t aci = DEFAULT_MAC_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.mac, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_security_level: + aci.sec_level = value_p->security_level; +#ifdef CONFIG_RSBAC_FD_CACHE + if (target == T_DIR) + need_flush = 1; +#endif + break; + case A_mac_categories: + aci.mac_categories = + value_p->mac_categories; +#ifdef CONFIG_RSBAC_FD_CACHE + if (target == T_DIR) + need_flush = 1; +#endif + break; + case A_mac_auto: + aci.mac_auto = value_p->mac_auto; +#ifdef CONFIG_RSBAC_FD_CACHE + if (target == T_DIR) + need_flush = 1; +#endif + break; + case A_mac_prop_trusted: + aci.mac_prop_trusted = + value_p->mac_prop_trusted; + break; + case A_mac_file_flags: + aci.mac_file_flags = + value_p-> + mac_file_flags & RSBAC_MAC_F_FLAGS; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + device_p->handles.mac, + 0, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); +#ifdef CONFIG_RSBAC_FD_CACHE + need_set = 1; +#endif + } + } + break; +#endif /* MAC */ + +#if defined(CONFIG_RSBAC_DAZ) + case SW_DAZ: + { +#if defined(CONFIG_RSBAC_DAZ_CACHE) + if (attr == A_daz_scanned) { + err = rsbac_list_add_ttl(device_p->handles.dazs, + rsbac_daz_ttl, +#ifdef CONFIG_RSBAC_DAZ_PERSIST + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, +#else + &tid_p->file.inode, +#endif + &value_p->daz_scanned); +#ifdef CONFIG_RSBAC_FD_CACHE + need_set = 1; +#endif + } else +#endif + { + struct rsbac_daz_fd_aci_t aci = + DEFAULT_DAZ_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p-> + handles.daz, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_daz_scanner: + if (aci.daz_scanner != value_p->daz_scanner) { + aci.daz_scanner = value_p->daz_scanner; + need_set = 1; + } + break; + case A_daz_do_scan: + if (aci.daz_do_scan != value_p->daz_do_scan) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (target == T_DIR) + need_flush = 1; +#endif + aci.daz_do_scan = value_p->daz_do_scan; + need_set = 1; + } + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (need_set) { + err = rsbac_ta_list_add_ttl + (ta_number, + device_p->handles.daz, + 0, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + } + } + } + break; +#endif /* DAZ */ + +#if defined(CONFIG_RSBAC_FF) + case SW_FF: + { + switch (attr) { + case A_ff_flags: + err = rsbac_ta_list_add_ttl(ta_number, + device_p-> + handles.ff, + 0, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &value_p->ff_flags); +#ifdef CONFIG_RSBAC_FD_CACHE + if (target == T_DIR) + need_flush = 1; + need_set = 1; +#endif + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* FF */ + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + struct rsbac_rc_fd_aci_t aci = DEFAULT_RC_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.rc, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_rc_type_fd: + if (aci.rc_type_fd != value_p->rc_type_fd) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (target == T_DIR) + need_flush = 1; +#endif + aci.rc_type_fd = value_p->rc_type_fd; + need_set = 1; + } + break; + case A_rc_force_role: + if (aci.rc_force_role != value_p->rc_force_role) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (target == T_DIR) + need_flush = 1; +#endif + aci.rc_force_role = value_p->rc_force_role; + need_set = 1; + } + break; + case A_rc_initial_role: + if (aci.rc_initial_role != value_p->rc_initial_role) { + aci.rc_initial_role = value_p->rc_initial_role; + need_set = 1; + } + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + if (need_set) { + err = rsbac_ta_list_add_ttl(ta_number, + device_p->handles.rc, + 0, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + } + } + break; +#endif /* RC */ + +#if defined(CONFIG_RSBAC_AUTH) + case SW_AUTH: + { + struct rsbac_auth_fd_aci_t aci = + DEFAULT_AUTH_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.auth, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_auth_may_setuid: + if (aci.auth_may_setuid != value_p->auth_may_setuid) { + aci.auth_may_setuid = value_p->auth_may_setuid; + need_set = 1; + } + break; + case A_auth_may_set_cap: + if (aci.auth_may_set_cap != value_p->auth_may_set_cap) { + aci.auth_may_set_cap = value_p->auth_may_set_cap; + need_set = 1; + } + break; + case A_auth_learn: + if (aci.auth_learn != value_p->auth_learn) { + aci.auth_learn = value_p->auth_learn; + need_set = 1; + } + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (need_set) { + err = rsbac_ta_list_add_ttl(ta_number, + device_p->handles.auth, + 0, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + } + } + break; +#endif /* AUTH */ + +#if defined(CONFIG_RSBAC_CAP) + case SW_CAP: + { + struct rsbac_cap_fd_aci_t aci = DEFAULT_CAP_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.cap, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_min_caps: + if ((aci.min_caps.cap[0] != value_p->min_caps.cap[0]) || (aci.min_caps.cap[1] != value_p->min_caps.cap[1])) { + aci.min_caps.cap[0] = value_p->min_caps.cap[0]; + aci.min_caps.cap[1] = value_p->min_caps.cap[1]; + need_set = 1; + } + break; + case A_max_caps: + if ((aci.max_caps.cap[0] != value_p->max_caps.cap[0]) || (aci.max_caps.cap[1] != value_p->max_caps.cap[1])) { + aci.max_caps.cap[0] = value_p->max_caps.cap[0]; + aci.max_caps.cap[1] = value_p->max_caps.cap[1]; + need_set = 1; + } + break; + case A_cap_ld_env: + if (aci.cap_ld_env != value_p->cap_ld_env) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (target == T_DIR) + need_flush = 1; +#endif + aci.cap_ld_env = value_p->cap_ld_env; + need_set = 1; + } + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (need_set) { + err = rsbac_ta_list_add_ttl(ta_number, + device_p->handles.cap, + 0, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_RES) + case SW_RES: + { + struct rsbac_res_fd_aci_t aci = DEFAULT_RES_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.res, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_res_min: + memcpy(&aci.res_min, &value_p->res_array, + sizeof(aci.res_min)); + break; + case A_res_max: + memcpy(&aci.res_max, &value_p->res_array, + sizeof(aci.res_max)); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + struct rsbac_res_fd_aci_t def_aci = + DEFAULT_RES_FD_ACI; + + if (memcmp(&aci, &def_aci, sizeof(aci))) + err = rsbac_ta_list_add_ttl + (ta_number, + device_p->handles.res, + 0, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, &aci); + else + err = rsbac_ta_list_remove(ta_number, + device_p->handles.res, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode); +#ifdef CONFIG_RSBAC_FD_CACHE + need_set = 1; +#endif + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_PAX) + case SW_PAX: + { + switch (attr) { + case A_pax_flags: + value_p->pax_flags &= RSBAC_PAX_ALL_FLAGS; + err = rsbac_ta_list_add_ttl(ta_number, + device_p->handles.pax, + 0, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &value_p->pax_flags); +#ifdef CONFIG_RSBAC_FD_CACHE + need_set = 1; +#endif + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* PAX */ + +#if defined(CONFIG_RSBAC_UDF) + case SW_UDF: + { +#if defined(CONFIG_RSBAC_UDF_CACHE) + if (attr == A_udf_checked) { + err = rsbac_list_add_ttl(device_p->handles.udfc, + rsbac_udf_ttl, +#ifdef CONFIG_RSBAC_UDF_PERSIST + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, +#else + &tid_p->file.inode, +#endif + &value_p->udf_checked); + } else +#endif + { + struct rsbac_udf_fd_aci_t aci = + DEFAULT_UDF_FD_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + device_p->handles.udf, + NULL, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + switch (attr) { + case A_udf_checker: + if (aci.udf_checker != value_p->udf_checker) { + aci.udf_checker = value_p->udf_checker; + need_set = 1; + } + break; + case A_udf_do_check: + if (aci.udf_do_check != value_p->udf_do_check) { +#ifdef CONFIG_RSBAC_FD_CACHE + if (target == T_DIR) + need_flush = 1; +#endif + aci.udf_do_check = value_p->udf_do_check; + need_set = 1; + } + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (need_set) { + err = rsbac_ta_list_add_ttl + (ta_number, + device_p->handles.udf, + 0, + device_p->persist ? (void *)&inode_nr : &tid_p->file.inode, + &aci); + } + } + } + break; +#endif /* UDF */ + + default: + err = -RSBAC_EINVALIDMODULE; + } +#ifdef CONFIG_RSBAC_FD_CACHE + if (!need_flush && need_set && device_p->fd_cache_handle[module]) { +#ifdef CONFIG_RSBAC_DEBUG + char * attr_name = NULL; + char * attr_val_name = NULL; + if (rsbac_debug_fdcache) { + attr_name = rsbac_kmalloc(32); + attr_val_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + } +#endif + rsbac_pr_debug(fdcache, "Invalidating fd cache item device %02u:%02u inode %lu, module %u, attr %s, new value %s\n", + RSBAC_MAJOR(tid_p->file.device), RSBAC_MINOR(tid_p->file.device), + tid_p->file.inode, module, get_attribute_name(attr_name, attr), get_attribute_value_name(attr_val_name, attr, value_p)); + rsbac_list_lol_remove(device_p->fd_cache_handle[module], &tid_p->file.inode); +#ifdef CONFIG_RSBAC_XSTATS + device_p->fd_cache_invalidates++; +#endif +#ifdef CONFIG_RSBAC_DEBUG + if (attr_name) + rsbac_kfree(attr_name); + if (attr_val_name) + rsbac_kfree(attr_val_name); +#endif + } +#endif + + /* free access to device_list_head */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + +#ifdef CONFIG_RSBAC_FD_CACHE + if (need_flush) { + u_int i; + struct rsbac_device_list_head_t *head_p; + + rsbac_pr_debug(fdcache, "Invalidating fd cache for module %u on all devices\n", + module); + for (i = 0; i < RSBAC_NR_DEVICE_LISTS; i++) { + srcu_idx = srcu_read_lock(&device_list_srcu[i]); + head_p = srcu_dereference(device_head_p[i], &device_list_srcu[i]); + device_p = srcu_dereference(head_p->head, &device_list_srcu[i]); + while (device_p) { + if (device_p->fd_cache_handle[module]) + rsbac_list_lol_remove_all(device_p->fd_cache_handle[module]); + device_p = srcu_dereference(device_p->next, &device_list_srcu[i]); + } + srcu_read_unlock(&device_list_srcu[i], srcu_idx); + } + } +#endif + + return err; +} + +static int set_attr_dev(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + struct rsbac_dev_desc_t dev, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value_p) +{ + int err = 0; + /* rsbac_pr_debug(ds, "Setting dev attribute\n"); */ + switch (module) { + case SW_GEN: + { + struct rsbac_gen_dev_aci_t aci = + DEFAULT_GEN_DEV_ACI; + + if (dev.type > D_char) + return -RSBAC_EINVALIDTARGET; + rsbac_ta_list_get_data_ttl(ta_number, + dev_handles.gen, + NULL, &dev, &aci); + switch (attr) { + case A_log_array_low: + aci.log_array_low = value_p->log_array_low; + break; + case A_log_array_high: + aci.log_array_high = + value_p->log_array_high; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + dev_handles. + gen, 0, &dev, + &aci); + } + } + break; + +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_dev_aci_t aci = + DEFAULT_MAC_DEV_ACI; + + if (dev.type > D_char) + return -RSBAC_EINVALIDTARGET; + rsbac_ta_list_get_data_ttl(ta_number, + dev_handles.mac, + NULL, &dev, &aci); + switch (attr) { + case A_security_level: + aci.sec_level = value_p->security_level; + break; + case A_mac_categories: + aci.mac_categories = + value_p->mac_categories; + break; + case A_mac_check: + aci.mac_check = value_p->mac_check; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + dev_handles. + mac, 0, &dev, + &aci); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + rsbac_rc_type_id_t type = value_p->rc_type; + struct rsbac_dev_desc_t dev_desc; + rsbac_list_handle_t handle; + + dev_desc.major = dev.major; + dev_desc.minor = dev.minor; + switch (dev.type) { + case D_char: + dev_desc.type = D_char; + handle = dev_handles.rc; + break; + case D_block: + dev_desc.type = D_block; + handle = dev_handles.rc; + break; + case D_char_major: + if (type > RC_type_max_value) + return -RSBAC_EINVALIDVALUE; + dev_desc.type = D_char; + dev_desc.minor = 0; + handle = dev_major_handles.rc; + break; + case D_block_major: + if (type > RC_type_max_value) + return -RSBAC_EINVALIDVALUE; + dev_desc.type = D_block; + dev_desc.minor = 0; + handle = dev_major_handles.rc; + break; + default: + return -RSBAC_EINVALIDTARGET; + } + + switch (attr) { + case A_rc_type: + err = rsbac_ta_list_add_ttl(ta_number, + handle, + 0, + &dev_desc, + &type); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif + + default: + err = -RSBAC_EINVALIDMODULE; + } + + return err; +} + +static int set_attr_ipc(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value_p) +{ + int err = 0; + /* rsbac_pr_debug(ds, "Setting ipc attribute"); */ + switch (module) { +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_ipc_aci_t aci = + DEFAULT_MAC_IPC_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + ipc_handles.mac, + NULL, + &tid_p->ipc, &aci); + switch (attr) { + case A_security_level: + aci.sec_level = value_p->security_level; + break; + case A_mac_categories: + aci.mac_categories = + value_p->mac_categories; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + ipc_handles. + mac, 0, + &tid_p->ipc, + &aci); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + rsbac_rc_type_id_t type = value_p->rc_type; + + switch (attr) { + case A_rc_type: + err = rsbac_ta_list_add_ttl(ta_number, + ipc_handles.rc, + 0, + &tid_p->ipc, + &type); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_JAIL) + case SW_JAIL: + { + rsbac_jail_id_t id = value_p->jail_id; + + switch (attr) { + case A_jail_id: +/* if (id) + rsbac_pr_debug(aef, + "Setting jail_id for IPC " + "%s %lu to %u\n", + get_ipc_target_name(tmp, + tid_p->ipc.type), + tid_p->ipc.id.id_nr, + id); */ + err = rsbac_ta_list_add_ttl(ta_number, + ipc_handles. + jail, 0, + &tid_p->ipc, + &id); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif + + default: + err = -RSBAC_EINVALIDMODULE; + } + + return err; +} + +static int set_attr_user(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value_p) +{ + int err = 0; + /* rsbac_pr_debug(ds, "Setting %s user attribute %i " + "for %u to %i\n", + get_switch_target_name(tmp, module), attr, + tid_p->user, value_p->dummy); */ + switch (module) { + case SW_GEN: + { + struct rsbac_gen_user_aci_t aci = + DEFAULT_GEN_U_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.gen, + NULL, + &tid_p->user, &aci); + switch (attr) { + case A_pseudo: + aci.pseudo = value_p->pseudo; + break; + case A_log_user_based: + aci.log_user_based = + value_p->log_user_based; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + user_handles. + gen, 0, + &tid_p->user, + &aci); + } + } + break; + +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_user_aci_t aci = + DEFAULT_MAC_U_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.mac, + NULL, + &tid_p->user, &aci); + switch (attr) { + case A_security_level: + if (value_p->security_level < + aci.min_security_level) + err = -RSBAC_EINVALIDVALUE; + else + aci.security_level = + value_p->security_level; + break; + case A_initial_security_level: + if ((value_p->security_level < + aci.min_security_level) + || (value_p->security_level > + aci.security_level) + ) + err = -RSBAC_EINVALIDVALUE; + else + aci.initial_security_level = + value_p->security_level; + break; + case A_min_security_level: + if (value_p->security_level > + aci.security_level) + err = -RSBAC_EINVALIDVALUE; + else + aci.min_security_level = + value_p->security_level; + break; + case A_mac_categories: + if ((value_p->mac_categories & aci. + mac_min_categories) != + aci.mac_min_categories) + err = -RSBAC_EINVALIDVALUE; + else + aci.mac_categories = + value_p->mac_categories; + break; + case A_mac_initial_categories: + if (((value_p->mac_categories & aci. + mac_min_categories) != + aci.mac_min_categories) + || + ((value_p->mac_categories & aci. + mac_categories) != + value_p->mac_categories) + ) + err = -RSBAC_EINVALIDVALUE; + else + aci.mac_initial_categories = + value_p->mac_categories; + break; + case A_mac_min_categories: + if ((value_p->mac_categories & aci. + mac_categories) != + value_p->mac_categories) + err = -RSBAC_EINVALIDVALUE; + else + aci.mac_min_categories = + value_p->mac_categories; + break; + case A_system_role: + case A_mac_role: + aci.system_role = value_p->system_role; + break; + case A_mac_user_flags: + aci.mac_user_flags = + value_p-> + mac_user_flags & RSBAC_MAC_U_FLAGS; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + user_handles. + mac, 0, + &tid_p->user, + &aci); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_DAZ) + case SW_DAZ: + { + rsbac_system_role_int_t role = + value_p->system_role; + + switch (attr) { + case A_system_role: + case A_daz_role: + err = rsbac_ta_list_add_ttl(ta_number, + user_handles. + daz, 0, + &tid_p->user, + &role); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_FF) + case SW_FF: + { + rsbac_system_role_int_t role = + value_p->system_role; + + switch (attr) { + case A_system_role: + case A_ff_role: + err = rsbac_ta_list_add_ttl(ta_number, + user_handles. + ff, 0, + &tid_p->user, + &role); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + struct rsbac_rc_user_aci_t aci = DEFAULT_RC_U_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.rc, + NULL, + &tid_p->user, &aci); + switch (attr) { + case A_rc_def_role: + aci.rc_role = value_p->rc_def_role; + break; + case A_rc_type: + aci.rc_type = value_p->rc_type; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + user_handles. + rc, 0, + &tid_p->user, + &aci); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_AUTH) + case SW_AUTH: + { + rsbac_system_role_int_t role = + value_p->system_role; + + switch (attr) { + case A_system_role: + case A_auth_role: + err = rsbac_ta_list_add_ttl(ta_number, + user_handles. + auth, 0, + &tid_p->user, + &role); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_CAP) + case SW_CAP: + { + struct rsbac_cap_user_aci_t aci = + DEFAULT_CAP_U_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.cap, + NULL, + &tid_p->user, &aci); + switch (attr) { + case A_system_role: + case A_cap_role: + aci.cap_role = value_p->system_role; + break; + case A_min_caps: + aci.min_caps.cap[0] = value_p->min_caps.cap[0]; + aci.min_caps.cap[1] = value_p->min_caps.cap[1]; + break; + case A_max_caps: + aci.max_caps.cap[0] = value_p->max_caps.cap[0]; + aci.max_caps.cap[1] = value_p->max_caps.cap[1]; + break; + case A_cap_ld_env: + aci.cap_ld_env = value_p->cap_ld_env; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + user_handles. + cap, 0, + &tid_p->user, + &aci); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_JAIL) + case SW_JAIL: + { + rsbac_system_role_int_t role = + value_p->system_role; + + switch (attr) { + case A_system_role: + case A_jail_role: + err = rsbac_ta_list_add_ttl(ta_number, + user_handles. + jail, 0, + &tid_p->user, + &role); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_RES) + case SW_RES: + { + struct rsbac_res_user_aci_t aci = + DEFAULT_RES_U_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + user_handles.res, + NULL, + &tid_p->user, &aci); + switch (attr) { + case A_system_role: + case A_res_role: + aci.res_role = value_p->system_role; + break; + case A_res_min: + memcpy(&aci.res_min, &value_p->res_array, + sizeof(aci.res_min)); + break; + case A_res_max: + memcpy(&aci.res_max, &value_p->res_array, + sizeof(aci.res_max)); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + struct rsbac_res_user_aci_t def_aci = + DEFAULT_RES_U_ACI; + + if (tid_p->user != RSBAC_ALL_USERS) { + rsbac_uid_t all_users = + RSBAC_ALL_USERS; + + rsbac_ta_list_get_data_ttl + (ta_number, user_handles.res, + NULL, &all_users, &def_aci); + } + if (memcmp(&aci, &def_aci, sizeof(aci))) + err = + rsbac_ta_list_add_ttl + (ta_number, user_handles.res, + 0, &tid_p->user, &aci); + else + err = + rsbac_ta_list_remove(ta_number, + user_handles. + res, + &tid_p-> + user); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_PAX) + case SW_PAX: + { + rsbac_system_role_int_t role = + value_p->system_role; + + switch (attr) { + case A_system_role: + case A_pax_role: + err = rsbac_ta_list_add_ttl(ta_number, + user_handles. + pax, 0, + &tid_p->user, + &role); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_UDF) + case SW_UDF: + { + rsbac_system_role_int_t role = + value_p->system_role; + + switch (attr) { + case A_system_role: + case A_udf_role: + err = rsbac_ta_list_add_ttl(ta_number, + user_handles. + udf, 0, + &tid_p->user, + &role); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif + + default: + err = -RSBAC_EINVALIDMODULE; + } + + return err; +} + +static int set_attr_process(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value_p) +{ + int err = 0; + /* rsbac_pr_debug(ds, "Setting process attribute\n"); */ + if (!tid_p->process) { + rsbac_printk(KERN_WARNING "rsbac_set_attr(): Trying to set attribute for process 0!\n"); + return -RSBAC_EINVALIDTARGET; + } + switch (module) { + case SW_GEN: + { + struct rsbac_gen_process_aci_t aci = + DEFAULT_GEN_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.gen, + NULL, &tid_p->process, + &aci); + switch (attr) { + case A_vset: + aci.vset = value_p->vset; + break; +#ifdef CONFIG_RSBAC_MPROTECT + case A_allow_write_exec: + aci.allow_write_exec = value_p->allow_write_exec; + break; +#endif + case A_log_program_based: + aci.log_program_based = + value_p->log_program_based; + break; + case A_fake_root_uid: + aci.fake_root_uid = value_p->fake_root_uid; + break; + case A_audit_uid: + aci.audit_uid = value_p->audit_uid; + break; + case A_auid_exempt: + aci.auid_exempt = value_p->auid_exempt; + break; + case A_remote_ip: + aci.remote_ip = value_p->remote_ip; + break; + case A_kernel_thread: + aci.kernel_thread = value_p->kernel_thread; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + process_handles.gen, + 0, + &tid_p-> + process, &aci); + } + } + break; + +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_process_aci_t aci = + DEFAULT_MAC_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.mac, + NULL, &tid_p->process, + &aci); + switch (attr) { + case A_security_level: + aci.owner_sec_level = + value_p->security_level; + break; + case A_initial_security_level: + aci.owner_initial_sec_level = + value_p->security_level; + break; + case A_min_security_level: + aci.owner_min_sec_level = + value_p->security_level; + break; + case A_mac_categories: + aci.mac_owner_categories = + value_p->mac_categories; + break; + case A_mac_initial_categories: + aci.mac_owner_initial_categories = + value_p->mac_categories; + break; + case A_mac_min_categories: + aci.mac_owner_min_categories = + value_p->mac_categories; + break; + case A_current_sec_level: + aci.current_sec_level = + value_p->current_sec_level; + break; + case A_mac_curr_categories: + aci.mac_curr_categories = + value_p->mac_categories; + break; + case A_min_write_open: + aci.min_write_open = + value_p->min_write_open; + break; + case A_min_write_categories: + aci.min_write_categories = + value_p->mac_categories; + break; + case A_max_read_open: + aci.max_read_open = value_p->max_read_open; + break; + case A_max_read_categories: + aci.max_read_categories = + value_p->mac_categories; + break; + case A_mac_process_flags: + aci.mac_process_flags = + value_p-> + mac_process_flags & RSBAC_MAC_P_FLAGS; + break; + case A_mac_auto: + if (value_p->mac_auto) + aci.mac_process_flags |= MAC_auto; + else + aci.mac_process_flags &= ~MAC_auto; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + process_handles.mac, + 0, + &tid_p-> + process, &aci); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_DAZ) + case SW_DAZ: + { + struct rsbac_daz_process_aci_t aci = + DEFAULT_DAZ_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.daz, + NULL, + &tid_p->process, &aci); + switch (attr) { + case A_daz_scanner: + aci.daz_scanner = value_p->daz_scanner; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + process_handles. + daz, 0, + &tid_p-> + process, &aci); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + struct rsbac_rc_process_aci_t aci = + DEFAULT_RC_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.rc, + NULL, &tid_p->process, + &aci); + switch (attr) { + case A_rc_role: + aci.rc_role = value_p->rc_role; + break; + case A_rc_type: + aci.rc_type = value_p->rc_type; + break; + case A_rc_select_type: + aci.rc_select_type = value_p->rc_select_type; + break; + case A_rc_force_role: + aci.rc_force_role = value_p->rc_force_role; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + process_handles.rc, + 0, + &tid_p-> + process, &aci); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_AUTH) + case SW_AUTH: + { + struct rsbac_auth_process_aci_t aci = + DEFAULT_AUTH_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.auth, + NULL, + &tid_p->process, &aci); + switch (attr) { + case A_auth_may_setuid: + aci.auth_may_setuid = + value_p->auth_may_setuid; + break; + case A_auth_may_set_cap: + aci.auth_may_set_cap = + value_p->auth_may_set_cap; + break; +#if defined(CONFIG_RSBAC_AUTH_LEARN) + case A_auth_start_uid: + aci.auth_start_uid = + value_p->auth_start_uid; + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + case A_auth_start_euid: + aci.auth_start_euid = + value_p->auth_start_euid; + break; +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + case A_auth_start_gid: + aci.auth_start_gid = + value_p->auth_start_gid; + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case A_auth_start_egid: + aci.auth_start_egid = + value_p->auth_start_egid; + break; +#endif +#endif + case A_auth_learn: + aci.auth_learn = value_p->auth_learn; + break; +#endif + case A_auth_last_auth: + aci.auth_last_auth = + value_p->auth_last_auth; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + process_handles.auth, + 0, + &tid_p->process, + &aci); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_CAP) + case SW_CAP: + { + struct rsbac_cap_process_aci_t aci = + DEFAULT_CAP_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.cap, + NULL, + &tid_p->process, &aci); + switch (attr) { + case A_cap_process_hiding: + aci.cap_process_hiding = + value_p->cap_process_hiding; + break; +#if defined(CONFIG_RSBAC_CAP_LOG_MISSING) || defined(CONFIG_RSBAC_CAP_LEARN) + case A_max_caps_user: + aci.max_caps_user.cap[0] = value_p->max_caps_user.cap[0]; + aci.max_caps_user.cap[1] = value_p->max_caps_user.cap[1]; + break; + case A_max_caps_program: + aci.max_caps_program.cap[0] = value_p->max_caps_program.cap[0]; + aci.max_caps_program.cap[1] = value_p->max_caps_program.cap[1]; +#endif + break; + case A_cap_ld_env: + aci.cap_ld_env = value_p->cap_ld_env; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + process_handles. + cap, 0, + &tid_p-> + process, &aci); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_JAIL) + case SW_JAIL: + { + struct rsbac_jail_process_aci_t aci = + DEFAULT_JAIL_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.jail, + NULL, &tid_p->process, + &aci); + switch (attr) { + case A_jail_id: + aci.id = value_p->jail_id; + break; + case A_jail_parent: + aci.parent = value_p->jail_parent; + break; + case A_jail_ip: + aci.ip = value_p->jail_ip; + break; + case A_jail_flags: + aci.flags = value_p->jail_flags; + break; + case A_jail_max_caps: + aci.max_caps.cap[0] = value_p->jail_max_caps.cap[0]; + aci.max_caps.cap[1] = value_p->jail_max_caps.cap[1]; + break; + case A_jail_scd_get: + aci.scd_get = value_p->jail_scd_get; + break; + case A_jail_scd_modify: + aci.scd_modify = value_p->jail_scd_modify; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + process_handles.jail, + 0, + &tid_p-> + process, &aci); + } + } + break; +#endif + +#if defined(CONFIG_RSBAC_UDF) + case SW_UDF: + { + struct rsbac_udf_process_aci_t aci = + DEFAULT_UDF_P_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + process_handles.udf, + NULL, + &tid_p->process, &aci); + switch (attr) { + case A_udf_checker: + aci.udf_checker = value_p->udf_checker; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + process_handles. + udf, 0, + &tid_p-> + process, &aci); + } + } + break; +#endif + + default: + err = -RSBAC_EINVALIDMODULE; + } + + return err; +} + +#ifdef CONFIG_RSBAC_UM +static int set_attr_group(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value_p) +{ + int err = 0; + /* rsbac_pr_debug(ds, "Setting group attribute\n"); */ + switch (module) { +#if defined(CONFIG_RSBAC_RC_UM_PROT) + case SW_RC: + { + rsbac_rc_type_id_t type = value_p->rc_type; + rsbac_gid_t group_desc; + + group_desc = tid_p->group; + + switch (attr) { + case A_rc_type: + err = rsbac_ta_list_add_ttl(ta_number, + group_handles. + rc, 0, + &group_desc, + &type); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif + + default: + err = -RSBAC_EINVALIDMODULE; + } + + return err; +} +#endif /* UM */ + +#ifdef CONFIG_RSBAC_NET_DEV +static int set_attr_netdev(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value_p) +{ + int err = 0; + /* rsbac_pr_debug(ds, "Setting netdev attribute\n"); */ + switch (module) { +#if defined(CONFIG_RSBAC_IND_NETDEV_LOG) + case SW_GEN: + { + struct rsbac_gen_netdev_aci_t aci = + DEFAULT_GEN_NETDEV_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + netdev_handles.gen, + NULL, + &tid_p->netdev, &aci); + switch (attr) { + case A_log_array_low: + aci.log_array_low = value_p->log_array_low; + break; + case A_log_array_high: + aci.log_array_high = + value_p->log_array_high; + break; + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + netdev_handles. + gen, 0, + &tid_p->netdev, + &aci); + } + } + break; +#endif +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + rsbac_rc_type_id_t type = value_p->rc_type; + + switch (attr) { + case A_rc_type: + err = rsbac_ta_list_add_ttl(ta_number, + netdev_handles. + rc, 0, + &tid_p->netdev, + &type); + break; + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif + + default: + err = -RSBAC_EINVALIDMODULE; + } + + return err; +} +#endif + +#ifdef CONFIG_RSBAC_NET_OBJ +static int set_attr_nettemp(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value_p) +{ + int err = 0; + /* rsbac_pr_debug(ds, "Setting nettemp attribute\n"); */ + if (!rsbac_ta_list_exist(ta_number, net_temp_handle, &tid_p->nettemp)) + return -RSBAC_EINVALIDTARGET; + switch (module) { +#if defined(CONFIG_RSBAC_IND_NETOBJ_LOG) + case SW_GEN: + { + struct rsbac_gen_netobj_aci_t aci = + DEFAULT_GEN_NETOBJ_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + nettemp_handles.gen, + NULL, + &tid_p->nettemp, &aci); + switch (attr) { + case A_log_array_low: + aci.log_array_low = value_p->log_array_low; + break; + case A_log_array_high: + aci.log_array_high = + value_p->log_array_high; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + nettemp_handles. + gen, 0, + &tid_p-> + nettemp, &aci); + } + } + break; +#endif /* IND_NETOBJ_LOG */ +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_netobj_aci_t aci = + DEFAULT_MAC_NETOBJ_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + nettemp_handles.mac, + NULL, + &tid_p->nettemp, &aci); + switch (attr) { + case A_security_level: + aci.sec_level = value_p->security_level; + break; + case A_mac_categories: + aci.mac_categories = + value_p->mac_categories; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + nettemp_handles. + mac, 0, + &tid_p-> + nettemp, &aci); + } + } + break; +#endif /* MAC */ + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + struct rsbac_rc_nettemp_aci_t aci = + DEFAULT_RC_NETTEMP_ACI; + + rsbac_ta_list_get_data_ttl(ta_number, + nettemp_handles.rc, + NULL, + &tid_p->nettemp, &aci); + switch (attr) { + case A_rc_type: + aci.netobj_type = value_p->rc_type; + break; + case A_rc_type_nt: + aci.nettemp_type = value_p->rc_type; + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + if (!err) { + err = rsbac_ta_list_add_ttl(ta_number, + nettemp_handles. + rc, 0, + &tid_p-> + nettemp, &aci); + } + } + break; +#endif /* RC */ + + default: + err = -RSBAC_EINVALIDMODULE; + } + + return err; +} + +static int set_attr_netobj(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t *tid_p, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *value_p) +{ + int err = 0; + /* rsbac_pr_debug(ds, "Setting netobj attribute\n"); */ + switch (module) { +#if defined(CONFIG_RSBAC_MAC) + case SW_MAC: + { + struct rsbac_mac_netobj_aci_t aci = + DEFAULT_MAC_NETOBJ_ACI; + + switch (attr) { + case A_local_sec_level: + case A_local_mac_categories: + if (rsbac_ta_list_get_data_ttl(ta_number, lnetobj_handles.mac, NULL, &tid_p->netobj.sock_p, &aci)) { /* not found -> fallback to template */ + rsbac_net_temp_id_t temp = 0; + + rsbac_ta_net_lookup_templates + (ta_number, &tid_p->netobj, + &temp, NULL); + if (temp) + rsbac_ta_list_get_data_ttl + (ta_number, + nettemp_handles.mac, + NULL, &temp, &aci); + } + break; + + case A_remote_sec_level: + case A_remote_mac_categories: + if (rsbac_ta_list_get_data_ttl(ta_number, rnetobj_handles.mac, NULL, &tid_p->netobj.sock_p, &aci)) { /* not found -> fallback to template */ + rsbac_net_temp_id_t temp = 0; + + rsbac_ta_net_lookup_templates + (ta_number, &tid_p->netobj, + NULL, &temp); + if (temp) + rsbac_ta_list_get_data_ttl + (ta_number, + nettemp_handles.mac, + NULL, &temp, &aci); + } + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + if (err) + break; + { + switch (attr) { + case A_local_sec_level: + aci.sec_level = + value_p->security_level; + err = + rsbac_ta_list_add_ttl + (ta_number, + lnetobj_handles.mac, 0, + &tid_p->netobj.sock_p, &aci); + break; + case A_remote_sec_level: + aci.sec_level = + value_p->security_level; + err = + rsbac_ta_list_add_ttl + (ta_number, + rnetobj_handles.mac, 0, + &tid_p->netobj.sock_p, &aci); + break; + case A_local_mac_categories: + aci.mac_categories = + value_p->mac_categories; + err = + rsbac_ta_list_add_ttl + (ta_number, + lnetobj_handles.mac, 0, + &tid_p->netobj.sock_p, &aci); + break; + case A_remote_mac_categories: + aci.mac_categories = + value_p->mac_categories; + err = + rsbac_ta_list_add_ttl + (ta_number, + rnetobj_handles.mac, 0, + &tid_p->netobj.sock_p, &aci); + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + } + break; +#endif /* MAC */ + +#if defined(CONFIG_RSBAC_RC) + case SW_RC: + { + rsbac_rc_type_id_t type = value_p->rc_type; + + switch (attr) { + case A_local_rc_type: + err = rsbac_ta_list_add_ttl(ta_number, + lnetobj_handles.rc, 0, + &tid_p->netobj. + sock_p, &type); + break; + + case A_remote_rc_type: + err = rsbac_ta_list_add_ttl(ta_number, + rnetobj_handles.rc, 0, + &tid_p->netobj. + sock_p, &type); + break; + + default: + err = -RSBAC_EINVALIDATTR; + } + } + break; +#endif /* RC */ + + default: + err = -RSBAC_EINVALIDMODULE; + } + + return err; +} +#endif /* UM */ + + +int rsbac_ta_set_attr(rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t value) +{ + int err = 0; +/* +#ifdef CONFIG_RSBAC_DEBUG + char tmp[RSBAC_MAXNAMELEN]; +#endif +*/ + if (!rsbac_initialized) { + rsbac_printk(KERN_WARNING "rsbac_set_attr(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_set_attr(): called from interrupt, process %u(%s)!\n", + current->pid, current->comm); + return -RSBAC_EFROMINTERRUPT; + } + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + err = set_attr_fd(ta_number, module, target, &tid, attr, &value); + break; + + case T_DEV: + err = + set_attr_dev(ta_number, module, target, tid.dev, attr, + &value); + break; + + case T_IPC: + err = + set_attr_ipc(ta_number, module, target, &tid, attr, + &value); + break; + + case T_USER: + err = + set_attr_user(ta_number, module, target, &tid, attr, + &value); + break; + + case T_PROCESS: + err = + set_attr_process(ta_number, module, target, &tid, attr, + &value); + break; + +#ifdef CONFIG_RSBAC_UM + case T_GROUP: + err = + set_attr_group(ta_number, module, target, &tid, attr, + &value); + break; +#endif /* CONFIG_RSBAC_UM */ + +#ifdef CONFIG_RSBAC_NET_DEV + case T_NETDEV: + err = + set_attr_netdev(ta_number, module, target, &tid, attr, + &value); + break; +#endif + +#ifdef CONFIG_RSBAC_NET_OBJ + case T_NETTEMP: + err = + set_attr_nettemp(ta_number, module, target, &tid, attr, + &value); + break; + + case T_NETOBJ: + err = + set_attr_netobj(ta_number, module, target, &tid, attr, + &value); + break; +#endif /* NET_OBJ */ + + /* switch(target): no valid target */ + default: + return -RSBAC_EINVALIDTARGET; + } +#ifdef CONFIG_RSBAC_XSTATS + if (!err) + set_attr_count[target]++; +#endif + return err; +} + +/************************************************************************** */ + +int rsbac_ta_remove_target(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid) +{ + int error = 0; + struct rsbac_device_list_item_t *device_p; + u_int hash; + int srcu_idx; + rsbac_inode_nr_t inode_nr; + + if (!rsbac_initialized) { + // rsbac_printk(KERN_WARNING "rsbac_ta_remove_target(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_ta_remove_target(): called from interrupt!\n"); + return -RSBAC_EFROMINTERRUPT; + } + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + inode_nr = tid.file.inode; + /* rsbac_pr_debug(ds, "Removing file/dir/fifo/symlink ACI\n"); */ +#if defined(CONFIG_RSBAC_MAC) + /* file and dir items can also have mac_f_trusets -> remove first */ + if ((target == T_FILE) + || (target == T_DIR) + ) + error = rsbac_mac_remove_f_trusets(tid.file); +#endif +#if defined(CONFIG_RSBAC_AUTH) + /* file and dir items can also have auth_f_capsets -> remove first */ + if ((target == T_FILE) + || (target == T_DIR) + ) + error = rsbac_auth_remove_f_capsets(tid.file); +#endif +#if defined(CONFIG_RSBAC_ACL) + /* items can also have an acl_fd_item -> remove first */ + error = rsbac_acl_remove_acl(ta_number, target, tid); +#endif + hash = device_hash(tid.file.device); + srcu_idx = srcu_read_lock(&device_list_srcu[hash]); + + device_p = lookup_device(tid.file.device, hash); + if (!device_p) { + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_remove_target(): unknown device %02u:%02u\n", + RSBAC_MAJOR(tid.file. + device), + RSBAC_MINOR(tid.file. + device)); + return -RSBAC_EINVALIDDEV; + } + rsbac_ta_list_remove(ta_number, + device_p->handles.gen, + device_p->persist ? (void *)&inode_nr : &tid.file.inode); +#if defined(CONFIG_RSBAC_MAC) + rsbac_ta_list_remove(ta_number, + device_p->handles.mac, + device_p->persist ? (void *)&inode_nr : &tid.file.inode); +#endif +#if defined(CONFIG_RSBAC_DAZ) + rsbac_ta_list_remove(ta_number, + device_p->handles.daz, + device_p->persist ? (void *)&inode_nr : &tid.file.inode); +#if defined(CONFIG_RSBAC_DAZ_CACHE) + rsbac_ta_list_remove(ta_number, + device_p->handles.dazs, +#ifdef CONFIG_RSBAC_DAZ_PERSIST + device_p->persist ? (void *)&inode_nr : &tid.file.inode); +#else + &tid.file.inode); +#endif +#endif +#endif +#if defined(CONFIG_RSBAC_FF) + rsbac_ta_list_remove(ta_number, + device_p->handles.ff, + device_p->persist ? (void *)&inode_nr : &tid.file.inode); +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_ta_list_remove(ta_number, + device_p->handles.rc, + device_p->persist ? (void *)&inode_nr : &tid.file.inode); +#endif +#if defined(CONFIG_RSBAC_AUTH) + rsbac_ta_list_remove(ta_number, + device_p->handles.auth, + device_p->persist ? (void *)&inode_nr : &tid.file.inode); +#endif +#if defined(CONFIG_RSBAC_CAP) + rsbac_ta_list_remove(ta_number, + device_p->handles.cap, + device_p->persist ? (void *)&inode_nr : &tid.file.inode); +#endif +#if defined(CONFIG_RSBAC_PAX) + rsbac_ta_list_remove(ta_number, + device_p->handles.pax, + device_p->persist ? (void *)&inode_nr : &tid.file.inode); +#endif +#if defined(CONFIG_RSBAC_RES) + rsbac_ta_list_remove(ta_number, + device_p->handles.res, + device_p->persist ? (void *)&inode_nr : &tid.file.inode); +#endif +#if defined(CONFIG_RSBAC_UDF) + rsbac_ta_list_remove(ta_number, + device_p->handles.udf, + device_p->persist ? (void *)&inode_nr : &tid.file.inode); +#if defined(CONFIG_RSBAC_UDF_CACHE) + rsbac_ta_list_remove(ta_number, + device_p->handles.udfc, +#ifdef CONFIG_RSBAC_UDF_PERSIST + device_p->persist ? (void *)&inode_nr : &tid.file.inode); +#else + &tid.file.inode); +#endif +#endif +#endif + + /* free access to device_list_head */ + srcu_read_unlock(&device_list_srcu[hash], srcu_idx); +#ifdef CONFIG_RSBAC_FD_CACHE + rsbac_pr_debug(fdcache, "removed FD item device %02u:%02u inode %lu, invalidate cache item\n", + RSBAC_MAJOR(tid.file.device), RSBAC_MINOR(tid.file.device), + tid.file.inode); + rsbac_fd_cache_invalidate(&tid.file); +#endif + break; + + case T_DEV: + { + switch (tid.dev.type) + { + case D_block: + case D_char: + rsbac_ta_list_remove(ta_number, + dev_handles.gen, + &tid.dev); +#if defined(CONFIG_RSBAC_MAC) + rsbac_ta_list_remove(ta_number, + dev_handles.mac, + &tid.dev); +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_ta_list_remove(ta_number, + dev_handles.rc, + &tid.dev); +#endif + break; + case D_block_major: + case D_char_major: + { + enum rsbac_dev_type_t orig_devtype=tid.dev.type; + + if (tid.dev.type==D_block_major) + tid.dev.type=D_block; + else + tid.dev.type=D_char; + rsbac_ta_list_remove(ta_number, + dev_major_handles.gen, + &tid.dev); +#if defined(CONFIG_RSBAC_MAC) + rsbac_ta_list_remove(ta_number, + dev_major_handles.mac, + &tid.dev); +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_ta_list_remove(ta_number, + dev_major_handles.rc, + &tid.dev); +#endif + tid.dev.type=orig_devtype; + break; + } + default: + return -RSBAC_EINVALIDTARGET; + } + } + break; + + case T_IPC: + /* rsbac_pr_debug(ds, "Removing ipc ACI\n"); */ +#if defined(CONFIG_RSBAC_MAC) + rsbac_ta_list_remove(ta_number, ipc_handles.mac, &tid.ipc); +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_ta_list_remove(ta_number, ipc_handles.rc, &tid.ipc); +#endif +#if defined(CONFIG_RSBAC_JAIL) + rsbac_ta_list_remove(ta_number, + ipc_handles.jail, &tid.ipc); +#endif + break; + + case T_USER: + /* rsbac_pr_debug(ds, "Removing user ACI"); */ + rsbac_ta_list_remove(ta_number, + user_handles.gen, &tid.user); +#if defined(CONFIG_RSBAC_MAC) + rsbac_ta_list_remove(ta_number, + user_handles.mac, &tid.user); +#endif +#if defined(CONFIG_RSBAC_DAZ) + rsbac_ta_list_remove(ta_number, + user_handles.daz, &tid.user); +#endif +#if defined(CONFIG_RSBAC_FF) + rsbac_ta_list_remove(ta_number, + user_handles.ff, &tid.user); +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_ta_list_remove(ta_number, + user_handles.rc, &tid.user); +#endif +#if defined(CONFIG_RSBAC_AUTH) + rsbac_ta_list_remove(ta_number, + user_handles.auth, &tid.user); +#endif +#if defined(CONFIG_RSBAC_CAP) + rsbac_ta_list_remove(ta_number, + user_handles.cap, &tid.user); +#endif +#if defined(CONFIG_RSBAC_JAIL) + rsbac_ta_list_remove(ta_number, + user_handles.jail, &tid.user); +#endif +#if defined(CONFIG_RSBAC_PAX) + rsbac_ta_list_remove(ta_number, + user_handles.pax, &tid.user); +#endif +#if defined(CONFIG_RSBAC_RES) + rsbac_ta_list_remove(ta_number, + user_handles.res, &tid.user); +#endif +#if defined(CONFIG_RSBAC_UDF) + rsbac_ta_list_remove(ta_number, + user_handles.udf, &tid.user); +#endif + break; + + case T_PROCESS: +/* too noisy... kicked out. + rsbac_pr_debug(ds, "Removing process ACI\n"); +*/ +#if defined(CONFIG_RSBAC_ACL) + /* process items can also have an acl_p_item -> remove first */ + error = rsbac_acl_remove_acl(ta_number, target, tid); +#endif + rsbac_ta_list_remove(ta_number, + process_handles.gen, + &tid.process); +#if defined(CONFIG_RSBAC_MAC) + /* process items can also have mac_p_trusets -> remove first */ + error = rsbac_mac_remove_p_trusets(tid.process); + rsbac_ta_list_remove(ta_number, + process_handles.mac, + &tid.process); +#endif +#if defined(CONFIG_RSBAC_DAZ) + rsbac_ta_list_remove(ta_number, + process_handles.daz, &tid.process); +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_ta_list_remove(ta_number, + process_handles.rc, + &tid.process); +#endif +#if defined(CONFIG_RSBAC_AUTH) + /* process items can also have auth_p_capsets -> remove first */ + error = rsbac_auth_remove_p_capsets(tid.process); + rsbac_ta_list_remove(ta_number, + process_handles.auth, &tid.process); +#endif +#if defined(CONFIG_RSBAC_CAP) + rsbac_ta_list_remove(ta_number, + process_handles.cap, &tid.process); +#endif +#if defined(CONFIG_RSBAC_JAIL) + rsbac_ta_list_remove(ta_number, + process_handles.jail, + &tid.process); +#endif +#if defined(CONFIG_RSBAC_UDF) + rsbac_ta_list_remove(ta_number, + process_handles.udf, &tid.process); +#endif + break; + +#ifdef CONFIG_RSBAC_UM + case T_GROUP: + /* rsbac_pr_debug(ds, "Removing group ACI\n"); */ +#if defined(CONFIG_RSBAC_RC_UM_PROT) + rsbac_ta_list_remove(ta_number, + group_handles.rc, &tid.group); +#endif + break; +#endif /* CONFIG_RSBAC_UM */ + +#ifdef CONFIG_RSBAC_NET_DEV + case T_NETDEV: +#if defined(CONFIG_RSBAC_IND_NETDEV_LOG) + rsbac_ta_list_remove(ta_number, + netdev_handles.gen, &tid.netdev); +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_ta_list_remove(ta_number, + netdev_handles.rc, &tid.netdev); +#endif + break; +#endif + +#ifdef CONFIG_RSBAC_NET_OBJ + case T_NETTEMP: +/* too noisy... kicked out. + rsbac_pr_debug(ds, "Removing nettemp ACI\n"); +*/ +#if defined(CONFIG_RSBAC_IND_NETOBJ_LOG) + rsbac_ta_list_remove(ta_number, + nettemp_handles.gen, &tid.nettemp); +#endif +#if defined(CONFIG_RSBAC_MAC) + rsbac_ta_list_remove(ta_number, + nettemp_handles.mac, &tid.nettemp); +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_ta_list_remove(ta_number, + nettemp_handles.rc, &tid.nettemp); +#endif +#if defined(CONFIG_RSBAC_ACL_NET_OBJ_PROT) + rsbac_acl_remove_acl(ta_number, T_NETTEMP_NT, tid); + rsbac_acl_remove_acl(ta_number, T_NETTEMP, tid); +#endif + break; + + case T_NETOBJ: +/* too noisy... kicked out. + rsbac_pr_debug(ds, "Removing netobj ACI\n"); +*/ +#if defined(CONFIG_RSBAC_MAC) + rsbac_ta_list_remove(ta_number, + lnetobj_handles.mac, + &tid.netobj.sock_p); + rsbac_ta_list_remove(ta_number, + rnetobj_handles.mac, + &tid.netobj.sock_p); +#endif +#if defined(CONFIG_RSBAC_RC) + rsbac_ta_list_remove(ta_number, + lnetobj_handles.rc, + &tid.netobj.sock_p); + rsbac_ta_list_remove(ta_number, + rnetobj_handles.rc, + &tid.netobj.sock_p); +#endif + break; + +#endif + + default: + return -RSBAC_EINVALIDTARGET; + } +#ifdef CONFIG_RSBAC_XSTATS + remove_count[target]++; +#endif + return error; +} +EXPORT_SYMBOL(rsbac_ta_remove_target); + +int rsbac_ta_list_all_dev(rsbac_list_ta_number_t ta_number, + struct rsbac_dev_desc_t **id_pp) +{ + int count = 0; + int tmp_count; + + tmp_count = rsbac_ta_list_count(ta_number, dev_handles.gen); + if (tmp_count > 0) + count += tmp_count; +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_ta_list_count(ta_number, dev_handles.mac); + if (tmp_count > 0) + count += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_ta_list_count(ta_number, dev_major_handles.rc); + if (tmp_count > 0) + count += tmp_count; + tmp_count = rsbac_ta_list_count(ta_number, dev_handles.rc); + if (tmp_count > 0) + count += tmp_count; +#endif + if (id_pp) { + struct rsbac_dev_desc_t *i_id_p = NULL; + char *pos = NULL; +#if defined(CONFIG_RSBAC_MAC) || defined(CONFIG_RSBAC_RC) + u_int i; +#endif + + if (count > 0) { + int i_count = 0; + + i_count = count + 20; /* max value to expect */ + *id_pp = rsbac_kmalloc_unlocked(i_count * sizeof(**id_pp)); + if (!*id_pp) + return -RSBAC_ENOMEM; + pos = (char *) *id_pp; + tmp_count = rsbac_ta_list_get_all_desc(ta_number, + dev_handles. + gen, + (void **) + &i_id_p); + if (tmp_count > 0) { + if (tmp_count > i_count) + tmp_count = i_count; + memcpy(pos, i_id_p, + tmp_count * sizeof(*i_id_p)); + rsbac_kfree(i_id_p); + count = tmp_count; + i_count -= tmp_count; + pos += tmp_count * sizeof(*i_id_p); + } else + count = 0; +#if defined(CONFIG_RSBAC_MAC) + if (i_count) { + tmp_count = + rsbac_ta_list_get_all_desc(ta_number, + dev_handles. + mac, + (void **) + &i_id_p); + if (tmp_count > 0) { + if (tmp_count > i_count) + tmp_count = i_count; + for (i = 0; i < tmp_count; i++) { + if (!rsbac_ta_list_exist + (ta_number, + dev_handles.gen, + &i_id_p[i])) { + memcpy(pos, + &i_id_p[i], + sizeof + (*i_id_p)); + pos += + sizeof + (*i_id_p); + count++; + i_count--; + } + } + rsbac_kfree(i_id_p); + } + } +#endif +#if defined(CONFIG_RSBAC_RC) + if (i_count) { + tmp_count = + rsbac_ta_list_get_all_desc(ta_number, + dev_major_handles. + rc, + (void **) + &i_id_p); + if (tmp_count > 0) { + if (tmp_count > i_count) + tmp_count = i_count; + for (i = 0; i < tmp_count; i++) { + i_id_p[i].type += + (D_block_major - + D_block); + memcpy(pos, &i_id_p[i], + sizeof(*i_id_p)); + pos += sizeof(*i_id_p); + count++; + i_count--; + } + rsbac_kfree(i_id_p); + } + } + if (i_count) { + tmp_count = + rsbac_ta_list_get_all_desc(ta_number, + dev_handles. + rc, + (void **) + &i_id_p); + if (tmp_count > 0) { + if (tmp_count > i_count) + tmp_count = i_count; + for (i = 0; i < tmp_count; i++) { + if (!rsbac_ta_list_exist + (ta_number, + dev_handles.gen, + &i_id_p[i])) +#if defined(CONFIG_RSBAC_MAC) + if (!rsbac_ta_list_exist(ta_number, dev_handles.mac, &i_id_p[i])) +#endif + { + memcpy + (pos, + &i_id_p + [i], + sizeof + (*i_id_p)); + pos += sizeof(*i_id_p); + count++; + i_count--; + } + } + rsbac_kfree(i_id_p); + } + } +#endif + if (!count) + rsbac_kfree(*id_pp); + } + } + return count; +} + +/* Copy new items, of they do not exist. Adjust list counters. */ +static int copy_new_uids(rsbac_list_handle_t list, + rsbac_list_ta_number_t ta_number, + int *count_p, + int *i_count_p, rsbac_uid_t * res_id_p) +{ + rsbac_uid_t *i_id_p = NULL; + rsbac_boolean_t found; + int tmp_count; + int i; + int j; + + if (!list || !count_p || !i_count_p || !res_id_p) + return -RSBAC_EINVALIDPOINTER; + if (!*i_count_p) + return 0; +/* rsbac_pr_debug(ds, "list %p, ta_number %u, count %u, " + "i_count %u, res_id_p %p, res_id_p[0] %u\n", + list, ta_number, *count_p, *i_count_p, res_id_p, + res_id_p[0]); */ + tmp_count = + rsbac_ta_list_get_all_desc(ta_number, list, (void **) &i_id_p); + if (tmp_count > 0) { + if (tmp_count > *i_count_p) + tmp_count = *i_count_p; + for (i = 0; i < tmp_count; i++) { + found = FALSE; + for (j = 0; j < *count_p; j++) { + if (res_id_p[j] == i_id_p[i]) { + found = TRUE; + break; + } + } + if (found == FALSE) { + res_id_p[*count_p] = i_id_p[i]; + (*count_p)++; + (*i_count_p)--; + } + } + rsbac_kfree(i_id_p); + } + return 0; +} + +int rsbac_ta_list_all_user(rsbac_list_ta_number_t ta_number, + rsbac_uid_t ** id_pp) +{ + int count = 0; + int tmp_count; + + tmp_count = rsbac_ta_list_count(ta_number, user_handles.gen); + if (tmp_count > 0) + count += tmp_count; +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_ta_list_count(ta_number, user_handles.mac); + if (tmp_count > 0) + count += tmp_count; +#endif +#if defined(CONFIG_RSBAC_DAZ) + tmp_count = rsbac_ta_list_count(ta_number, user_handles.daz); + if (tmp_count > 0) + count += tmp_count; +#endif +#if defined(CONFIG_RSBAC_FF) + tmp_count = rsbac_ta_list_count(ta_number, user_handles.ff); + if (tmp_count > 0) + count += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_ta_list_count(ta_number, user_handles.rc); + if (tmp_count > 0) + count += tmp_count; +#endif +#if defined(CONFIG_RSBAC_AUTH) + tmp_count = rsbac_ta_list_count(ta_number, user_handles.auth); + if (tmp_count > 0) + count += tmp_count; +#endif +#if defined(CONFIG_RSBAC_CAP) + tmp_count = rsbac_ta_list_count(ta_number, user_handles.cap); + if (tmp_count > 0) + count += tmp_count; +#endif +#if defined(CONFIG_RSBAC_JAIL) + tmp_count = rsbac_ta_list_count(ta_number, user_handles.jail); + if (tmp_count > 0) + count += tmp_count; +#endif +#if defined(CONFIG_RSBAC_PAX) + tmp_count = rsbac_ta_list_count(ta_number, user_handles.pax); + if (tmp_count > 0) + count += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RES) + tmp_count = rsbac_ta_list_count(ta_number, user_handles.res); + if (tmp_count > 0) + count += tmp_count; +#endif +#if defined(CONFIG_RSBAC_UDF) + tmp_count = rsbac_ta_list_count(ta_number, user_handles.udf); + if (tmp_count > 0) + count += tmp_count; +#endif + if (id_pp) { + if (count > 0) { + int i_count; + rsbac_uid_t *i_id_p = NULL; + + i_count = count + 20; /* max value to expect */ + *id_pp = rsbac_kmalloc_unlocked(i_count * sizeof(**id_pp)); + if (!*id_pp) + return -RSBAC_ENOMEM; + tmp_count = rsbac_ta_list_get_all_desc(ta_number, + user_handles. + gen, + (void **) + &i_id_p); + if (tmp_count > 0) { + if (tmp_count > i_count) + tmp_count = i_count; + memcpy(*id_pp, i_id_p, + tmp_count * sizeof(*i_id_p)); + rsbac_kfree(i_id_p); + count = tmp_count; + i_count -= tmp_count; + } else + count = 0; +#if defined(CONFIG_RSBAC_MAC) + copy_new_uids(user_handles.mac, ta_number, &count, + &i_count, *id_pp); +#endif +#if defined(CONFIG_RSBAC_DAZ) + copy_new_uids(user_handles.daz, ta_number, &count, + &i_count, *id_pp); +#endif +#if defined(CONFIG_RSBAC_FF) + copy_new_uids(user_handles.ff, ta_number, &count, + &i_count, *id_pp); +#endif +#if defined(CONFIG_RSBAC_RC) + copy_new_uids(user_handles.rc, ta_number, &count, + &i_count, *id_pp); +#endif +#if defined(CONFIG_RSBAC_AUTH) + copy_new_uids(user_handles.auth, ta_number, &count, + &i_count, *id_pp); +#endif +#if defined(CONFIG_RSBAC_CAP) + copy_new_uids(user_handles.cap, ta_number, &count, + &i_count, *id_pp); +#endif +#if defined(CONFIG_RSBAC_JAIL) + copy_new_uids(user_handles.jail, ta_number, &count, + &i_count, *id_pp); +#endif +#if defined(CONFIG_RSBAC_PAX) + copy_new_uids(user_handles.pax, ta_number, &count, + &i_count, *id_pp); +#endif +#if defined(CONFIG_RSBAC_RES) + copy_new_uids(user_handles.res, ta_number, &count, + &i_count, *id_pp); +#endif +#if defined(CONFIG_RSBAC_UDF) + copy_new_uids(user_handles.udf, ta_number, &count, + &i_count, *id_pp); +#endif + if (!count) + rsbac_kfree(*id_pp); + } + } + return count; +} + +/* Copy new items, of they do not exist. Adjust list counters. */ +static int copy_new_ipcs(rsbac_list_handle_t list, + rsbac_list_ta_number_t ta_number, + int *count_p, + int *i_count_p, struct rsbac_ipc_t * res_id_p) +{ + struct rsbac_ipc_t *i_id_p = NULL; + rsbac_boolean_t found; + int tmp_count; + int i; + int j; + + if (!list || !count_p || !i_count_p || !res_id_p) + return -RSBAC_EINVALIDPOINTER; + if (!*i_count_p) + return 0; +/* rsbac_pr_debug(ds, "list %p, ta_number %u, count %u, " + "i_count %u, res_id_p %p, res_id_p[0] %u\n", + list, ta_number, *count_p, *i_count_p, res_id_p, + res_id_p[0]); */ + tmp_count = + rsbac_ta_list_get_all_desc(ta_number, list, (void **) &i_id_p); + if (tmp_count > 0) { + if (tmp_count > *i_count_p) + tmp_count = *i_count_p; + for (i = 0; i < tmp_count; i++) { + found = FALSE; + for (j = 0; j < *count_p; j++) { + if (!ipc_compare(&res_id_p[j], &i_id_p[i])) { + found = TRUE; + break; + } + } + if (found == FALSE) { + res_id_p[*count_p] = i_id_p[i]; + (*count_p)++; + (*i_count_p)--; + } + } + rsbac_kfree(i_id_p); + } + return 0; +} + +int rsbac_ta_list_all_ipc(rsbac_list_ta_number_t ta_number, + struct rsbac_ipc_t ** id_pp) +{ + int count = 0; +#if (defined(CONFIG_RSBAC_MAC) || defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_JAIL)) + int tmp_count; +#endif + +#if defined(CONFIG_RSBAC_MAC) + tmp_count = rsbac_ta_list_count(ta_number, ipc_handles.mac); + if (tmp_count > 0) + count += tmp_count; +#endif + +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_ta_list_count(ta_number, ipc_handles.rc); + if (tmp_count > 0) + count += tmp_count; +#endif + +#if defined(CONFIG_RSBAC_JAIL) + tmp_count = rsbac_ta_list_count(ta_number, ipc_handles.jail); + if (tmp_count > 0) + count += tmp_count; +#endif + + if (id_pp) { + if (count > 0) { + int i_count; + + i_count = count + 20; /* max value to expect */ + *id_pp = rsbac_kmalloc_unlocked(i_count * sizeof(**id_pp)); + if (!*id_pp) + return -RSBAC_ENOMEM; + count = 0; + +#if defined(CONFIG_RSBAC_MAC) + copy_new_ipcs(ipc_handles.mac, ta_number, &count, + &i_count, *id_pp); +#endif + +#if defined(CONFIG_RSBAC_RC) + copy_new_ipcs(ipc_handles.rc, ta_number, &count, + &i_count, *id_pp); +#endif +#if defined(CONFIG_RSBAC_JAIL) + copy_new_ipcs(ipc_handles.jail, ta_number, &count, + &i_count, *id_pp); +#endif + + if (!count) + rsbac_kfree(*id_pp); + } + } + return count; +} + +int rsbac_ta_list_all_group(rsbac_list_ta_number_t ta_number, + rsbac_gid_t ** id_pp) +{ +#if defined(CONFIG_RSBAC_RC_UM_PROT) + int count = 0; + int tmp_count; + + tmp_count = rsbac_ta_list_count(ta_number, group_handles.rc); + if (tmp_count > 0) + count += tmp_count; + if (id_pp) { + if (count > 0) { + int i_count; + rsbac_gid_t *i_id_p = NULL; + + i_count = count + 20; /* max value to expect */ + *id_pp = rsbac_kmalloc_unlocked(i_count * sizeof(**id_pp)); + if (!*id_pp) + return -RSBAC_ENOMEM; + tmp_count = rsbac_ta_list_get_all_desc(ta_number, + group_handles. + rc, + (void **) + &i_id_p); + if (tmp_count > 0) { + if (tmp_count > i_count) + tmp_count = i_count; + memcpy(*id_pp, i_id_p, + tmp_count * sizeof(*i_id_p)); + rsbac_kfree(i_id_p); + count = tmp_count; + i_count -= tmp_count; + } else + count = 0; + if (!count) + rsbac_kfree(*id_pp); + } + } + return count; +#else + return 0; +#endif +} + + +#ifdef CONFIG_RSBAC_NET_DEV +int rsbac_ta_net_list_all_netdev(rsbac_list_ta_number_t ta_number, + rsbac_netdev_id_t ** id_pp) +{ + int count = 0; + int tmp_count; + +#if defined(CONFIG_RSBAC_IND_NETDEV_LOG) + tmp_count = rsbac_ta_list_count(ta_number, netdev_handles.gen); + if (tmp_count > 0) + count += tmp_count; +#endif +#if defined(CONFIG_RSBAC_RC) + tmp_count = rsbac_ta_list_count(ta_number, netdev_handles.rc); + if (tmp_count > 0) + count += tmp_count; +#endif + if (id_pp) { + rsbac_netdev_id_t *i_id_p = NULL; + char *pos = NULL; +#if defined(CONFIG_RSBAC_RC) + u_int i; +#endif + + if (count > 0) { + int i_count = 0; + + i_count = count + 20; /* max value to expect */ + *id_pp = rsbac_kmalloc_unlocked(i_count * sizeof(**id_pp)); + if (!*id_pp) + return -RSBAC_ENOMEM; + pos = (char *) *id_pp; +#if defined(CONFIG_RSBAC_IND_NETDEV_LOG) + tmp_count = rsbac_ta_list_get_all_desc(ta_number, + netdev_handles. + gen, + (void **) + &i_id_p); + if (tmp_count > 0) { + if (tmp_count > i_count) + tmp_count = i_count; + memcpy(pos, i_id_p, + tmp_count * sizeof(*i_id_p)); + rsbac_kfree(i_id_p); + count = tmp_count; + i_count -= tmp_count; + pos += tmp_count * sizeof(*i_id_p); + } else + count = 0; +#endif +#if defined(CONFIG_RSBAC_RC) + if (i_count) { + tmp_count = + rsbac_ta_list_get_all_desc(ta_number, + netdev_handles. + rc, + (void **) + &i_id_p); + if (tmp_count > 0) { + if (tmp_count > i_count) + tmp_count = i_count; + for (i = 0; i < tmp_count; i++) { +#if defined(CONFIG_RSBAC_IND_NETDEV_LOG) + if (!rsbac_ta_list_exist + (ta_number, + netdev_handles.gen, + &i_id_p[i])) +#endif + { + memcpy(pos, + &i_id_p[i], + sizeof + (*i_id_p)); + pos += + sizeof + (*i_id_p); + count++; + i_count--; + } + } + rsbac_kfree(i_id_p); + } + } +#endif + if (!count) + rsbac_kfree(*id_pp); + } + } + return count; +} +#endif + +#ifdef CONFIG_RSBAC_NET_OBJ +/* Get a template id from a net description */ +int rsbac_net_get_id(rsbac_list_ta_number_t ta_number, + struct rsbac_net_description_t *desc_p, + rsbac_net_temp_id_t * id_p) +{ + if (!rsbac_initialized) + return -RSBAC_ENOTINITIALIZED; + if (!id_p || !desc_p) + return -RSBAC_EINVALIDPOINTER; + if (rsbac_ta_list_get_desc(ta_number, + net_temp_handle, + id_p, desc_p, rsbac_net_compare_data) + ) + *id_p = RSBAC_NET_UNKNOWN; + return 0; +} + +/* get the template ids for a netobj */ +/* set *_temp_p to NULL, if you do not need it */ +int rsbac_ta_net_lookup_templates(rsbac_list_ta_number_t ta_number, + struct rsbac_net_obj_desc_t *netobj_p, + rsbac_net_temp_id_t * local_temp_p, + rsbac_net_temp_id_t * remote_temp_p) +{ + struct rsbac_net_description_t *rsbac_net_desc_p; + int err = 0; + struct net_device *dev; + + if (!netobj_p || !netobj_p->sock_p || !netobj_p->sock_p->sk + || !netobj_p->sock_p->ops) + return -RSBAC_EINVALIDPOINTER; + if (!local_temp_p && !remote_temp_p) + return -RSBAC_EINVALIDVALUE; + + rsbac_net_desc_p = rsbac_kmalloc_unlocked(sizeof(*rsbac_net_desc_p)); + if (!rsbac_net_desc_p) + return -RSBAC_ENOMEM; + + rsbac_net_desc_p->address_family = netobj_p->sock_p->ops->family; + rsbac_net_desc_p->type = netobj_p->sock_p->type; + rsbac_net_desc_p->protocol = netobj_p->sock_p->sk->sk_protocol; + if (netobj_p->sock_p->sk->sk_bound_dev_if) { + dev = dev_get_by_index(&init_net, netobj_p->sock_p->sk-> + sk_bound_dev_if); + if (dev) { + strcpy(rsbac_net_desc_p->netdev, dev->name); + dev_put(dev); + } else + rsbac_net_desc_p->netdev[0] = RSBAC_NET_UNKNOWN; + } else + rsbac_net_desc_p->netdev[0] = RSBAC_NET_UNKNOWN; + if (local_temp_p) { + switch (rsbac_net_desc_p->address_family) { + case AF_INET: + if (netobj_p->local_addr) { + struct sockaddr_in *addr = + netobj_p->local_addr; + + rsbac_net_desc_p->address = + &addr->sin_addr.s_addr; + rsbac_net_desc_p->address_len = + sizeof(__u32); + rsbac_net_desc_p->port = + ntohs(addr->sin_port); + } else { + rsbac_net_desc_p->address = + &inet_sk(netobj_p->sock_p->sk)-> + inet_rcv_saddr; + rsbac_net_desc_p->address_len = + sizeof(__u32); + rsbac_net_desc_p->port = + inet_sk(netobj_p->sock_p->sk)->inet_num; + } + dev = ip_dev_find(&init_net, *(__u32 *) rsbac_net_desc_p->address); + + if (dev) { + strcpy(rsbac_net_desc_p->netdev, + dev->name); + dev_put(dev); + } + break; + case AF_UNIX: + rsbac_printk(KERN_WARNING "rsbac_ta_net_lookup_templates(): unsupported family AF_UNIX, should be target UNIXSOCK or IPC-anonunix\n"); + BUG(); + return -RSBAC_EINVALIDTARGET; + + default: + rsbac_net_desc_p->address = NULL; + rsbac_net_desc_p->port = RSBAC_NET_UNKNOWN; + } + if ((err = rsbac_net_get_id(ta_number, rsbac_net_desc_p, + local_temp_p))) { + *local_temp_p = 0; + rsbac_printk(KERN_WARNING "rsbac_net_lookup_templates(): rsbac_net_get_id for local returned error %u\n", + err); + } + if (rsbac_net_desc_p->address_family == AF_INET) + rsbac_pr_debug(ds_net, + "user %u temp id for local is %u\n", + __kuid_val(current_uid()), *local_temp_p); + } + if (remote_temp_p) { + switch (rsbac_net_desc_p->address_family) { + case AF_INET: + if (netobj_p->remote_addr) { + struct sockaddr_in *addr = + netobj_p->remote_addr; + + rsbac_net_desc_p->address = + &addr->sin_addr.s_addr; + rsbac_net_desc_p->address_len = + sizeof(__u32); + rsbac_net_desc_p->port = + ntohs(addr->sin_port); + } else { + rsbac_net_desc_p->address = + &inet_sk(netobj_p->sock_p->sk)->inet_daddr; + rsbac_net_desc_p->address_len = + sizeof(__u32); + rsbac_net_desc_p->port = + ntohs(inet_sk(netobj_p->sock_p->sk)-> + inet_dport); + } + dev = ip_dev_find(&init_net, *(__u32 *) rsbac_net_desc_p->address); + + if (dev) { + strcpy(rsbac_net_desc_p->netdev, + dev->name); + dev_put(dev); + } + break; + case AF_UNIX: + rsbac_printk(KERN_WARNING "rsbac_ta_net_lookup_templates(): unsupported family AF_UNIX, should be target UNIXSOCK or IPC-anonunix\n"); + return -RSBAC_EINVALIDTARGET; + + default: + rsbac_net_desc_p->address = NULL; + rsbac_net_desc_p->address_len = 0; + rsbac_net_desc_p->port = RSBAC_NET_UNKNOWN; + } + if ((err = + rsbac_net_get_id(ta_number, rsbac_net_desc_p, + remote_temp_p))) { + *remote_temp_p = 0; + rsbac_printk(KERN_WARNING "rsbac_net_lookup_templates(): rsbac_net_get_id for remote returned error %u\n", + err); + } + if (rsbac_net_desc_p->address_family == AF_INET) + rsbac_pr_debug(ds_net, + "user %u temp id for remote is %u\n", + __kuid_val(current_uid()), *remote_temp_p); + } + rsbac_kfree(rsbac_net_desc_p); + return 0; +} + +void rsbac_net_obj_cleanup(rsbac_net_obj_id_t netobj) +{ + union rsbac_target_id_t tid; + + tid.netobj.sock_p = netobj; + rsbac_remove_target(T_NETOBJ, tid); +} + +int rsbac_ta_net_template_exists(rsbac_list_ta_number_t ta_number, + rsbac_net_temp_id_t id) +{ + return rsbac_ta_list_exist(ta_number, net_temp_handle, &id); +} + +int rsbac_ta_net_template(rsbac_list_ta_number_t ta_number, + enum rsbac_net_temp_syscall_t call, + rsbac_net_temp_id_t id, + union rsbac_net_temp_syscall_data_t *data_p) +{ + struct rsbac_net_temp_data_t int_data; + int err; + + memset(&int_data, 0, sizeof(int_data)); + int_data.address_family = AF_MAX; + int_data.type = RSBAC_NET_ANY; + int_data.protocol = RSBAC_NET_ANY; + strcpy(int_data.name, "DEFAULT"); + + switch (call) { + case NTS_new_template: + case NTS_check_id: + break; + case NTS_copy_template: + err = rsbac_ta_list_get_data_ttl(ta_number, + net_temp_handle, + NULL, + &data_p->id, &int_data); + if (err) + return err; + break; + default: + err = rsbac_ta_list_get_data_ttl(ta_number, + net_temp_handle, + NULL, &id, &int_data); + if (err) + return err; + } + /* get data values from user space */ + switch (call) { + case NTS_set_address: + if(int_data.address_family == AF_INET) { + int i; + + memcpy(&int_data.address.inet, &data_p->address.inet, + sizeof(int_data.address.inet)); + if(int_data.address.inet.nr_addr > RSBAC_NET_NR_INET_ADDR) + return -RSBAC_EINVALIDVALUE; + for(i=0; i 32) + return -RSBAC_EINVALIDVALUE; + } else { + memcpy(&int_data.address.other, &data_p->address.other, + sizeof(int_data.address.other)); + } + return rsbac_ta_list_add_ttl(ta_number, net_temp_handle, 0, + &id, &int_data); + case NTS_set_address_family: + if(int_data.address_family != data_p->address_family) { + int_data.address_family = data_p->address_family; + memset(&int_data.address, 0, sizeof(int_data.address)); + } + return rsbac_ta_list_add_ttl(ta_number, + net_temp_handle, + 0, &id, &int_data); + case NTS_set_type: + int_data.type = data_p->type; + return rsbac_ta_list_add_ttl(ta_number, + net_temp_handle, + 0, &id, &int_data); + case NTS_set_protocol: + int_data.protocol = data_p->protocol; + return rsbac_ta_list_add_ttl(ta_number, + net_temp_handle, + 0, &id, &int_data); + case NTS_set_netdev: + strncpy(int_data.netdev, data_p->netdev, RSBAC_IFNAMSIZ); + int_data.netdev[RSBAC_IFNAMSIZ] = 0; + return rsbac_ta_list_add_ttl(ta_number, + net_temp_handle, + 0, &id, &int_data); + case NTS_set_ports: + memcpy(&int_data.ports, &data_p->ports, + sizeof(int_data.ports)); + if(int_data.ports.nr_ports > RSBAC_NET_NR_PORTS) + return -RSBAC_EINVALIDVALUE; + return rsbac_ta_list_add_ttl(ta_number, + net_temp_handle, + 0, &id, &int_data); + case NTS_set_name: + strncpy(int_data.name, data_p->name, + RSBAC_NET_TEMP_NAMELEN - 1); + int_data.name[RSBAC_NET_TEMP_NAMELEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, + net_temp_handle, + 0, &id, &int_data); + case NTS_new_template: + if (rsbac_ta_list_exist(ta_number, net_temp_handle, &id)) + return -RSBAC_EEXISTS; + strncpy(int_data.name, data_p->name, + RSBAC_NET_TEMP_NAMELEN - 1); + int_data.name[RSBAC_NET_TEMP_NAMELEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, + net_temp_handle, + 0, &id, &int_data); + case NTS_copy_template: + if (rsbac_ta_list_exist(ta_number, net_temp_handle, &id)) + return -RSBAC_EEXISTS; + return rsbac_ta_list_add_ttl(ta_number, + net_temp_handle, + 0, &id, &int_data); + case NTS_delete_template: + return rsbac_ta_list_remove(ta_number, net_temp_handle, + &id); + case NTS_check_id: + if (rsbac_ta_list_exist(ta_number, net_temp_handle, &id)) { + data_p->id = id; + return 0; + } else + return -RSBAC_ENOTFOUND; + case NTS_get_address: + memcpy(&data_p->address, &int_data.address, + sizeof(int_data.address)); + return 0; + case NTS_get_address_family: + data_p->address_family = int_data.address_family; + return 0; + case NTS_get_type: + data_p->type = int_data.type; + return 0; + case NTS_get_protocol: + data_p->protocol = int_data.protocol; + return 0; + case NTS_get_netdev: + strncpy(data_p->netdev, int_data.netdev, RSBAC_IFNAMSIZ); + return 0; + case NTS_get_ports: + memcpy(&data_p->ports, &int_data.ports, + sizeof(int_data.ports)); + return 0; + case NTS_get_name: + strcpy(data_p->name, int_data.name); + return 0; + + default: + return -RSBAC_EINVALIDREQUEST; + } +} + +int rsbac_ta_net_list_all_template(rsbac_list_ta_number_t ta_number, + rsbac_net_temp_id_t ** id_pp) +{ + if (id_pp) + return rsbac_ta_list_get_all_desc(ta_number, + net_temp_handle, + (void **) id_pp); + else + return rsbac_ta_list_count(ta_number, net_temp_handle); +} + +int rsbac_ta_net_template_exist(rsbac_list_ta_number_t ta_number, + rsbac_net_temp_id_t temp) +{ + return rsbac_ta_list_exist(ta_number, net_temp_handle, &temp); +} + +int rsbac_net_remote_request(enum rsbac_adf_request_t request) +{ + switch (request) { + case R_SEND: + case R_RECEIVE: + case R_READ: + case R_WRITE: + case R_ACCEPT: + case R_CONNECT: + return TRUE; + + default: + return FALSE; + } +} + +#endif /* NET_OBJ */ + +#if defined(CONFIG_RSBAC_DAZ) +EXPORT_SYMBOL(rsbac_daz_get_ttl); +/* Get ttl for new cache items in seconds */ +rsbac_time_t rsbac_daz_get_ttl(void) +{ +#if defined(CONFIG_RSBAC_DAZ_CACHE) + return rsbac_daz_ttl; +#else + return 0; +#endif +} + +EXPORT_SYMBOL(rsbac_daz_set_ttl); +void rsbac_daz_set_ttl(rsbac_time_t ttl) +{ +#if defined(CONFIG_RSBAC_DAZ_CACHE) + if (ttl) { + if (ttl > RSBAC_LIST_MAX_AGE_LIMIT) + ttl = RSBAC_LIST_MAX_AGE_LIMIT; + rsbac_daz_ttl = ttl; + } +#endif +} + +EXPORT_SYMBOL(rsbac_daz_flush_cache); +int rsbac_daz_flush_cache(void) +{ +#if defined(CONFIG_RSBAC_DAZ_CACHE) + struct rsbac_device_list_head_t *head_p; + struct rsbac_device_list_item_t *device_p; + u_int i; + int srcu_idx; + + for (i = 0; i < RSBAC_NR_DEVICE_LISTS; i++) { + srcu_idx = srcu_read_lock(&device_list_srcu[i]); + head_p = srcu_dereference(device_head_p[i], &device_list_srcu[i]); + device_p = srcu_dereference(head_p->head, &device_list_srcu[i]); + while (device_p) { + rsbac_list_remove_all(device_p->handles.dazs); + device_p = srcu_dereference(device_p->next, &device_list_srcu[i]); + } + srcu_read_unlock(&device_list_srcu[i], srcu_idx); + } +#endif + return 0; +} +#endif + +#if defined(CONFIG_RSBAC_JAIL) +static int rsbac_jail_exists_compare(void * data1, void * data2) +{ + struct rsbac_jail_process_aci_t * aci_p = data1; + + return memcmp(&aci_p->id, data2, sizeof(rsbac_jail_id_t)); +} + +rsbac_boolean_t rsbac_jail_exists(rsbac_jail_id_t jail_id) +{ + rsbac_pid_t pid; + + if(!rsbac_ta_list_get_desc(0, + process_handles.jail, + &pid, + &jail_id, + rsbac_jail_exists_compare)) + return TRUE; + else + return FALSE; +} +#endif + +#if defined(CONFIG_RSBAC_UDF) +EXPORT_SYMBOL(rsbac_udf_get_ttl); +/* Get ttl for new cache items in seconds */ +rsbac_time_t rsbac_udf_get_ttl(void) +{ +#if defined(CONFIG_RSBAC_UDF_CACHE) + return rsbac_udf_ttl; +#else + return 0; +#endif +} + +EXPORT_SYMBOL(rsbac_udf_set_ttl); +void rsbac_udf_set_ttl(rsbac_time_t ttl) +{ +#if defined(CONFIG_RSBAC_UDF_CACHE) + if (ttl) { + if (ttl > RSBAC_LIST_MAX_AGE_LIMIT) + ttl = RSBAC_LIST_MAX_AGE_LIMIT; + rsbac_udf_ttl = ttl; + } +#endif +} + +EXPORT_SYMBOL(rsbac_udf_flush_cache); +int rsbac_udf_flush_cache(void) +{ +#if defined(CONFIG_RSBAC_UDF_CACHE) + struct rsbac_device_list_head_t *head_p; + struct rsbac_device_list_item_t *device_p; + u_int i; + int srcu_idx; + + for (i = 0; i < RSBAC_NR_DEVICE_LISTS; i++) { + srcu_idx = srcu_read_lock(&device_list_srcu[i]); + head_p = srcu_dereference(device_head_p[i], &device_list_srcu[i]); + device_p = srcu_dereference(head_p->head, &device_list_srcu[i]); + while (device_p) { + rsbac_list_remove_all(device_p->handles.udfc); + device_p = srcu_dereference(device_p->next, &device_list_srcu[i]); + } + srcu_read_unlock(&device_list_srcu[i], srcu_idx); + } +#endif + return 0; +} +#endif + +void rsbac_flags_set(unsigned long int rsbac_flags) +{ +} + +void rsbac_delayed_kfree(void * data, rsbac_time_t ttl) +{ +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) + struct rsbac_delayed_kfree_list_t * new_item; + + if (!data || !delayed_kfree_item_slab) + return; +// rsbac_printk(KERN_DEBUG "rsbac_delayed_kfree: called with data %p ttl %u\n", data, ttl); + new_item = rsbac_smalloc(delayed_kfree_item_slab); + if (!new_item) { + rsbac_printk(KERN_WARNING "rsbac_delayed_kfree: failed to allocate memory\n"); + return; + } + new_item->next = NULL; + new_item->data = data; + new_item->max_age = RSBAC_CURRENT_TIME + ttl; + spin_lock(&delayed_kfree_lock); + if(delayed_kfree_last) { + delayed_kfree_last->next = new_item; + delayed_kfree_last = new_item; + } else + delayed_kfree_last = delayed_kfree_first = new_item; +#ifdef CONFIG_RSBAC_XSTATS + delayed_kfree_count++; + delayed_kfree_used++; +#endif + spin_unlock(&delayed_kfree_lock); +#endif +} diff --git a/rsbac/data_structures/acl_data_structures.c b/rsbac/data_structures/acl_data_structures.c new file mode 100644 index 000000000000..0f7950b37a20 --- /dev/null +++ b/rsbac/data_structures/acl_data_structures.c @@ -0,0 +1,8440 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of ACL data structures */ +/* Author and (c) 1999-2016: Amon Ott */ +/* */ +/* Last modified: 25/Jan/2016 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************** */ +/* Global Variables */ +/************************************************************************** */ + +/* The following global variables are needed for access to ACL data.*/ + +static struct rsbac_acl_device_list_head_t * device_list_head_p; +static spinlock_t device_list_lock; +static struct srcu_struct device_list_srcu; +static struct lock_class_key device_list_lock_class; + +static rsbac_list_handle_t dev_handle = NULL; +static rsbac_list_handle_t dev_major_handle = NULL; +static rsbac_list_handle_t scd_handle = NULL; +static rsbac_list_handle_t group_handle = NULL; +static rsbac_list_handle_t gm_handle = NULL; +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT +static rsbac_list_handle_t netdev_handle = NULL; +#endif +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT +static rsbac_list_handle_t nettemp_nt_handle = NULL; +static rsbac_list_handle_t nettemp_handle = NULL; +static rsbac_list_handle_t netobj_handle = NULL; +#endif + +static rsbac_list_handle_t default_fd_handle = NULL; +static rsbac_list_handle_t default_dev_handle = NULL; +static rsbac_list_handle_t default_ipc_handle = NULL; +static rsbac_list_handle_t default_scd_handle = NULL; +static rsbac_list_handle_t u_handle = NULL; +static rsbac_list_handle_t default_u_handle = NULL; +static rsbac_list_handle_t default_p_handle = NULL; +#ifdef CONFIG_RSBAC_ACL_UM_PROT +static rsbac_list_handle_t g_handle = NULL; +static rsbac_list_handle_t default_g_handle = NULL; +#endif +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT +static rsbac_list_handle_t default_netdev_handle = NULL; +static rsbac_acl_rights_vector_t default_netdev_rights = 0; +#endif +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT +static rsbac_list_handle_t default_nettemp_nt_handle = NULL; +static rsbac_list_handle_t default_netobj_handle = NULL; +static rsbac_acl_rights_vector_t default_nettemp_nt_rights = 0; +static rsbac_acl_rights_vector_t default_netobj_rights = 0; +#endif + +static rsbac_acl_group_id_t group_last_new = 0; + +static rsbac_acl_rights_vector_t default_fd_rights = 0; +static rsbac_acl_rights_vector_t default_dev_rights = 0; +static rsbac_acl_rights_vector_t default_ipc_rights = 0; +static rsbac_acl_rights_vector_t default_scd_rights = 0; +static rsbac_acl_rights_vector_t default_u_rights = 0; +#ifdef CONFIG_RSBAC_ACL_UM_PROT +static rsbac_acl_rights_vector_t default_g_rights = 0; +#endif +static rsbac_acl_rights_vector_t default_p_rights = 0; + +static struct kmem_cache * acl_device_item_slab = NULL; + +/**************************************************/ +/* Declarations of external functions */ +/**************************************************/ + +rsbac_boolean_t writable(struct super_block *sb_p); + +/**************************************************/ +/* Declarations of internal functions */ +/**************************************************/ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +/* nr_hashes is always 2^n, no matter what the macros say */ + +static u_int nr_fd_hash_bits = RSBAC_ACL_NR_FD_LIST_BITS; + +static int entry_compare(void *desc1, void *desc2) +{ + int result; + struct rsbac_acl_entry_desc_t *i_desc1 = desc1; + struct rsbac_acl_entry_desc_t *i_desc2 = desc2; + + result = memcmp(&i_desc1->subj_type, + &i_desc2->subj_type, sizeof(i_desc1->subj_type)); + if (result) + return result; + else + return memcmp(&i_desc1->subj_id, + &i_desc2->subj_id, sizeof(i_desc1->subj_id)); +} + +static int dev_compare(void *desc1, void *desc2) +{ + int result; + struct rsbac_dev_desc_t *i_desc1 = desc1; + struct rsbac_dev_desc_t *i_desc2 = desc2; + + result = memcmp(&i_desc1->type, + &i_desc2->type, sizeof(i_desc1->type)); + if (result) + return result; + result = memcmp(&i_desc1->major, + &i_desc2->major, sizeof(i_desc1->major)); + if (result) + return result; + return memcmp(&i_desc1->minor, + &i_desc2->minor, sizeof(i_desc1->minor)); +} + +static int dev_major_compare(void *desc1, void *desc2) +{ + int result; + struct rsbac_dev_desc_t *i_desc1 = desc1; + struct rsbac_dev_desc_t *i_desc2 = desc2; + + result = memcmp(&i_desc1->type, + &i_desc2->type, sizeof(i_desc1->type)); + if (result) + return result; + return memcmp(&i_desc1->major, + &i_desc2->major, sizeof(i_desc1->major)); +} + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT +static int netdev_compare(void *desc1, void *desc2) +{ + return strncmp(desc1, desc2, RSBAC_IFNAMSIZ); +} +#endif + +static int fd_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + memcpy(new_data, old_data, sizeof(rsbac_acl_rights_vector_t)); + return 0; +} + +static int fd_old_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + rsbac_acl_rights_vector_t *new = new_data; + rsbac_acl_rights_vector_t *old = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + *new = (*old & RSBAC_ALL_REQUEST_VECTOR) + | ((*old & ~(RSBAC_ALL_REQUEST_VECTOR)) << + (RSBAC_ACL_SPECIAL_RIGHT_BASE - + RSBAC_ACL_OLD_SPECIAL_RIGHT_BASE)); + return 0; +} + +static rsbac_list_conv_function_t *fd_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_FD_OLD_LIST_VERSION: + return fd_conv; + case RSBAC_ACL_FD_OLD_OLD_LIST_VERSION: + return fd_old_conv; + default: + return NULL; + } +} + +static int dev_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + memcpy(new_desc, old_desc, sizeof(struct rsbac_dev_desc_t)); + memcpy(new_data, old_data, sizeof(rsbac_acl_rights_vector_t)); + return 0; +} + +static int dev_old_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + rsbac_acl_rights_vector_t *new = new_data; + rsbac_acl_rights_vector_t *old = old_data; + + memcpy(new_desc, old_desc, sizeof(struct rsbac_dev_desc_t)); + *new = (*old & RSBAC_ALL_REQUEST_VECTOR) + | ((*old & ~(RSBAC_ALL_REQUEST_VECTOR)) << + (RSBAC_ACL_SPECIAL_RIGHT_BASE - + RSBAC_ACL_OLD_SPECIAL_RIGHT_BASE)); + return 0; +} + +static int dev_old_old_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_dev_desc_t *new = new_desc; + struct rsbac_dev_t *old = old_desc; + rsbac_acl_rights_vector_t *newd = new_data; + rsbac_acl_rights_vector_t *oldd = old_data; + + + memcpy(new_data, old_data, sizeof(rsbac_acl_rights_vector_t)); + new->type = old->type; + new->major = RSBAC_MAJOR(old->id); + new->minor = RSBAC_MINOR(old->id); + *newd = (*oldd & RSBAC_ALL_REQUEST_VECTOR) + | ((*oldd & ~(RSBAC_ALL_REQUEST_VECTOR)) << + (RSBAC_ACL_SPECIAL_RIGHT_BASE - + RSBAC_ACL_OLD_SPECIAL_RIGHT_BASE)); + return 0; +} + +static rsbac_list_conv_function_t *dev_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_DEV_OLD_LIST_VERSION: + return dev_conv; + case RSBAC_ACL_DEV_OLD_OLD_LIST_VERSION: + return dev_old_conv; + case RSBAC_ACL_DEV_OLD_OLD_OLD_LIST_VERSION: + return dev_old_old_conv; + default: + return NULL; + } +} + +static int scd_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + memcpy(new_desc, old_desc, sizeof(__u8)); + memcpy(new_data, old_data, sizeof(rsbac_acl_rights_vector_t)); + return 0; +} + +static int scd_old_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + rsbac_acl_rights_vector_t *new = new_data; + rsbac_acl_rights_vector_t *old = old_data; + + memcpy(new_desc, old_desc, sizeof(__u8)); + *new = (*old & RSBAC_ALL_REQUEST_VECTOR) + | ((*old & ~(RSBAC_ALL_REQUEST_VECTOR)) << + (RSBAC_ACL_SPECIAL_RIGHT_BASE - + RSBAC_ACL_OLD_SPECIAL_RIGHT_BASE)); + return 0; +} + +static rsbac_list_conv_function_t *scd_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_SCD_OLD_LIST_VERSION: + return scd_conv; + case RSBAC_ACL_SCD_OLD_OLD_LIST_VERSION: + return scd_old_conv; + default: + return NULL; + } +} + +static int u_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + rsbac_uid_t *new = new_desc; + rsbac_old_uid_t *old = old_desc; + + *new = *old; + memcpy(new_data, old_data, sizeof(rsbac_acl_rights_vector_t)); + return 0; +} + +static rsbac_list_conv_function_t *u_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_U_OLD_LIST_VERSION: + return u_conv; + default: + return NULL; + } +} + +#ifdef CONFIG_RSBAC_ACL_UM_PROT +static int g_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + rsbac_gid_t *new = new_desc; + rsbac_old_gid_t *old = old_desc; + + *new = *old; + memcpy(new_data, old_data, sizeof(rsbac_acl_rights_vector_t)); + return 0; +} + +static rsbac_list_conv_function_t *g_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_G_OLD_LIST_VERSION: + return g_conv; + default: + return NULL; + } +} +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT +static int netdev_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + memcpy(new_desc, old_desc, sizeof(rsbac_netdev_id_t)); + memcpy(new_data, old_data, sizeof(rsbac_acl_rights_vector_t)); + return 0; +} + +static int netdev_old_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + rsbac_acl_rights_vector_t *new = new_data; + rsbac_acl_rights_vector_t *old = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_netdev_id_t)); + *new = (*old & RSBAC_ALL_REQUEST_VECTOR) + | ((*old & ~(RSBAC_ALL_REQUEST_VECTOR)) << + (RSBAC_ACL_SPECIAL_RIGHT_BASE - + RSBAC_ACL_OLD_SPECIAL_RIGHT_BASE)); + return 0; +} + +static rsbac_list_conv_function_t *netdev_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_NETDEV_OLD_LIST_VERSION: + return netdev_conv; + case RSBAC_ACL_NETDEV_OLD_OLD_LIST_VERSION: + return netdev_old_conv; + default: + return NULL; + } +} +#endif + +static int nettemp_nt_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + memcpy(new_desc, old_desc, sizeof(rsbac_net_temp_id_t)); + memcpy(new_data, old_data, sizeof(rsbac_acl_rights_vector_t)); + return 0; +} + +static int nettemp_nt_old_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + rsbac_acl_rights_vector_t *new = new_data; + rsbac_acl_rights_vector_t *old = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_net_temp_id_t)); + *new = (*old & RSBAC_ALL_REQUEST_VECTOR) + | ((*old & ~(RSBAC_ALL_REQUEST_VECTOR)) << + (RSBAC_ACL_SPECIAL_RIGHT_BASE - + RSBAC_ACL_OLD_SPECIAL_RIGHT_BASE)); + return 0; +} + +static rsbac_list_conv_function_t *nettemp_nt_get_conv(rsbac_version_t + old_version) +{ + switch (old_version) { + case RSBAC_ACL_NETTEMP_NT_OLD_LIST_VERSION: + return nettemp_nt_conv; + case RSBAC_ACL_NETTEMP_NT_OLD_OLD_LIST_VERSION: + return nettemp_nt_old_conv; + default: + return NULL; + } +} + +static int nettemp_old_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + memcpy(new_desc, old_desc, sizeof(rsbac_net_temp_id_t)); + memcpy(new_data, old_data, sizeof(rsbac_acl_rights_vector_t)); + return 0; +} + +static int nettemp_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + rsbac_acl_rights_vector_t *new = new_data; + rsbac_acl_rights_vector_t *old = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_net_temp_id_t)); + *new = (*old & RSBAC_ALL_REQUEST_VECTOR) + | ((*old & ~(RSBAC_ALL_REQUEST_VECTOR)) << + (RSBAC_ACL_SPECIAL_RIGHT_BASE - + RSBAC_ACL_OLD_SPECIAL_RIGHT_BASE)); + return 0; +} + +static rsbac_list_conv_function_t *nettemp_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_NETTEMP_OLD_LIST_VERSION: + return nettemp_conv; + case RSBAC_ACL_NETTEMP_OLD_OLD_LIST_VERSION: + return nettemp_old_conv; + default: + return NULL; + } +} + +static int netobj_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + memcpy(new_desc, old_desc, sizeof(rsbac_net_obj_id_t)); + memcpy(new_data, old_data, sizeof(rsbac_acl_rights_vector_t)); + return 0; +} + +static rsbac_list_conv_function_t *netobj_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_NETOBJ_OLD_LIST_VERSION: + return netobj_conv; + default: + return NULL; + } +} + +static int gm_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + *((rsbac_uid_t *) new_desc) = *((rsbac_old_uid_t *) old_desc); + return 0; +} + +static rsbac_list_conv_function_t *gm_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_GM_OLD_VERSION: + return gm_conv; + default: + return NULL; + } +} + + +static int common_subconv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_acl_entry_desc_t *new_d = new_desc; + struct rsbac_acl_old_entry_desc_t *old_d = old_desc; + + memcpy(new_data, old_data, sizeof(rsbac_acl_rights_vector_t)); + new_d->subj_type = old_d->subj_type; + new_d->subj_id = old_d->subj_id; + return 0; +} + +static int common_old_subconv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + rsbac_acl_rights_vector_t *new = new_data; + rsbac_acl_rights_vector_t *old = old_data; + struct rsbac_acl_entry_desc_t *new_d = new_desc; + struct rsbac_acl_old_entry_desc_t *old_d = old_desc; + + new_d->subj_type = old_d->subj_type; + new_d->subj_id = old_d->subj_id; + *new = (*old & RSBAC_ALL_REQUEST_VECTOR) + | ((*old & ~(RSBAC_ALL_REQUEST_VECTOR)) << + (RSBAC_ACL_SPECIAL_RIGHT_BASE - + RSBAC_ACL_OLD_SPECIAL_RIGHT_BASE)); + return 0; +} + +static rsbac_list_conv_function_t *fd_get_subconv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_FD_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_FD_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} + +static rsbac_list_conv_function_t *dev_get_subconv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_DEV_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_DEV_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} + +static rsbac_list_conv_function_t *scd_get_subconv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_SCD_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_SCD_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} + +static rsbac_list_conv_function_t *u_get_subconv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_U_OLD_LIST_VERSION: + return common_subconv; + default: + return NULL; + } +} + +#ifdef CONFIG_RSBAC_ACL_UM_PROT +static rsbac_list_conv_function_t *g_get_subconv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_G_OLD_LIST_VERSION: + return common_subconv; + default: + return NULL; + } +} +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT +static rsbac_list_conv_function_t *netdev_get_subconv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_NETDEV_OLD_LIST_VERSION: + return common_subconv; + default: + return NULL; + } +} +#endif + +static rsbac_list_conv_function_t *nettemp_nt_get_subconv(rsbac_version_t + old_version) +{ + switch (old_version) { + case RSBAC_ACL_NETTEMP_NT_OLD_LIST_VERSION: + return common_subconv; + default: + return NULL; + } +} + +static rsbac_list_conv_function_t *nettemp_get_subconv(rsbac_version_t + old_version) +{ + switch (old_version) { + case RSBAC_ACL_NETTEMP_OLD_LIST_VERSION: + return common_subconv; + default: + return NULL; + } +} + +static rsbac_list_conv_function_t *netobj_get_subconv(rsbac_version_t + old_version) +{ + switch (old_version) { + case RSBAC_ACL_NETOBJ_OLD_LIST_VERSION: + return common_subconv; + default: + return NULL; + } +} + +static int gm_subconv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + memcpy(new_desc, old_desc, sizeof(rsbac_acl_group_id_t)); + return 0; +} + +static rsbac_list_conv_function_t *gm_get_subconv(rsbac_version_t + old_version) +{ + switch (old_version) { + case RSBAC_ACL_GM_OLD_VERSION: + return gm_subconv; + default: + return NULL; + } +} + +static rsbac_list_conv_function_t *def_fd_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_DEF_FD_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_DEF_FD_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} + +static rsbac_list_conv_function_t *def_dev_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_DEF_DEV_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_DEF_DEV_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} + +static rsbac_list_conv_function_t *def_ipc_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_DEF_IPC_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_DEF_IPC_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} + +static rsbac_list_conv_function_t *def_scd_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_DEF_SCD_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_DEF_SCD_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} + +static rsbac_list_conv_function_t *def_u_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_DEF_U_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_DEF_U_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} + +static rsbac_list_conv_function_t *def_p_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_DEF_P_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_DEF_P_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} + +#ifdef CONFIG_RSBAC_ACL_UM_PROT +static rsbac_list_conv_function_t *def_g_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_ACL_DEF_G_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_DEF_G_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT +static rsbac_list_conv_function_t *def_netdev_get_conv(rsbac_version_t + old_version) +{ + switch (old_version) { + case RSBAC_ACL_DEF_NETDEV_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_DEF_NETDEV_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} +#endif + +static rsbac_list_conv_function_t *def_nettemp_nt_get_conv(rsbac_version_t + old_version) +{ + switch (old_version) { + case RSBAC_ACL_DEF_NETTEMP_NT_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_DEF_NETTEMP_NT_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} + +static rsbac_list_conv_function_t *def_netobj_get_conv(rsbac_version_t + old_version) +{ + switch (old_version) { + case RSBAC_ACL_DEF_NETOBJ_OLD_LIST_VERSION: + return common_subconv; + case RSBAC_ACL_DEF_NETOBJ_OLD_OLD_LIST_VERSION: + return common_old_subconv; + default: + return NULL; + } +} + + +/* acl_register_fd_lists() */ +/* register fd ACL lists for device */ + +static int acl_register_fd_lists(struct rsbac_acl_device_list_item_t + *device_p, kdev_t kdev) +{ + int err = 0; + int tmperr; + struct rsbac_list_lol_info_t lol_info; + rsbac_acl_rights_vector_t def_mask = RSBAC_ACL_DEFAULT_FD_MASK; + + if (!device_p) + return -RSBAC_EINVALIDPOINTER; + + /* register all the ACL lists of lists */ + lol_info.version = RSBAC_ACL_FD_LIST_VERSION; + lol_info.key = RSBAC_ACL_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_old_inode_nr_t); + lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */ + lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + lol_info.max_age = 0; + tmperr = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &device_p->handle, + &lol_info, + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + entry_compare, + fd_get_conv, + fd_get_subconv, &def_mask, + NULL, + RSBAC_ACL_FD_FILENAME, kdev, + nr_fd_hash_bits, + rsbac_list_hash_old_fd, + RSBAC_ACL_FD_OLD_FILENAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "acl_register_fd_lists(): registering list %s for device %02u:%02u failed with error %s!\n", + RSBAC_ACL_FD_FILENAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + return err; +} + +/* acl_detach_fd_lists() */ +/* detach from fd ACL lists for device */ + +static int acl_detach_fd_lists(struct rsbac_acl_device_list_item_t + *device_p) +{ + int err = 0; + int tmperr; + + if (!device_p) + return -RSBAC_EINVALIDPOINTER; + + /* detach all the ACL lists of lists */ + tmperr = rsbac_list_lol_detach(&device_p->handle, + RSBAC_ACL_LIST_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "acl_detach_fd_lists(): detaching from list %s for device %02u:%02u failed with error %s!\n", + RSBAC_ACL_FD_FILENAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + return err; +} + +/************************************************************************** */ +/* The lookup functions return NULL, if the item is not found, and a */ +/* pointer to the item otherwise. */ + +/* first the device item lookup */ +static struct rsbac_acl_device_list_item_t *acl_lookup_device(kdev_t kdev) +{ + struct rsbac_acl_device_list_head_t *head_p = srcu_dereference(device_list_head_p, &device_list_srcu); + struct rsbac_acl_device_list_item_t *curr = srcu_dereference(head_p->curr, &device_list_srcu); + + /* if there is no current item or it is not the right one, search... */ + if (!curr || (RSBAC_MAJOR(curr->id) != RSBAC_MAJOR(kdev)) + || (RSBAC_MINOR(curr->id) != RSBAC_MINOR(kdev)) + ) { + curr = srcu_dereference(head_p->head, &device_list_srcu); + while (curr + && ((RSBAC_MAJOR(curr->id) != RSBAC_MAJOR(kdev)) + || (RSBAC_MINOR(curr->id) != RSBAC_MINOR(kdev)) + ) + ) { + curr = srcu_dereference(curr->next, &device_list_srcu); + } + if (curr) + device_list_head_p->curr = curr; + } + /* it is the current item -> return it */ + return curr; +} + +static struct rsbac_acl_device_list_item_t *acl_lookup_device_locked(kdev_t kdev) +{ + struct rsbac_acl_device_list_item_t *curr = device_list_head_p->curr; + + /* if there is no current item or it is not the right one, search... */ + if (!curr || (RSBAC_MAJOR(curr->id) != RSBAC_MAJOR(kdev)) + || (RSBAC_MINOR(curr->id) != RSBAC_MINOR(kdev)) + ) { + curr = device_list_head_p->head; + while (curr + && ((RSBAC_MAJOR(curr->id) != RSBAC_MAJOR(kdev)) + || (RSBAC_MINOR(curr->id) != RSBAC_MINOR(kdev)) + ) + ) { + curr = curr->next; + } + if (curr) + device_list_head_p->curr = curr; + } + /* it is the current item -> return it */ + return curr; +} + +/************************************************************************** */ +/* The add_item() functions add an item to the list, set head.curr to it, */ +/* and return a pointer to the item. */ +/* These functions will NOT check, if there is already an item under the */ +/* same ID! If this happens, the lookup functions will return the old item! */ + +/* Create a device item without adding to list. No locking needed. */ +static struct rsbac_acl_device_list_item_t +*create_device_item(kdev_t kdev) +{ + struct rsbac_acl_device_list_item_t *new_item_p; + + /* allocate memory for new device, return NULL, if failed */ + if (!(new_item_p = rsbac_smalloc_clear_unlocked(acl_device_item_slab))) + return NULL; + new_item_p->id = kdev; + new_item_p->mount_count = 1; + return new_item_p; +} + +/* Add an existing device item to list. Locking needed. */ +static struct rsbac_acl_device_list_item_t +*add_device_item(struct rsbac_acl_device_list_item_t *device_p) +{ + struct rsbac_acl_device_list_head_t * new_p; + struct rsbac_acl_device_list_head_t * old_p; + + if (!device_p) + return NULL; + + spin_lock(&device_list_lock); + old_p = device_list_head_p; + new_p = rsbac_kmalloc(sizeof(*new_p)); + *new_p = *old_p; + /* add new device to device list */ + if (!new_p->head) { /* first device */ + new_p->head = device_p; + new_p->tail = device_p; + new_p->curr = device_p; + new_p->count = 1; + device_p->prev = NULL; + device_p->next = NULL; + } else { /* there is another device -> hang to tail */ + device_p->prev = new_p->tail; + device_p->next = NULL; + new_p->tail->next = device_p; + new_p->tail = device_p; + new_p->curr = device_p; + new_p->count++; + } + rcu_assign_pointer(device_list_head_p, new_p); + spin_unlock(&device_list_lock); + synchronize_srcu(&device_list_srcu); + rsbac_kfree(old_p); + return device_p; +} + +/************************************************************************** */ +/* The remove_item() functions remove an item from the list. If this item */ +/* is head, tail or curr, these pointers are set accordingly. */ +/* To speed up removing several subsequent items, curr is set to the next */ +/* item, if possible. */ +/* If the item is not found, nothing is done. */ + +static void clear_device_item(struct rsbac_acl_device_list_item_t + *device_p) +{ + if (!device_p) + return; + acl_detach_fd_lists(device_p); + rsbac_sfree(acl_device_item_slab, device_p);; +} + +static void remove_device_item(kdev_t kdev) +{ + struct rsbac_acl_device_list_item_t *item_p; + struct rsbac_acl_device_list_head_t * new_p; + struct rsbac_acl_device_list_head_t * old_p; + + old_p = device_list_head_p; + new_p = rsbac_kmalloc(sizeof(*new_p)); + *new_p = *old_p; + + /* first we must locate the item. */ + if ((item_p = acl_lookup_device_locked(kdev))) { + if (new_p->head == item_p) { /* item is head */ + if (new_p->tail == item_p) { /* item is head and tail = only item -> list will be empty */ + new_p->head = NULL; + new_p->tail = NULL; + } else { /* item is head, but not tail -> next item becomes head */ + item_p->next->prev = NULL; + new_p->head = item_p->next; + } + } else { /* item is not head */ + if (new_p->tail == item_p) { /*item is not head, but tail -> previous item becomes tail */ + item_p->prev->next = NULL; + new_p->tail = item_p->prev; + } else { /* item is neither head nor tail -> item is cut out */ + item_p->prev->next = item_p->next; + item_p->next->prev = item_p->prev; + } + } + + /* curr is no longer valid -> reset. */ + new_p->curr = NULL; + /* adjust counter */ + new_p->count--; + rcu_assign_pointer(device_list_head_p, new_p); + spin_unlock(&device_list_lock); + synchronize_rcu(); + rsbac_kfree(old_p); + + /* now we can remove the item from memory. This means cleaning up */ + /* everything below. */ + clear_device_item(item_p); + } /* end of if: item was found */ + else + spin_unlock(&device_list_lock); +} + +/************************************************* */ +/* proc functions */ +/************************************************* */ + +#if defined(CONFIG_RSBAC_PROC) +static int +acl_devices_proc_show(struct seq_file *m, void *v) +{ + struct rsbac_acl_device_list_item_t *device_p; + struct rsbac_acl_device_list_head_t *head_p; + int srcu_idx; + + if (!rsbac_is_initialized()) + return -ENOSYS; + + seq_printf(m, "%u RSBAC ACL Devices\n-------------------\n", + device_list_head_p->count); + + /* wait for read access to device_list_head */ + srcu_idx = srcu_read_lock(&device_list_srcu); + head_p = srcu_dereference(device_list_head_p, &device_list_srcu); + for (device_p = srcu_dereference(head_p->head, &device_list_srcu); device_p; + device_p = srcu_dereference(device_p->next, &device_list_srcu)) { + seq_printf(m, + "%02u:%02u with mount_count = %u\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + device_p->mount_count); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + + return 0; +} + +static int acl_devices_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, acl_devices_proc_show, NULL); +} + +static const struct file_operations acl_devices_proc_fops = { + .owner = THIS_MODULE, + .open = acl_devices_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *acl_devices; + +static int +stats_acl_proc_show(struct seq_file *m, void *v) +{ + u_int item_count = 0; + u_int member_count = 0; + struct rsbac_acl_device_list_head_t *head_p; + struct rsbac_acl_device_list_item_t *device_p; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + int srcu_idx; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "stats_acl_proc_info(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(aef_acl, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, "ACL Status\n-----------\n"); + + srcu_idx = srcu_read_lock(&device_list_srcu); + head_p = srcu_dereference(device_list_head_p, &device_list_srcu); + device_p = srcu_dereference(head_p->head, &device_list_srcu); + while (device_p) { + item_count = rsbac_list_lol_count(device_p->handle); + member_count = rsbac_list_lol_all_subcount(device_p->handle); + seq_printf(m, + "device %02u:%02u has %i file ACLs, sum of %i members\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), item_count, + member_count); + device_p = srcu_dereference(device_p->next, &device_list_srcu); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + + /* dev list */ + seq_printf(m, + "%li device ACL items, sum of %li members\n", + rsbac_list_lol_count(dev_handle), + rsbac_list_lol_all_subcount(dev_handle)); + seq_printf(m, + "%li device major ACL items, sum of %li members\n", + rsbac_list_lol_count(dev_major_handle), + rsbac_list_lol_all_subcount(dev_major_handle)); + + /* SCD list */ + seq_printf(m, + "%li scd ACL items, sum of %li members\n", + rsbac_list_lol_count(scd_handle), + rsbac_list_lol_all_subcount(scd_handle)); + + /* user list */ + seq_printf(m, + "%li user ACL items, sum of %li members\n", + rsbac_list_lol_count(u_handle), + rsbac_list_lol_all_subcount(u_handle)); + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + /* Linux group list */ + seq_printf(m, + "%li Linux group ACL items, sum of %li members\n", + rsbac_list_lol_count(g_handle), + rsbac_list_lol_all_subcount(g_handle)); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + /* netdev list */ + seq_printf(m, + "%li network device ACL items, sum of %li members\n", + rsbac_list_lol_count(netdev_handle), + rsbac_list_lol_all_subcount(netdev_handle)); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + /* nettemp_nt list */ + seq_printf(m, + "%li network template NT ACL items, sum of %li members\n", + rsbac_list_lol_count(nettemp_nt_handle), + rsbac_list_lol_all_subcount(nettemp_nt_handle)); + /* nettemp list */ + seq_printf(m, + "%li network template ACL items, sum of %li members\n", + rsbac_list_lol_count(nettemp_handle), + rsbac_list_lol_all_subcount(nettemp_handle)); + /* netobj list */ + seq_printf(m, + "%li network object ACL items, sum of %li members\n", + rsbac_list_lol_count(netobj_handle), + rsbac_list_lol_all_subcount(netobj_handle)); +#endif + + seq_printf(m, "%li groups, last new is %u\n", + rsbac_list_count(group_handle), group_last_new); + + /* protect gm list */ + seq_printf(m, + "%li group member items, sum of %li group memberships\n", + rsbac_list_lol_count(gm_handle), + rsbac_list_lol_all_subcount(gm_handle)); + return 0; +} + +static int stats_acl_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, stats_acl_proc_show, NULL); +} + +static const struct file_operations stats_acl_proc_fops = { + .owner = THIS_MODULE, + .open = stats_acl_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *stats_acl; + +static int +acl_acllist_proc_show(struct seq_file *m, void *v) +{ + u_int i, j, k; + char tmp1[80], tmp2[80]; + u_int count = 0; + int tmp_count; + int tmp_sub_count; + u_int member_count = 0; + struct rsbac_acl_device_list_head_t *head_p; + struct rsbac_acl_device_list_item_t *device_p; + rsbac_old_inode_nr_t *fd_desc_p; + struct rsbac_dev_desc_t *dev_desc_p; + __u8 *scd_desc_p; + rsbac_uid_t *u_desc_p; +#ifdef CONFIG_RSBAC_ACL_UM_PROT + rsbac_gid_t *g_desc_p; +#endif +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + rsbac_netdev_id_t *netdev_desc_p; +#endif +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + rsbac_net_temp_id_t *nettemp_desc_p; + rsbac_net_obj_id_t *netobj_desc_p; +#endif + struct rsbac_acl_entry_desc_t *sub_desc_p; + rsbac_acl_rights_vector_t rights; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + int srcu_idx; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "acl_acllist_proc_info(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(aef_acl, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, "ACL Lists\n----------\n"); + + seq_printf(m, + "Default FD ACL: %li members:", + rsbac_list_count(default_fd_handle)); + tmp_count = + rsbac_list_get_all_desc(default_fd_handle, + (void **) &sub_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (RSBAC_UID_SET(sub_desc_p[i].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_SET(sub_desc_p[i].subj_id), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + else + seq_printf(m, " %s %u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + } + rsbac_kfree(sub_desc_p); + } + + /* default_dev list */ + seq_printf(m, + "\nDefault Device ACL: %li members:", + rsbac_list_count(default_dev_handle)); + tmp_count = + rsbac_list_get_all_desc(default_dev_handle, + (void **) &sub_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (RSBAC_UID_SET(sub_desc_p[i].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_SET(sub_desc_p[i].subj_id), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + else + seq_printf(m, " %s %u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + } + rsbac_kfree(sub_desc_p); + } + + /* default_ipc_list */ + seq_printf(m, + "\nDefault IPC ACL: %li members:", + rsbac_list_count(default_ipc_handle)); + tmp_count = + rsbac_list_get_all_desc(default_ipc_handle, + (void **) &sub_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (RSBAC_UID_SET(sub_desc_p[i].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_SET(sub_desc_p[i].subj_id), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + else + seq_printf(m, " %s %u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + } + rsbac_kfree(sub_desc_p); + } + + /* default_scd_list */ + seq_printf(m, + "\nDefault SCD ACL: %li members:", + rsbac_list_count(default_scd_handle)); + tmp_count = + rsbac_list_get_all_desc(default_scd_handle, + (void **) &sub_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (RSBAC_UID_SET(sub_desc_p[i].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_SET(sub_desc_p[i].subj_id), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + else + seq_printf(m, " %s %u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + } + rsbac_kfree(sub_desc_p); + } + + /* default_u_list */ + seq_printf(m, + "\nDefault User ACL: %li members:", + rsbac_list_count(default_u_handle)); + tmp_count = + rsbac_list_get_all_desc(default_u_handle, + (void **) &sub_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (RSBAC_UID_SET(sub_desc_p[i].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_SET(sub_desc_p[i].subj_id), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + else + seq_printf(m, " %s %u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + } + rsbac_kfree(sub_desc_p); + } + + /* default_p list */ + seq_printf(m, + "\nDefault Process ACL: %li members:", + rsbac_list_count(default_p_handle)); + tmp_count = + rsbac_list_get_all_desc(default_p_handle, + (void **) &sub_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (RSBAC_UID_SET(sub_desc_p[i].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_SET(sub_desc_p[i].subj_id), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + else + seq_printf(m, " %s %u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + } + rsbac_kfree(sub_desc_p); + } +#ifdef CONFIG_RSBAC_ACL_UM_PROT + /* default_g_list */ + seq_printf(m, + "\nDefault Linux Group ACL: %li members:", + rsbac_list_count(default_g_handle)); + tmp_count = + rsbac_list_get_all_desc(default_g_handle, + (void **) &sub_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (RSBAC_UID_SET(sub_desc_p[i].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_SET(sub_desc_p[i].subj_id), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + else + seq_printf(m, " %s %u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + } + rsbac_kfree(sub_desc_p); + } +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + /* default_netdev list */ + seq_printf(m, + "\nDefault Network Device ACL: %li members:", + rsbac_list_count(default_netdev_handle)); + tmp_count = + rsbac_list_get_all_desc(default_netdev_handle, + (void **) &sub_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (RSBAC_UID_SET(sub_desc_p[i].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_SET(sub_desc_p[i].subj_id), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + else + seq_printf(m, " %s %u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + } + rsbac_kfree(sub_desc_p); + } +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + /* default_netdev list */ + seq_printf(m, + "\nDefault Network Template NT ACL: %li members:", + rsbac_list_count(default_nettemp_nt_handle)); + tmp_count = + rsbac_list_get_all_desc(default_nettemp_nt_handle, + (void **) &sub_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (RSBAC_UID_SET(sub_desc_p[i].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_SET(sub_desc_p[i].subj_id), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + else + seq_printf(m, " %s %u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + } + rsbac_kfree(sub_desc_p); + } + /* default_netobj list */ + seq_printf(m, + "\nDefault Network Object ACL: %li members:", + rsbac_list_count(default_netobj_handle)); + tmp_count = + rsbac_list_get_all_desc(default_netobj_handle, + (void **) &sub_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (RSBAC_UID_SET(sub_desc_p[i].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_SET(sub_desc_p[i].subj_id), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + else + seq_printf(m, " %s %u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [i]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[i].subj_id)); + } + rsbac_kfree(sub_desc_p); + } +#endif + + seq_printf(m, "\n\nFile/Dir/Fifo/Symlink ACLs:\n"); + + /* protect device list */ + srcu_idx = srcu_read_lock(&device_list_srcu); + head_p = srcu_dereference(device_list_head_p, &device_list_srcu); + device_p = srcu_dereference(head_p->head, &device_list_srcu); + while (device_p) { + /* reset counters */ + count = 0; + member_count = 0; + seq_printf(m, + "\nDevice %02u:%02u\n inode count mask+members", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id)); + tmp_count = rsbac_list_lol_get_all_desc(device_p->handle, + (void **) &fd_desc_p); + if (tmp_count > 0) { + for (j = 0; j < tmp_count; j++) { + seq_printf(m, + "\n%6u\t %li\t", + fd_desc_p[j], + rsbac_list_lol_subcount + (device_p->handle, + &fd_desc_p[j])); + } + if (!rsbac_list_lol_get_data + (device_p->handle, + &fd_desc_p[j], &rights)) { + seq_printf(m, + "%s\n\t\t", + u64tostracl + (tmp1, + rights)); + } + tmp_sub_count = + rsbac_list_lol_get_all_subdesc + (device_p->handle, + &fd_desc_p[j], + (void **) &sub_desc_p); + if (tmp_sub_count > 0) { + for (k = 0; + k < tmp_sub_count; + k++) { + if (RSBAC_UID_SET(sub_desc_p[k].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [k]. + subj_type), + RSBAC_UID_SET(sub_desc_p[k].subj_id), + RSBAC_UID_NUM(sub_desc_p[k].subj_id)); + else + seq_printf(m, + "%s %u, ", + get_acl_subject_type_name + (tmp1, + sub_desc_p + [k]. + subj_type), + RSBAC_UID_NUM(sub_desc_p + [k]. + subj_id)); + } + rsbac_kfree(sub_desc_p); + member_count += + tmp_sub_count; + } + count += tmp_count; + rsbac_kfree(fd_desc_p); + } + seq_printf(m, + "\n%u file ACLs, sum of %u members\n", count, + member_count); + device_p = srcu_dereference(device_p->next, &device_list_srcu); + } + /* unprotect device list */ + srcu_read_unlock(&device_list_srcu, srcu_idx); + + /* dev list */ + seq_printf(m, + "\nDevice ACLs:\ntype+id count mask+members"); + + member_count = 0; + tmp_count = + rsbac_list_lol_get_all_desc(dev_handle, (void **) &dev_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (!rsbac_list_lol_get_data + (dev_handle, &dev_desc_p[i], &rights)) { + seq_printf(m, + "\n%c%02u:%02u\t %3li\t%s\n\t\t", + 'B' + dev_desc_p[i].type, + dev_desc_p[i].major, + dev_desc_p[i].minor, + rsbac_list_lol_subcount + (dev_handle, &dev_desc_p[i]), + u64tostracl(tmp1, rights)); + } + tmp_sub_count = + rsbac_list_lol_get_all_subdesc(dev_handle, + &dev_desc_p[i], + (void **) + &sub_desc_p); + if (tmp_sub_count > 0) { + for (j = 0; j < tmp_sub_count; j++) { + if (RSBAC_UID_SET(sub_desc_p[j].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [j]. + subj_type), + RSBAC_UID_SET(sub_desc_p[j].subj_id), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + else + seq_printf(m, + "%s %u, ", + get_acl_subject_type_name + (tmp1, + sub_desc_p[j]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + } + rsbac_kfree(sub_desc_p); + member_count += tmp_sub_count; + } + } + rsbac_kfree(dev_desc_p); + } + seq_printf(m, + "\n\n%i device ACL items, sum of %u members\n", + tmp_count, member_count); + + /* dev major list */ + seq_printf(m, + "\nDevice major ACLs:\ntype+id count mask+members"); + + member_count = 0; + tmp_count = + rsbac_list_lol_get_all_desc(dev_major_handle, + (void **) &dev_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (!rsbac_list_lol_get_data + (dev_major_handle, &dev_desc_p[i], &rights)) { + seq_printf(m, + "\n%c%02u\t %3li\t%s\n\t\t", + 'B' + dev_desc_p[i].type, + dev_desc_p[i].major, + rsbac_list_lol_subcount + (dev_major_handle, + &dev_desc_p[i]), + u64tostracl(tmp1, rights)); + } + tmp_sub_count = + rsbac_list_lol_get_all_subdesc + (dev_major_handle, &dev_desc_p[i], + (void **) &sub_desc_p); + if (tmp_sub_count > 0) { + for (j = 0; j < tmp_sub_count; j++) { + if (RSBAC_UID_SET(sub_desc_p[j].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [j]. + subj_type), + RSBAC_UID_SET(sub_desc_p[j].subj_id), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + else + seq_printf(m, + "%s %u, ", + get_acl_subject_type_name + (tmp1, + sub_desc_p[j]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + } + rsbac_kfree(sub_desc_p); + member_count += tmp_sub_count; + } + } + rsbac_kfree(dev_desc_p); + } + seq_printf(m, + "\n\n%i device major ACL items, sum of %u members\n", + tmp_count, member_count); + /* scd list */ + member_count = 0; + seq_printf(m, + "\nSCD ACLs:\nname count mask+members"); + tmp_count = + rsbac_list_lol_get_all_desc(scd_handle, (void **) &scd_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (!rsbac_list_lol_get_data + (scd_handle, &scd_desc_p[i], &rights)) { + seq_printf(m, + "\n%-16s %3li\t%s\n\t\t\t", + get_acl_scd_type_name(tmp1, + scd_desc_p + [i]), + rsbac_list_lol_subcount + (scd_handle, &scd_desc_p[i]), + u64tostracl(tmp2, rights)); + } + tmp_sub_count = + rsbac_list_lol_get_all_subdesc(scd_handle, + &scd_desc_p[i], + (void **) + &sub_desc_p); + if (tmp_sub_count > 0) { + for (j = 0; j < tmp_sub_count; j++) { + if (RSBAC_UID_SET(sub_desc_p[j].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [j]. + subj_type), + RSBAC_UID_SET(sub_desc_p[j].subj_id), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + else + seq_printf(m, + "%s %u, ", + get_acl_subject_type_name + (tmp1, + sub_desc_p[j]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + } + rsbac_kfree(sub_desc_p); + member_count += tmp_sub_count; + } + } + rsbac_kfree(scd_desc_p); + } + seq_printf(m, + "\n\n%u SCD ACL items, sum of %u members\n", tmp_count, + member_count); + + /* user list */ + seq_printf(m, + "\nUser ACLs:\nuid count mask+members"); + + member_count = 0; + tmp_count = + rsbac_list_lol_get_all_desc(u_handle, (void **) &u_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (!rsbac_list_lol_get_data + (u_handle, &u_desc_p[i], &rights)) { + if (RSBAC_UID_SET(u_desc_p[i])) + seq_printf(m, + "\n%u/%u\t %3li\t%s\n\t\t", + RSBAC_UID_SET(u_desc_p[i]), + RSBAC_UID_NUM(u_desc_p[i]), + rsbac_list_lol_subcount + (u_handle, &u_desc_p[i]), + u64tostracl(tmp1, rights)); + else + seq_printf(m, + "\n%u\t %3li\t%s\n\t\t", + RSBAC_UID_NUM(u_desc_p[i]), + rsbac_list_lol_subcount + (u_handle, &u_desc_p[i]), + u64tostracl(tmp1, rights)); + } + tmp_sub_count = + rsbac_list_lol_get_all_subdesc(u_handle, + &u_desc_p[i], + (void **) + &sub_desc_p); + if (tmp_sub_count > 0) { + for (j = 0; j < tmp_sub_count; j++) { + if (RSBAC_UID_SET(sub_desc_p[j].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [j]. + subj_type), + RSBAC_UID_SET(sub_desc_p[j].subj_id), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + else + seq_printf(m, + "%s %u, ", + get_acl_subject_type_name + (tmp1, + sub_desc_p[j]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + } + rsbac_kfree(sub_desc_p); + member_count += tmp_sub_count; + } + } + rsbac_kfree(u_desc_p); + } + seq_printf(m, + "\n\n%i user ACL items, sum of %u members\n", + tmp_count, member_count); + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + /* Linux group list */ + seq_printf(m, + "\nLinux group ACLs:\ngid count mask+members"); + + member_count = 0; + tmp_count = + rsbac_list_lol_get_all_desc(g_handle, (void **) &g_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (!rsbac_list_lol_get_data + (g_handle, &g_desc_p[i], &rights)) { + if (RSBAC_GID_SET(g_desc_p[i])) + seq_printf(m, + "\n%u/%u\t %3li\t%s\n\t\t", + RSBAC_GID_SET(g_desc_p[i]), + RSBAC_GID_NUM(g_desc_p[i]), + rsbac_list_lol_subcount + (g_handle, &g_desc_p[i]), + u64tostracl(tmp1, rights)); + else + seq_printf(m, + "\n%u\t %3li\t%s\n\t\t", + RSBAC_GID_NUM(g_desc_p[i]), + rsbac_list_lol_subcount + (g_handle, &g_desc_p[i]), + u64tostracl(tmp1, rights)); + } + tmp_sub_count = + rsbac_list_lol_get_all_subdesc(g_handle, + &g_desc_p[i], + (void **) + &sub_desc_p); + if (tmp_sub_count > 0) { + for (j = 0; j < tmp_sub_count; j++) { + if (RSBAC_GID_SET(sub_desc_p[j].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [j]. + subj_type), + RSBAC_GID_SET(sub_desc_p[j].subj_id), + RSBAC_GID_NUM(sub_desc_p[j].subj_id)); + else + seq_printf(m, + "%s %u, ", + get_acl_subject_type_name + (tmp1, + sub_desc_p[j]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + } + rsbac_kfree(sub_desc_p); + member_count += tmp_sub_count; + } + } + rsbac_kfree(g_desc_p); + } + seq_printf(m, + "\n\n%i Linux group ACL items, sum of %u members\n", + tmp_count, member_count); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + /* netdev list */ + seq_printf(m, + "\nNetwork Device ACLs:\nname\t\t count mask+members"); + member_count = 0; + tmp_count = + rsbac_list_lol_get_all_desc(netdev_handle, + (void **) &netdev_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (!rsbac_list_lol_get_data + (netdev_handle, &netdev_desc_p[i], &rights)) { + seq_printf(m, + "\n%-16s %3li\t %s\n\t\t", + netdev_desc_p[i], + rsbac_list_lol_subcount + (netdev_handle, + &netdev_desc_p[i]), + u64tostracl(tmp1, rights)); + } + tmp_sub_count = + rsbac_list_lol_get_all_subdesc(netdev_handle, + &netdev_desc_p + [i], + (void **) + &sub_desc_p); + if (tmp_sub_count > 0) { + for (j = 0; j < tmp_sub_count; j++) { + if (RSBAC_UID_SET(sub_desc_p[j].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [j]. + subj_type), + RSBAC_UID_SET(sub_desc_p[j].subj_id), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + else + seq_printf(m, + "%s %u, ", + get_acl_subject_type_name + (tmp1, + sub_desc_p[j]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + } + rsbac_kfree(sub_desc_p); + member_count += tmp_sub_count; + } + } + rsbac_kfree(netdev_desc_p); + } + seq_printf(m, + "\n\n%i network device ACL items, sum of %u members\n", + tmp_count, member_count); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + /* nettemp_nt list */ + seq_printf(m, + "\nNetwork Template NT (template protection) ACLs:\nTemplate count mask+members"); + + member_count = 0; + tmp_count = + rsbac_list_lol_get_all_desc(nettemp_nt_handle, + (void **) &nettemp_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (!rsbac_list_lol_get_data + (nettemp_nt_handle, &nettemp_desc_p[i], + &rights)) { + seq_printf(m, + "\n%10u %3li\t%s\n\t\t", + nettemp_desc_p[i], + rsbac_list_lol_subcount + (nettemp_nt_handle, + &nettemp_desc_p[i]), + u64tostracl(tmp1, rights)); + } + tmp_sub_count = + rsbac_list_lol_get_all_subdesc + (nettemp_nt_handle, &nettemp_desc_p[i], + (void **) &sub_desc_p); + if (tmp_sub_count > 0) { + for (j = 0; j < tmp_sub_count; j++) { + if (RSBAC_UID_SET(sub_desc_p[j].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [j]. + subj_type), + RSBAC_UID_SET(sub_desc_p[j].subj_id), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + else + seq_printf(m, + "%s %u, ", + get_acl_subject_type_name + (tmp1, + sub_desc_p[j]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + } + rsbac_kfree(sub_desc_p); + member_count += tmp_sub_count; + } + } + rsbac_kfree(nettemp_desc_p); + } + seq_printf(m, + "\n\n%i network template NT ACL items, sum of %u members\n", + tmp_count, member_count); + + /* nettemp list */ + seq_printf(m, + "\nNetwork Template (netobj protection) ACLs:\nTemplate count mask+members"); + member_count = 0; + tmp_count = + rsbac_list_lol_get_all_desc(nettemp_handle, + (void **) &nettemp_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (!rsbac_list_lol_get_data + (nettemp_handle, &nettemp_desc_p[i], + &rights)) { + seq_printf(m, + "\n%10u %3li\t%s\n\t\t", + nettemp_desc_p[i], + rsbac_list_lol_subcount + (nettemp_handle, + &nettemp_desc_p[i]), + u64tostracl(tmp1, rights)); + } + tmp_sub_count = + rsbac_list_lol_get_all_subdesc(nettemp_handle, + &nettemp_desc_p + [i], + (void **) + &sub_desc_p); + if (tmp_sub_count > 0) { + for (j = 0; j < tmp_sub_count; j++) { + if (RSBAC_UID_SET(sub_desc_p[j].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [j]. + subj_type), + RSBAC_UID_SET(sub_desc_p[j].subj_id), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + else + seq_printf(m, + "%s %u, ", + get_acl_subject_type_name + (tmp1, + sub_desc_p[j]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + } + rsbac_kfree(sub_desc_p); + member_count += tmp_sub_count; + } + } + rsbac_kfree(nettemp_desc_p); + } + seq_printf(m, + "\n\n%i network template ACL items, sum of %u members\n", + tmp_count, member_count); + + /* netobj list */ + seq_printf(m, + "\nNetwork Object ACLs:\nObject-ID count mask+members"); + + member_count = 0; + tmp_count = + rsbac_list_lol_get_all_desc(netobj_handle, + (void **) &netobj_desc_p); + if (tmp_count > 0) { + for (i = 0; i < tmp_count; i++) { + if (!rsbac_list_lol_get_data + (netobj_handle, &netobj_desc_p[i], &rights)) { + seq_printf(m, + "\n%p %3li\t%s\n\t\t", + netobj_desc_p[i], + rsbac_list_lol_subcount + (netobj_handle, + &netobj_desc_p[i]), + u64tostracl(tmp1, rights)); + } + tmp_sub_count = + rsbac_list_lol_get_all_subdesc(netobj_handle, + &netobj_desc_p + [i], + (void **) + &sub_desc_p); + if (tmp_sub_count > 0) { + for (j = 0; j < tmp_sub_count; j++) { + if (RSBAC_UID_SET(sub_desc_p[j].subj_id)) + seq_printf(m, " %s %u/%u,", + get_acl_subject_type_name(tmp1, + sub_desc_p + [j]. + subj_type), + RSBAC_UID_SET(sub_desc_p[j].subj_id), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + else + seq_printf(m, + "%s %u, ", + get_acl_subject_type_name + (tmp1, + sub_desc_p[j]. + subj_type), + RSBAC_UID_NUM(sub_desc_p[j].subj_id)); + } + rsbac_kfree(sub_desc_p); + member_count += tmp_sub_count; + } + } + rsbac_kfree(netobj_desc_p); + } + seq_printf(m, + "\n\n%i network object ACL items, sum of %u members\n", + tmp_count, member_count); +#endif + + return 0; +} + +static int acl_acllist_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, acl_acllist_proc_show, NULL); +} + +static const struct file_operations acl_acllist_proc_fops = { + .owner = THIS_MODULE, + .open = acl_acllist_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *acl_acllist; + +static int +acl_grouplist_proc_show(struct seq_file *m, void *v) +{ + char type; + int count, sub_count; + int i, j; + u_int member_count = 0; + struct rsbac_acl_group_entry_t *entry_p; + rsbac_uid_t *user_p; + rsbac_acl_group_id_t *group_p; + rsbac_time_t *ttl_p; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "acl_grouplist_proc_info(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(aef_acl, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, "ACL Groups\n----------\n"); + + /* group list */ + seq_printf(m, + "Group list: %li groups, last new is %u\nID\ttype name\t\towner\n", + rsbac_list_count(group_handle), group_last_new); + + count = rsbac_list_get_all_data(group_handle, (void **) &entry_p); + if (count > 0) { + for (i = 0; i < count; i++) { + if (entry_p[i].type == ACLG_GLOBAL) + type = 'G'; + else + type = 'P'; + if (RSBAC_UID_SET(entry_p[i].owner)) + seq_printf(m, "%u\t%c %-18s %u/%u\n", + entry_p[i].id, type, entry_p[i].name, + RSBAC_UID_SET(entry_p[i].owner), + RSBAC_UID_NUM(entry_p[i].owner)); + else + seq_printf(m, "%u\t%c %-18s %u\n", + entry_p[i].id, type, entry_p[i].name, + RSBAC_UID_NUM(entry_p[i].owner)); + } + rsbac_kfree(entry_p); + } + + /* group member list */ + member_count = 0; + seq_printf(m, + "\nGroup memberships:\nuser count\tgroups"); + + count = rsbac_list_lol_get_all_desc(gm_handle, (void **) &user_p); + if (count > 0) { + for (i = 0; i < count; i++) { + sub_count = + rsbac_list_lol_get_all_subdesc_ttl(gm_handle, + &user_p[i], + (void **) + &group_p, + &ttl_p); + if (RSBAC_UID_SET(user_p[i])) + seq_printf(m, "\n%u/%u\t%i\t", + RSBAC_UID_SET(user_p[i]), + RSBAC_UID_NUM(user_p[i]), + sub_count); + else + seq_printf(m, "\n%u\t%i\t", + RSBAC_UID_NUM(user_p[i]), + sub_count); + if (sub_count > 0) { + for (j = 0; j < sub_count; j++) { + if (ttl_p[j]) + seq_printf(m, + "%u(ttl:%i) ", + group_p[j], + ttl_p[j]); + else + seq_printf(m, + "%u ", + group_p[j]); + } + member_count += sub_count; + rsbac_kfree(group_p); + rsbac_kfree(ttl_p); + } + } + rsbac_kfree(user_p); + } + seq_printf(m, + "\n\n%u user items, sum of %u memberships\n", count, + member_count); + return 0; +} + +static int acl_grouplist_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, acl_grouplist_proc_show, NULL); +} + +static const struct file_operations acl_grouplist_proc_fops = { + .owner = THIS_MODULE, + .open = acl_grouplist_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *acl_grouplist; + +#endif + + +/************************************************* */ +/* Init functions */ +/************************************************* */ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac/error.h. */ + +/************************************************************************** */ +/* Initialization of all ACL data structures. After this call, all ACL */ +/* data is kept in memory for performance reasons, but is written to disk */ +/* on every change. */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +static void registration_error(int err, char *listname) +#else +static void __init registration_error(int err, char *listname) +#endif +{ + if (err) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_acl(): Registering ACL %s list failed with error %s\n", + listname, get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } +} + + +#ifdef CONFIG_RSBAC_INIT_DELAY +void acl_create_def(void) +#else +void __init acl_create_def(void) +#endif +{ + if (!rsbac_list_count(default_fd_handle)) { + struct rsbac_acl_entry_desc_t desc; + struct rsbac_acl_entry_t acman_entry = + RSBAC_ACL_ACMAN_FD_ENTRY; + struct rsbac_acl_entry_t sysadm_entry = + RSBAC_ACL_SYSADM_FD_ENTRY; + struct rsbac_acl_entry_t gen_entry = + RSBAC_ACL_GENERAL_FD_ENTRY; + + rsbac_printk(KERN_WARNING "rsbac_init_acl(): File/Dir default ACL empty on dev %02u:%02u, generating standard ACL!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + desc.subj_type = acman_entry.subj_type; + desc.subj_id = acman_entry.subj_id; + rsbac_list_add(default_fd_handle, &desc, + &acman_entry.rights); + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_add(default_fd_handle, &desc, + &sysadm_entry.rights); + desc.subj_type = gen_entry.subj_type; + desc.subj_id = gen_entry.subj_id; + rsbac_list_add(default_fd_handle, &desc, + &gen_entry.rights); + } + if (!rsbac_list_count(default_dev_handle)) { + struct rsbac_acl_entry_desc_t desc; + struct rsbac_acl_entry_t acman_entry = + RSBAC_ACL_ACMAN_DEV_ENTRY; + struct rsbac_acl_entry_t sysadm_entry = + RSBAC_ACL_SYSADM_DEV_ENTRY; + struct rsbac_acl_entry_t gen_entry = + RSBAC_ACL_GENERAL_DEV_ENTRY; + + rsbac_printk(KERN_WARNING "rsbac_init_acl(): Device default ACL empty on dev %02u:%02u, generating standard ACL!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + desc.subj_type = acman_entry.subj_type; + desc.subj_id = acman_entry.subj_id; + rsbac_list_add(default_dev_handle, &desc, + &acman_entry.rights); + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_add(default_dev_handle, &desc, + &sysadm_entry.rights); + desc.subj_type = gen_entry.subj_type; + desc.subj_id = gen_entry.subj_id; + rsbac_list_add(default_dev_handle, &desc, + &gen_entry.rights); + } + if (!rsbac_list_count(default_ipc_handle)) { + struct rsbac_acl_entry_desc_t desc; + struct rsbac_acl_entry_t acman_entry = + RSBAC_ACL_ACMAN_IPC_ENTRY; + struct rsbac_acl_entry_t sysadm_entry = + RSBAC_ACL_SYSADM_IPC_ENTRY; + struct rsbac_acl_entry_t gen_entry = + RSBAC_ACL_GENERAL_IPC_ENTRY; + + rsbac_printk(KERN_WARNING "rsbac_init_acl(): IPC default ACL empty on dev %02u:%02u, generating standard ACL!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + desc.subj_type = acman_entry.subj_type; + desc.subj_id = acman_entry.subj_id; + rsbac_list_add(default_ipc_handle, &desc, + &acman_entry.rights); + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_add(default_ipc_handle, &desc, + &sysadm_entry.rights); + desc.subj_type = gen_entry.subj_type; + desc.subj_id = gen_entry.subj_id; + rsbac_list_add(default_ipc_handle, &desc, + &gen_entry.rights); + } + if (!rsbac_list_count(default_scd_handle)) { + struct rsbac_acl_entry_desc_t desc; + struct rsbac_acl_entry_t acman_entry = + RSBAC_ACL_ACMAN_SCD_ENTRY; + + rsbac_printk(KERN_WARNING "rsbac_init_acl(): SCD default ACL empty on dev %02u:%02u, generating standard ACL!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + desc.subj_type = acman_entry.subj_type; + desc.subj_id = acman_entry.subj_id; + rsbac_list_add(default_scd_handle, &desc, + &acman_entry.rights); + } + if (!rsbac_list_lol_count(scd_handle)) { + struct rsbac_acl_entry_desc_t desc; + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_SCD_MASK; + struct rsbac_acl_entry_t gen_entry = + RSBAC_ACL_GENERAL_SCD_ENTRY; +#ifdef CONFIG_RSBAC_USER_MOD_IOPERM + struct rsbac_acl_entry_t gen_ioports_entry = + RSBAC_ACL_GENERAL_SCD_IOPORTS_ENTRY; +#endif + struct rsbac_acl_entry_t gen_other_entry = + RSBAC_ACL_GENERAL_SCD_OTHER_ENTRY; + struct rsbac_acl_entry_t gen_network_entry = + RSBAC_ACL_GENERAL_SCD_NETWORK_ENTRY; + struct rsbac_acl_entry_t sysadm_entry = + RSBAC_ACL_SYSADM_SCD_ENTRY; + struct rsbac_acl_entry_t sysadm_other_entry = + RSBAC_ACL_SYSADM_SCD_OTHER_ENTRY; +#ifdef CONFIG_RSBAC_USER_MOD_IOPERM + struct rsbac_acl_entry_t sysadm_kmem_entry = + RSBAC_ACL_SYSADM_SCD_KMEM_ENTRY; +#endif + struct rsbac_acl_entry_t acman_other_entry = + RSBAC_ACL_ACMAN_SCD_OTHER_ENTRY; + struct rsbac_acl_entry_t auditor_rsbaclog_entry = + RSBAC_ACL_AUDITOR_SCD_RSBACLOG_ENTRY; + __u8 scd; + + rsbac_printk(KERN_WARNING "rsbac_init_acl(): SCD ACLs empty on dev %02u:%02u, generating standard entries!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + scd = ST_rlimit; + if (!rsbac_list_lol_add(scd_handle, &scd, &mask)) { + desc.subj_type = gen_entry.subj_type; + desc.subj_id = gen_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &gen_entry.rights); + } + for (scd = ST_time_strucs; scd <= ST_rsbac; scd++) { + if (!rsbac_list_lol_add(scd_handle, &scd, &mask)) { + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, + &desc, + &sysadm_entry. + rights); + } + } + scd = ST_rsbac_log; + if (!rsbac_list_lol_add(scd_handle, &scd, &mask)) { + desc.subj_type = auditor_rsbaclog_entry.subj_type; + desc.subj_id = auditor_rsbaclog_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &auditor_rsbaclog_entry. + rights); + } + scd = ST_network; + if (!rsbac_list_lol_add(scd_handle, &scd, &mask)) { + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &sysadm_entry.rights); + desc.subj_type = gen_network_entry.subj_type; + desc.subj_id = gen_network_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &gen_network_entry.rights); + } + scd = ST_firewall; + if (!rsbac_list_lol_add(scd_handle, &scd, &mask)) { + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &sysadm_entry.rights); + desc.subj_type = gen_network_entry.subj_type; + desc.subj_id = gen_network_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &gen_network_entry.rights); + } + scd = ST_priority; + if (!rsbac_list_lol_add(scd_handle, &scd, &mask)) { + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &sysadm_entry.rights); + } + scd = ST_sysfs; + if (!rsbac_list_lol_add(scd_handle, &scd, &mask)) { + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &sysadm_entry.rights); + } + for (scd = ST_quota; scd < ST_none; scd++) + if (!rsbac_list_lol_add(scd_handle, &scd, &mask)) { + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, + &desc, + &sysadm_entry. + rights); + } +#ifdef CONFIG_RSBAC_USER_MOD_IOPERM + scd = ST_ioports; + if (!rsbac_list_lol_add(scd_handle, &scd, &mask)) { + desc.subj_type = gen_ioports_entry.subj_type; + desc.subj_id = gen_ioports_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &gen_ioports_entry.rights); + } + scd = ST_kmem; + if (!rsbac_list_lol_add(scd_handle, &scd, &mask)) { + desc.subj_type = sysadm_kmem_entry.subj_type; + desc.subj_id = sysadm_kmem_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &sysadm_kmem_entry.rights); + } +#endif + + scd = ST_other; + if (!rsbac_list_lol_add(scd_handle, &scd, &mask)) { + desc.subj_type = sysadm_other_entry.subj_type; + desc.subj_id = sysadm_other_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &sysadm_other_entry.rights); + desc.subj_type = acman_other_entry.subj_type; + desc.subj_id = acman_other_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &acman_other_entry.rights); + desc.subj_type = gen_other_entry.subj_type; + desc.subj_id = gen_other_entry.subj_id; + rsbac_list_lol_subadd(scd_handle, &scd, &desc, + &gen_other_entry.rights); + } + } +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +void acl_create_def2(void) +#else +void __init acl_create_def2(void) +#endif +{ + if (!rsbac_list_count(default_u_handle)) { + struct rsbac_acl_entry_desc_t desc; + struct rsbac_acl_entry_t acman_entry = + RSBAC_ACL_ACMAN_U_ENTRY; + struct rsbac_acl_entry_t sysadm_entry = + RSBAC_ACL_SYSADM_U_ENTRY; + struct rsbac_acl_entry_t gen_entry = + RSBAC_ACL_GENERAL_U_ENTRY; + + rsbac_printk(KERN_WARNING "rsbac_init_acl(): User default ACL empty on dev %02u:%02u, generating standard ACL!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_add(default_u_handle, &desc, + &sysadm_entry.rights); + desc.subj_type = acman_entry.subj_type; + desc.subj_id = acman_entry.subj_id; + rsbac_list_add(default_u_handle, &desc, + &acman_entry.rights); + desc.subj_type = gen_entry.subj_type; + desc.subj_id = gen_entry.subj_id; + rsbac_list_add(default_u_handle, &desc, &gen_entry.rights); + } + if (!rsbac_list_count(default_p_handle)) { + struct rsbac_acl_entry_desc_t desc; + struct rsbac_acl_entry_t acman_entry = + RSBAC_ACL_ACMAN_P_ENTRY; + struct rsbac_acl_entry_t sysadm_entry = + RSBAC_ACL_SYSADM_P_ENTRY; + struct rsbac_acl_entry_t gen_entry = + RSBAC_ACL_GENERAL_P_ENTRY; + + rsbac_printk(KERN_WARNING "rsbac_init_acl(): Process default ACL empty on dev %02u:%02u, generating standard ACL!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_add(default_p_handle, &desc, + &sysadm_entry.rights); + desc.subj_type = acman_entry.subj_type; + desc.subj_id = acman_entry.subj_id; + rsbac_list_add(default_p_handle, &desc, + &acman_entry.rights); + desc.subj_type = gen_entry.subj_type; + desc.subj_id = gen_entry.subj_id; + rsbac_list_add(default_p_handle, &desc, &gen_entry.rights); + } + if (!rsbac_list_lol_count(gm_handle)) { + rsbac_printk(KERN_WARNING "rsbac_init_acl(): Group membership list empty on dev %02u:%02u!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + } + if (!rsbac_list_count(group_handle)) { + rsbac_printk(KERN_WARNING "rsbac_init_acl(): Group list empty on dev %02u:%02u!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + } else { + rsbac_list_get_max_desc(group_handle, &group_last_new); + } +#ifdef CONFIG_RSBAC_ACL_UM_PROT + if (!rsbac_list_count(default_g_handle)) { + struct rsbac_acl_entry_desc_t desc; + struct rsbac_acl_entry_t acman_entry = + RSBAC_ACL_ACMAN_G_ENTRY; + struct rsbac_acl_entry_t sysadm_entry = + RSBAC_ACL_SYSADM_G_ENTRY; + struct rsbac_acl_entry_t gen_entry = + RSBAC_ACL_GENERAL_G_ENTRY; + + rsbac_printk(KERN_WARNING "rsbac_init_acl(): Linux group default ACL empty on dev %02u:%02u, generating standard ACL!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_add(default_g_handle, &desc, + &sysadm_entry.rights); + desc.subj_type = acman_entry.subj_type; + desc.subj_id = acman_entry.subj_id; + rsbac_list_add(default_g_handle, &desc, + &acman_entry.rights); + desc.subj_type = gen_entry.subj_type; + desc.subj_id = gen_entry.subj_id; + rsbac_list_add(default_g_handle, &desc, &gen_entry.rights); + } +#endif +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + if (!rsbac_list_count(default_netdev_handle)) { + struct rsbac_acl_entry_desc_t desc; + struct rsbac_acl_entry_t acman_entry = + RSBAC_ACL_ACMAN_NETDEV_ENTRY; + struct rsbac_acl_entry_t sysadm_entry = + RSBAC_ACL_SYSADM_NETDEV_ENTRY; + struct rsbac_acl_entry_t gen_entry = + RSBAC_ACL_GENERAL_NETDEV_ENTRY; + + rsbac_printk(KERN_WARNING "rsbac_init_acl(): Network Device default ACL empty on dev %02u:%02u, generating standard ACL!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + desc.subj_type = acman_entry.subj_type; + desc.subj_id = acman_entry.subj_id; + rsbac_list_add(default_netdev_handle, &desc, + &acman_entry.rights); + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_add(default_netdev_handle, &desc, + &sysadm_entry.rights); + desc.subj_type = gen_entry.subj_type; + desc.subj_id = gen_entry.subj_id; + rsbac_list_add(default_netdev_handle, &desc, + &gen_entry.rights); + } +#endif +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + if (!rsbac_no_defaults + && !rsbac_list_count(default_nettemp_nt_handle)) { + struct rsbac_acl_entry_desc_t desc; + struct rsbac_acl_entry_t acman_entry = + RSBAC_ACL_ACMAN_NETTEMP_NT_ENTRY; + struct rsbac_acl_entry_t sysadm_entry = + RSBAC_ACL_SYSADM_NETTEMP_NT_ENTRY; + struct rsbac_acl_entry_t gen_entry = + RSBAC_ACL_GENERAL_NETTEMP_NT_ENTRY; + + rsbac_printk(KERN_WARNING "rsbac_init_acl(): Network Template NT (template protection) default ACL empty on dev %02u:%02u, generating standard ACL!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + desc.subj_type = acman_entry.subj_type; + desc.subj_id = acman_entry.subj_id; + rsbac_list_add(default_nettemp_nt_handle, &desc, + &acman_entry.rights); + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_add(default_nettemp_nt_handle, &desc, + &sysadm_entry.rights); + desc.subj_type = gen_entry.subj_type; + desc.subj_id = gen_entry.subj_id; + rsbac_list_add(default_nettemp_nt_handle, &desc, + &gen_entry.rights); + } + if (!rsbac_list_count(default_netobj_handle)) { + struct rsbac_acl_entry_desc_t desc; + struct rsbac_acl_entry_t acman_entry = + RSBAC_ACL_ACMAN_NETOBJ_ENTRY; + struct rsbac_acl_entry_t sysadm_entry = + RSBAC_ACL_SYSADM_NETOBJ_ENTRY; + struct rsbac_acl_entry_t gen_entry = + RSBAC_ACL_GENERAL_NETOBJ_ENTRY; + + rsbac_printk(KERN_WARNING "rsbac_init_acl(): Network Object default ACL empty on dev %02u:%02u, generating standard ACL!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev)); + desc.subj_type = acman_entry.subj_type; + desc.subj_id = acman_entry.subj_id; + rsbac_list_add(default_netobj_handle, &desc, + &acman_entry.rights); + desc.subj_type = sysadm_entry.subj_type; + desc.subj_id = sysadm_entry.subj_id; + rsbac_list_add(default_netobj_handle, &desc, + &sysadm_entry.rights); + desc.subj_type = gen_entry.subj_type; + desc.subj_id = gen_entry.subj_id; + rsbac_list_add(default_netobj_handle, &desc, + &gen_entry.rights); + } +#endif +} + +/* Because there can be no access to aci data structures before init, */ +/* rsbac_init_acl() will initialize all rw-spinlocks to unlocked. */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_init_acl(void) +#else +int __init rsbac_init_acl(void) +#endif +{ + int err = 0; + struct rsbac_acl_device_list_item_t *device_p = NULL; + char tmp[80]; + struct rsbac_list_lol_info_t lol_info; + struct rsbac_list_info_t list_info; + rsbac_acl_rights_vector_t def_mask; + + if (rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_init_acl(): RSBAC already initialized\n"); + return -RSBAC_EREINIT; + } + + /* set rw-spinlocks to unlocked status and init data structures */ + rsbac_printk(KERN_INFO "rsbac_init_acl(): Initializing RSBAC: ACL subsystem\n"); + + acl_device_item_slab = rsbac_slab_create_rcu("rsbac_acl_device_item", + sizeof(struct rsbac_acl_device_list_item_t)); + + /* Init device list */ + device_list_head_p = kmalloc(sizeof(*device_list_head_p), GFP_KERNEL); + if (!device_list_head_p) { + rsbac_printk(KERN_WARNING + "rsbac_init_acl(): Failed to allocate device_list_head\n"); + return -ENOMEM; + } + spin_lock_init(&device_list_lock); + init_srcu_struct(&device_list_srcu); + lockdep_set_class(&device_list_lock, &device_list_lock_class); + device_list_head_p->head = NULL; + device_list_head_p->tail = NULL; + device_list_head_p->curr = NULL; + device_list_head_p->count = 0; + + /* register ACL lists */ + rsbac_pr_debug(ds_acl, "Registering lists\n"); + device_p = create_device_item(rsbac_root_dev); + if (!device_p) { + rsbac_printk(KERN_CRIT + "rsbac_init_acl(): Could not create device!\n"); + return -RSBAC_ECOULDNOTADDDEVICE; + } + if ((err = acl_register_fd_lists(device_p, rsbac_root_dev))) { + rsbac_printk(KERN_WARNING "rsbac_init_acl(): File/Dir ACL registration failed for dev %02u:%02u, err %s!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev), + get_error_name(tmp, err)); + } + device_p = add_device_item(device_p); + if (!device_p) { + rsbac_printk(KERN_CRIT + "rsbac_init_acl(): Could not add device!\n"); + return -RSBAC_ECOULDNOTADDDEVICE; + } + + list_info.version = RSBAC_ACL_DEF_FD_LIST_VERSION; + list_info.key = RSBAC_ACL_LIST_KEY; + list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + list_info.max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &default_fd_handle, &list_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST, + entry_compare, + def_fd_get_conv, + NULL, + RSBAC_ACL_DEF_FD_FILENAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "default fd"); + } + + lol_info.version = RSBAC_ACL_DEV_LIST_VERSION; + lol_info.key = RSBAC_ACL_LIST_KEY; + lol_info.desc_size = sizeof(struct rsbac_dev_desc_t); + lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */ + lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + lol_info.max_age = 0; + def_mask = RSBAC_ACL_DEFAULT_DEV_MASK; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &dev_handle, &lol_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + dev_compare, + entry_compare, dev_get_conv, + dev_get_subconv, &def_mask, NULL, + RSBAC_ACL_DEV_FILENAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_dev, + NULL); + if (err) { + registration_error(err, "dev"); + } + lol_info.version = RSBAC_ACL_DEV_LIST_VERSION; + lol_info.key = RSBAC_ACL_LIST_KEY; + lol_info.desc_size = sizeof(struct rsbac_dev_desc_t); + lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */ + lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + lol_info.max_age = 0; + def_mask = RSBAC_ACL_DEFAULT_DEV_MASK; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &dev_major_handle, &lol_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + dev_major_compare, entry_compare, + dev_get_conv, dev_get_subconv, + &def_mask, NULL, + RSBAC_ACL_DEV_MAJOR_FILENAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_dev, + NULL); + if (err) { + registration_error(err, "dev major"); + } + list_info.version = RSBAC_ACL_DEF_DEV_LIST_VERSION; + list_info.key = RSBAC_ACL_LIST_KEY; + list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + list_info.max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &default_dev_handle, &list_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST, + entry_compare, + def_dev_get_conv, + NULL, + RSBAC_ACL_DEF_DEV_FILENAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "default dev"); + } + + list_info.version = RSBAC_ACL_DEF_IPC_LIST_VERSION; + list_info.key = RSBAC_ACL_LIST_KEY; + list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + list_info.max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &default_ipc_handle, &list_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST, + entry_compare, + def_ipc_get_conv, + NULL, + RSBAC_ACL_DEF_IPC_FILENAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "default ipc"); + } + + lol_info.version = RSBAC_ACL_SCD_LIST_VERSION; + lol_info.key = RSBAC_ACL_LIST_KEY; + lol_info.desc_size = sizeof(__u8); + lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */ + lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + lol_info.max_age = 0; + def_mask = RSBAC_ACL_DEFAULT_SCD_MASK; + err = rsbac_list_lol_register(RSBAC_LIST_VERSION, + &scd_handle, &lol_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA, NULL, + entry_compare, scd_get_conv, + scd_get_subconv, &def_mask, NULL, + RSBAC_ACL_SCD_FILENAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "scd"); + } + + list_info.version = RSBAC_ACL_DEF_SCD_LIST_VERSION; + list_info.key = RSBAC_ACL_LIST_KEY; + list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + list_info.max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &default_scd_handle, &list_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST, + entry_compare, + def_scd_get_conv, + NULL, + RSBAC_ACL_DEF_SCD_FILENAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "default scd"); + } + + lol_info.version = RSBAC_ACL_U_LIST_VERSION; + lol_info.key = RSBAC_ACL_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_uid_t); + lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */ + lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + lol_info.max_age = 0; + def_mask = RSBAC_ACL_DEFAULT_U_MASK; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &u_handle, &lol_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + entry_compare, + u_get_conv, + u_get_subconv, + &def_mask, + NULL, + RSBAC_ACL_U_FILENAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_uid, + NULL); + if (err) { + registration_error(err, "user"); + } + list_info.version = RSBAC_ACL_DEF_U_LIST_VERSION; + list_info.key = RSBAC_ACL_LIST_KEY; + list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + list_info.max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &default_u_handle, &list_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST, + entry_compare, + def_u_get_conv, + NULL, + RSBAC_ACL_DEF_U_FILENAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "default user"); + } + + list_info.version = RSBAC_ACL_DEF_P_LIST_VERSION; + list_info.key = RSBAC_ACL_LIST_KEY; + list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + list_info.max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &default_p_handle, &list_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST, + entry_compare, + def_p_get_conv, + NULL, + RSBAC_ACL_DEF_P_FILENAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "default process"); + } +#ifdef CONFIG_RSBAC_ACL_UM_PROT + lol_info.version = RSBAC_ACL_G_LIST_VERSION; + lol_info.key = RSBAC_ACL_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_gid_t); + lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */ + lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + lol_info.max_age = 0; + def_mask = RSBAC_ACL_DEFAULT_G_MASK; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &g_handle, &lol_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + entry_compare, + g_get_conv, + g_get_subconv, + &def_mask, + NULL, + RSBAC_ACL_G_FILENAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_gid, + NULL); + if (err) { + registration_error(err, "Linux group"); + } + list_info.version = RSBAC_ACL_DEF_G_LIST_VERSION; + list_info.key = RSBAC_ACL_LIST_KEY; + list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + list_info.max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &default_g_handle, &list_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST, + entry_compare, + def_g_get_conv, + NULL, + RSBAC_ACL_DEF_G_FILENAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "default Linux group"); + } +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + lol_info.version = RSBAC_ACL_NETDEV_LIST_VERSION; + lol_info.key = RSBAC_ACL_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_netdev_id_t); + lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */ + lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + lol_info.max_age = 0; + def_mask = RSBAC_ACL_DEFAULT_NETDEV_MASK; + err = rsbac_list_lol_register(RSBAC_LIST_VERSION, + &netdev_handle, &lol_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA, netdev_compare, + entry_compare, netdev_get_conv, + netdev_get_subconv, &def_mask, NULL, + RSBAC_ACL_NETDEV_FILENAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "netdev"); + } + list_info.version = RSBAC_ACL_DEF_NETDEV_LIST_VERSION; + list_info.key = RSBAC_ACL_LIST_KEY; + list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + list_info.max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &default_netdev_handle, &list_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST, + entry_compare, + def_netdev_get_conv, + NULL, + RSBAC_ACL_DEF_NETDEV_FILENAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "default netdev"); + } +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + lol_info.version = RSBAC_ACL_NETTEMP_NT_LIST_VERSION; + lol_info.key = RSBAC_ACL_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_net_temp_id_t); + lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */ + lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + lol_info.max_age = 0; + def_mask = RSBAC_ACL_DEFAULT_NETTEMP_MASK; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &nettemp_nt_handle, &lol_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + entry_compare, + nettemp_nt_get_conv, + nettemp_nt_get_subconv, + &def_mask, + NULL, + RSBAC_ACL_NETTEMP_NT_FILENAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_nettemp, + NULL); + if (err) { + registration_error(err, "nettemp_nt"); + } + list_info.version = RSBAC_ACL_DEF_NETTEMP_NT_LIST_VERSION; + list_info.key = RSBAC_ACL_LIST_KEY; + list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + list_info.max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &default_nettemp_nt_handle, &list_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST, + entry_compare, + def_nettemp_nt_get_conv, + NULL, + RSBAC_ACL_DEF_NETTEMP_NT_FILENAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "default nettemp_nt"); + } + lol_info.version = RSBAC_ACL_NETTEMP_LIST_VERSION; + lol_info.key = RSBAC_ACL_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_net_temp_id_t); + lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */ + lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + lol_info.max_age = 0; + def_mask = RSBAC_ACL_DEFAULT_NETOBJ_MASK; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &nettemp_handle, &lol_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + entry_compare, + nettemp_get_conv, + nettemp_get_subconv, + &def_mask, + NULL, + RSBAC_ACL_NETTEMP_FILENAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_nettemp, + NULL); + if (err) { + registration_error(err, "nettemp"); + } + lol_info.version = RSBAC_ACL_NETOBJ_LIST_VERSION; + lol_info.key = RSBAC_ACL_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_net_obj_id_t); + lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */ + lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + lol_info.max_age = 0; + def_mask = RSBAC_ACL_DEFAULT_NETOBJ_MASK; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &netobj_handle, + &lol_info, + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + entry_compare, + netobj_get_conv, + netobj_get_subconv, + &def_mask, + NULL, + RSBAC_ACL_NETOBJ_FILENAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_netobj, + NULL); + if (err) { + registration_error(err, "netobj"); + } + list_info.version = RSBAC_ACL_DEF_NETOBJ_LIST_VERSION; + list_info.key = RSBAC_ACL_LIST_KEY; + list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */ + list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */ + list_info.max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + &default_netobj_handle, &list_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST, + entry_compare, + def_netobj_get_conv, + NULL, + RSBAC_ACL_DEF_NETOBJ_FILENAME, + RSBAC_AUTO_DEV); + if (err) { + registration_error(err, "default netobj"); + } +#endif /* NET_OBJ_PROT */ + + /* groups */ + list_info.version = RSBAC_ACL_GROUP_VERSION; + list_info.key = RSBAC_ACL_LIST_KEY; + list_info.desc_size = sizeof(rsbac_acl_group_id_t); + list_info.data_size = sizeof(struct rsbac_acl_group_entry_t); + list_info.max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &group_handle, &list_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + NULL, + NULL, + RSBAC_ACL_GROUP_FILENAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "group"); + } + + /* group memberships */ + lol_info.version = RSBAC_ACL_GM_VERSION; + lol_info.key = RSBAC_ACL_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_uid_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_acl_group_id_t); + lol_info.subdata_size = 0; + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &gm_handle, &lol_info, +#if defined(CONFIG_RSBAC_ACL_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + NULL, + gm_get_conv, + gm_get_subconv, + NULL, NULL, RSBAC_ACL_GM_FILENAME, + RSBAC_AUTO_DEV, + 0, + rsbac_list_hash_uid, + NULL); + if (err) { + registration_error(err, "gm"); + } + +/* Create default lists */ + if (!rsbac_no_defaults) { + acl_create_def(); + acl_create_def2(); + } +#if defined(CONFIG_RSBAC_PROC) + acl_devices = proc_create("acl_devices", + S_IFREG | S_IRUGO, + proc_rsbac_root_p, &acl_devices_proc_fops); + stats_acl = proc_create("stats_acl", + S_IFREG | S_IRUGO, + proc_rsbac_root_p, &stats_acl_proc_fops); + acl_acllist = proc_create("acl_acllist", + S_IFREG | S_IRUGO, + proc_rsbac_root_p, &acl_acllist_proc_fops); + acl_grouplist = proc_create("acl_grouplist", + S_IFREG | S_IRUGO, + proc_rsbac_root_p, &acl_grouplist_proc_fops); +#endif + + rsbac_pr_debug(ds_acl, "Ready.\n"); + return err; +} + +int rsbac_mount_acl(kdev_t kdev) +{ + int err = 0; + struct rsbac_acl_device_list_item_t *device_p; + struct rsbac_acl_device_list_item_t *new_device_p; + int srcu_idx; + + rsbac_pr_debug(ds_acl, "mounting device %02u:%02u\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = acl_lookup_device(kdev); + /* repeated mount? */ + if (device_p) { + rsbac_printk(KERN_INFO "rsbac_mount_acl: repeated mount %u of device %02u:%02u\n", + device_p->mount_count, RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev)); + device_p->mount_count++; + srcu_read_unlock(&device_list_srcu, srcu_idx); + return 0; + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + /* OK, go on */ + new_device_p = create_device_item(kdev); + if (!new_device_p) + return -RSBAC_ECOULDNOTADDDEVICE; + + if ((err = acl_register_fd_lists(new_device_p, kdev))) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_mount_acl(): File/Dir ACL registration failed for dev %02u:%02u, err %s!\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev), + get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } + srcu_idx = srcu_read_lock(&device_list_srcu); + /* make sure to only add, if this device item has not been added in the meantime */ + device_p = acl_lookup_device(kdev); + if (device_p) { + rsbac_printk(KERN_WARNING "rsbac_mount_acl(): mount race for device %02u:%02u detected!\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + device_p->mount_count++; + /* also detaches lists */ + clear_device_item(new_device_p); + srcu_read_unlock(&device_list_srcu, srcu_idx); + } else { + srcu_read_unlock(&device_list_srcu, srcu_idx); + device_p = add_device_item(new_device_p); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_mount_acl: adding device %02u:%02u failed!\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + /* also detaches lists */ + clear_device_item(new_device_p); + err = -RSBAC_ECOULDNOTADDDEVICE; + } + } + + return err; +} + +/* When umounting a device, its file/dir ACLs must be removed. */ + +int rsbac_umount_acl(kdev_t kdev) +{ + struct rsbac_acl_device_list_item_t *device_p; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_umount(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(ds_acl, "umounting device %02u:%02u\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + /* sync of attribute lists was done in rsbac_umount */ + spin_lock(&device_list_lock); + /* OK, nobody else is working on it... */ + device_p = acl_lookup_device_locked(kdev); + if (device_p) { + if (device_p->mount_count == 1) + remove_device_item(kdev); + else { + if (device_p->mount_count > 1) { + device_p->mount_count--; + spin_unlock(&device_list_lock); + } else { + spin_unlock(&device_list_lock); + rsbac_printk(KERN_WARNING "rsbac_umount_acl: device %02u:%02u has mount_count < 1!\n", + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev)); + } + } + } + else + spin_unlock(&device_list_lock); + return 0; +} + +/***************************************************/ +/* We also need some status information... */ + +int rsbac_stats_acl(void) +{ + struct rsbac_acl_device_list_head_t *head_p; + struct rsbac_acl_device_list_item_t *device_p; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + int srcu_idx; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_stats_acl(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(aef_acl, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + rsbac_printk(KERN_INFO "ACL Status\n-----------\n"); + + /* protect device list */ + srcu_idx = srcu_read_lock(&device_list_srcu); + head_p = srcu_dereference(device_list_head_p, &device_list_srcu); + device_p = srcu_dereference(head_p->head, &device_list_srcu); + while (device_p) { + rsbac_printk(KERN_INFO "device %02u:%02u has %u file ACLs, sum of %u members\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + rsbac_list_lol_count(device_p->handle), + rsbac_list_lol_all_subcount(device_p->handle)); + device_p = srcu_dereference(device_p->next, &device_list_srcu); + } + /* unprotect device list */ + srcu_read_unlock(&device_list_srcu, srcu_idx); + + /* dev list */ + rsbac_printk(KERN_INFO "%li device major ACL items, sum of %li members\n", + rsbac_list_lol_count(dev_major_handle), + rsbac_list_lol_all_subcount(dev_major_handle)); + rsbac_printk(KERN_INFO "%li device ACL items, sum of %li members\n", + rsbac_list_lol_count(dev_handle), + rsbac_list_lol_all_subcount(dev_handle)); + + /* SCD list */ + rsbac_printk(KERN_INFO "%li scd ACL items, sum of %li members\n", + rsbac_list_lol_count(scd_handle), + rsbac_list_lol_all_subcount(scd_handle)); + + /* user list */ + rsbac_printk(KERN_INFO "%li user ACL items, sum of %li members\n", + rsbac_list_lol_count(u_handle), + rsbac_list_lol_all_subcount(u_handle)); + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + /* Linux group list */ + rsbac_printk(KERN_INFO "%li Linux group ACL items, sum of %li members\n", + rsbac_list_lol_count(g_handle), + rsbac_list_lol_all_subcount(g_handle)); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + /* netdev list */ + rsbac_printk(KERN_INFO "%li network device ACL items, sum of %li members\n", + rsbac_list_lol_count(netdev_handle), + rsbac_list_lol_all_subcount(netdev_handle)); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + /* nettemp_nt list */ + rsbac_printk(KERN_INFO "%li network template NT ACL items, sum of %li members\n", + rsbac_list_lol_count(nettemp_nt_handle), + rsbac_list_lol_all_subcount(nettemp_nt_handle)); + /* nettemp list */ + rsbac_printk(KERN_INFO "%li network template ACL items, sum of %li members\n", + rsbac_list_lol_count(nettemp_handle), + rsbac_list_lol_all_subcount(nettemp_handle)); + /* netobj list */ + rsbac_printk(KERN_INFO "%li network object ACL items, sum of %li members\n", + rsbac_list_lol_count(netobj_handle), + rsbac_list_lol_all_subcount(netobj_handle)); +#endif + + rsbac_printk(KERN_INFO "%li groups, last new is %u\n", + rsbac_list_count(group_handle), group_last_new); + + /* protect gm list */ + rsbac_printk(KERN_INFO "%li group member items, sum of %li group memberships\n", + rsbac_list_lol_count(gm_handle), + rsbac_list_lol_all_subcount(gm_handle)); + + return 0; +} + +/***************************************************/ +/* consistency checking (as far as possible) */ + +int rsbac_check_acl(int correct) +{ + struct rsbac_acl_device_list_head_t *head_p; + struct rsbac_acl_device_list_item_t *device_p; + u_long f_count = 0, f_sum = 0, tmp_count, + r_count, u_count, b_count, no_member_count; + long desc_count; + long sub_desc_count; + rsbac_old_inode_nr_t *fd_desc_p; + struct rsbac_dev_desc_t *dev_desc_p; + __u8 *scd_desc_p; + rsbac_uid_t *u_desc_p; +#ifdef CONFIG_RSBAC_ACL_UM_PROT + rsbac_gid_t *g_desc_p; +#endif +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + rsbac_netdev_id_t *netdev_desc_p; +#endif +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + rsbac_net_temp_id_t *nettemp_desc_p; + rsbac_net_obj_id_t *netobj_desc_p; +#endif + struct rsbac_acl_entry_desc_t *sub_desc_p; + rsbac_uid_t *user_p; + rsbac_acl_group_id_t *group_p; + u_int i, j; + int srcu_idx; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_check_acl(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + + /* group membership list */ + tmp_count = 0; + desc_count = + rsbac_list_lol_get_all_desc(gm_handle, (void **) &user_p); + if (desc_count > 0) { + for (i = 0; i < desc_count; i++) { + sub_desc_count = + rsbac_list_lol_get_all_subdesc(gm_handle, + &user_p[i], + (void **) + &group_p); + if (sub_desc_count > 0) { + for (j = 0; j < sub_desc_count; j++) { + if (!rsbac_list_exist + (group_handle, &group_p[j])) { + rsbac_printk(KERN_WARNING "rsbac_check_acl(): removing user %u membership in non-existent group %u!\n", + user_p[i], + group_p[j]); + rsbac_list_lol_subremove + (gm_handle, &user_p[i], + &group_p[j]); + } + } + rsbac_kfree(group_p); + } else { + /* remove empty membership list */ + if (!sub_desc_count) + rsbac_list_lol_remove(gm_handle, + &user_p[i]); + } + } + rsbac_kfree(user_p); + } + /* recalculated values! */ + rsbac_printk(KERN_INFO "rsbac_check_acl(): %li group membership items\n", + rsbac_list_lol_count(gm_handle)); + + /* group list */ + rsbac_printk(KERN_INFO "rsbac_check_acl(): %li group items\n", + rsbac_list_count(group_handle)); + + srcu_idx = srcu_read_lock(&device_list_srcu); + head_p = srcu_dereference(device_list_head_p, &device_list_srcu); + device_p = srcu_dereference(head_p->head, &device_list_srcu); + while (device_p) { /* for all sublists */ + f_count = 0; + r_count = 0; + u_count = 0; + b_count = 0; + no_member_count = 0; + + tmp_count = 0; + desc_count = rsbac_list_lol_get_all_desc(device_p->handle, + (void **) + &fd_desc_p); + if (desc_count > 0) { + for (i = 0; i < desc_count; i++) { + /* check for group existence of all ACL entries for groups */ + sub_desc_count = + rsbac_list_lol_get_all_subdesc + (device_p->handle, + &fd_desc_p[i], + (void **) &sub_desc_p); + if (sub_desc_count > 0) { + for (j = 0; + j < sub_desc_count; + j++) { + if ((sub_desc_p[j]. + subj_type == + ACLS_GROUP) + && + sub_desc_p[j]. + subj_id + && + !rsbac_list_exist + (group_handle, + &sub_desc_p + [j]. + subj_id)) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "fd_item for inode %u on device %02u:%02u has invalid group %u in ACL -> removing entry!\n", + fd_desc_p[i], + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (device_p->handle, + &fd_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "fd_item for inode %u on device %02u:%02u has invalid group %u in ACL!\n", + fd_desc_p[i], + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + sub_desc_p[j].subj_id); + } +#if defined(CONFIG_RSBAC_RC) + else if ((sub_desc_p[j].subj_type == ACLS_ROLE) + && + (sub_desc_p + [j]. + subj_id > + RC_role_max_value) + ) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "fd_item for inode %u on device %02u:%02u has invalid RC role %u in ACL -> removing entry!\n", + fd_desc_p[i], + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (device_p->handle, + &fd_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "fd_item for inode %u on device %02u:%02u has invalid role %u in ACL!\n", + fd_desc_p[i], + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + sub_desc_p[j].subj_id); + } +#endif + } + rsbac_kfree(sub_desc_p); + } + } + tmp_count++; + rsbac_kfree(fd_desc_p); + f_count += desc_count; + } + + switch (correct) { + case 2: + rsbac_printk(KERN_INFO "rsbac_check_acl(): Device %02u:%02u has %lu file/dir ACLs (%lu removed (%lu bad inodes, %lu dtimed inodes, %lu unlinked inodes, %lu had no members and default mask))\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), f_count, + b_count + r_count + u_count + + no_member_count, b_count, r_count, + u_count, no_member_count); + break; + case 1: + rsbac_printk(KERN_INFO "rsbac_check_acl(): Device %02u:%02u has %lu file/dir ACLs (%lu removed (%lu bad inodes, %lu dtimed inodes, %lu had no members and default mask), %lu unlinked inodes)\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), f_count, + b_count + r_count + no_member_count, + b_count, r_count, no_member_count, + u_count); + break; + default: + rsbac_printk(KERN_INFO "rsbac_check_acl(): Device %02u:%02u has %lu file/dir ACLs (%lu with bad inodes, %lu with dtimed inodes, %lu unlinked inodes, %lu without members and with default mask)\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), f_count, + b_count, r_count, u_count, + no_member_count); + } + f_sum += f_count; + /* go on */ + device_p = device_p->next; + } + rsbac_printk(KERN_INFO "rsbac_check_acl(): Sum of %u Devices with %lu file/dir ACLs\n", + device_list_head_p->count, f_sum); + /* free access to device_list_head */ + srcu_read_unlock(&device_list_srcu, srcu_idx); + + /* dev list */ + tmp_count = 0; + desc_count = + rsbac_list_lol_get_all_desc(dev_handle, (void **) &dev_desc_p); + if (desc_count > 0) { + for (i = 0; i < desc_count; i++) { + /* check for group existence of all ACL entries for groups */ + sub_desc_count = + rsbac_list_lol_get_all_subdesc(dev_handle, + &dev_desc_p[i], + (void **) + &sub_desc_p); + if (sub_desc_count > 0) { + for (j = 0; j < sub_desc_count; j++) { + if ((sub_desc_p[j].subj_type == + ACLS_GROUP) + && sub_desc_p[j].subj_id + && + !rsbac_list_exist(group_handle, + &sub_desc_p + [j]. + subj_id)) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "dev_item %c%02u:%02u, has invalid group %u in ACL -> removing entry!\n", + 'B' + dev_desc_p[i].type, + dev_desc_p[i].major, + dev_desc_p[i].minor, + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (dev_handle, + &dev_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "dev_item %c%02u:%02u, has invalid group %u in ACL!\n", + 'B' + dev_desc_p[i].type, + dev_desc_p[i].major, + dev_desc_p[i].minor, + sub_desc_p[j].subj_id); + } +#if defined(CONFIG_RSBAC_RC) + else if ((sub_desc_p[j]. + subj_type == ACLS_ROLE) + && (sub_desc_p[j]. + subj_id > + RC_role_max_value) + ) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "dev_item %c%02u:%02u, has invalid role %u in ACL -> removing entry!\n", + 'B' + dev_desc_p[i].type, + dev_desc_p[i].major, + dev_desc_p[i].minor, + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (dev_handle, + &dev_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "dev_item %c%02u:%02u, has invalid role %u in ACL!\n", + 'B' + dev_desc_p[i].type, + dev_desc_p[i].major, + dev_desc_p[i].minor, + sub_desc_p[j].subj_id); + } +#endif + } + rsbac_kfree(sub_desc_p); + } + } + rsbac_kfree(dev_desc_p); + f_sum += desc_count; + } + rsbac_printk(KERN_INFO "rsbac_check_acl(): %li device items\n", + desc_count); + tmp_count = 0; + desc_count = + rsbac_list_lol_get_all_desc(dev_major_handle, + (void **) &dev_desc_p); + if (desc_count > 0) { + for (i = 0; i < desc_count; i++) { + /* check for group existence of all ACL entries for groups */ + sub_desc_count = + rsbac_list_lol_get_all_subdesc + (dev_major_handle, &dev_desc_p[i], + (void **) &sub_desc_p); + if (sub_desc_count > 0) { + for (j = 0; j < sub_desc_count; j++) { + if ((sub_desc_p[j].subj_type == + ACLS_GROUP) + && sub_desc_p[j].subj_id + && + !rsbac_list_exist(group_handle, + &sub_desc_p + [j]. + subj_id)) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "dev_item %c%02u:%02u, has invalid group %u in ACL -> removing entry!\n", + 'B' + dev_desc_p[i].type, + dev_desc_p[i].major, + dev_desc_p[i].minor, + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (dev_major_handle, + &dev_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "dev_item %c%02u:%02u, has invalid group %u in ACL!\n", + 'B' + dev_desc_p[i].type, + dev_desc_p[i].major, + dev_desc_p[i].minor, + sub_desc_p[j].subj_id); + } +#if defined(CONFIG_RSBAC_RC) + else if ((sub_desc_p[j]. + subj_type == ACLS_ROLE) + && (sub_desc_p[j]. + subj_id > + RC_role_max_value) + ) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "dev_item %c%02u:%02u, has invalid role %u in ACL -> removing entry!\n", + 'B' + dev_desc_p[i].type, + dev_desc_p[i].major, + dev_desc_p[i].minor, + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (dev_major_handle, + &dev_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "dev_item %c%02u:%02u, has invalid role %u in ACL!\n", + 'B' + dev_desc_p[i].type, + dev_desc_p[i].major, + dev_desc_p[i].minor, + sub_desc_p[j].subj_id); + } +#endif + } + rsbac_kfree(sub_desc_p); + } + } + rsbac_kfree(dev_desc_p); + f_sum += desc_count; + } + rsbac_printk(KERN_INFO "rsbac_check_acl(): %li device items\n", + desc_count); + + /* SCD list */ + tmp_count = 0; + desc_count = + rsbac_list_lol_get_all_desc(scd_handle, (void **) &scd_desc_p); + if (desc_count > 0) { + for (i = 0; i < desc_count; i++) { + /* check for group existence of all ACL entries for groups */ + sub_desc_count = + rsbac_list_lol_get_all_subdesc(scd_handle, + &scd_desc_p[i], + (void **) + &sub_desc_p); + if (sub_desc_count > 0) { + for (j = 0; j < sub_desc_count; j++) { + if ((sub_desc_p[j].subj_type == + ACLS_GROUP) + && sub_desc_p[j].subj_id + && + !rsbac_list_exist(group_handle, + &sub_desc_p + [j]. + subj_id)) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "scd_item %u has invalid group %u in ACL -> removing entry!\n", + scd_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (scd_handle, + &scd_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "scd_item %u has invalid group %u in ACL!\n", + scd_desc_p[i], + sub_desc_p[j].subj_id); + } +#if defined(CONFIG_RSBAC_RC) + else if ((sub_desc_p[j]. + subj_type == ACLS_ROLE) + && (sub_desc_p[j]. + subj_id > + RC_role_max_value) + ) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "scd_item %u has invalid role %u in ACL -> removing entry!\n", + scd_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (scd_handle, + &scd_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "scd_item %u has invalid role %u in ACL!\n", + scd_desc_p[i], + sub_desc_p[j].subj_id); + } +#endif + } + rsbac_kfree(sub_desc_p); + } + } + rsbac_kfree(scd_desc_p); + f_sum += desc_count; + } + rsbac_printk(KERN_INFO "rsbac_check_acl(): %li SCD items\n", + desc_count); + + /* User list */ + tmp_count = 0; + desc_count = + rsbac_list_lol_get_all_desc(u_handle, (void **) &u_desc_p); + if (desc_count > 0) { + for (i = 0; i < desc_count; i++) { + /* check for group existence of all ACL entries for groups */ + sub_desc_count = + rsbac_list_lol_get_all_subdesc(u_handle, + &u_desc_p[i], + (void **) + &sub_desc_p); + if (sub_desc_count > 0) { + for (j = 0; j < sub_desc_count; j++) { + if ((sub_desc_p[j].subj_type == + ACLS_GROUP) + && sub_desc_p[j].subj_id + && + !rsbac_list_exist(group_handle, + &sub_desc_p + [j]. + subj_id)) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "u_item %u has invalid group %u in ACL -> removing entry!\n", + u_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (u_handle, + &u_desc_p[i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "u_item %u has invalid group %u in ACL!\n", + u_desc_p[i], + sub_desc_p[j].subj_id); + } +#if defined(CONFIG_RSBAC_RC) + else if ((sub_desc_p[j]. + subj_type == ACLS_ROLE) + && (sub_desc_p[j]. + subj_id > + RC_role_max_value) + ) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "u_item %u has invalid role %u in ACL -> removing entry!\n", + u_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (u_handle, + &u_desc_p[i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "u_item %u has invalid role %u in ACL!\n", + u_desc_p[i], + sub_desc_p[j].subj_id); + } +#endif + } + rsbac_kfree(sub_desc_p); + } + } + rsbac_kfree(u_desc_p); + f_sum += desc_count; + } + rsbac_printk(KERN_INFO "rsbac_check_acl(): %li user items\n", + desc_count); + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + /* User list */ + tmp_count = 0; + desc_count = + rsbac_list_lol_get_all_desc(g_handle, (void **) &g_desc_p); + if (desc_count > 0) { + for (i = 0; i < desc_count; i++) { + /* check for group existence of all ACL entries for groups */ + sub_desc_count = + rsbac_list_lol_get_all_subdesc(g_handle, + &g_desc_p[i], + (void **) + &sub_desc_p); + if (sub_desc_count > 0) { + for (j = 0; j < sub_desc_count; j++) { + if ((sub_desc_p[j].subj_type == + ACLS_GROUP) + && sub_desc_p[j].subj_id + && + !rsbac_list_exist(group_handle, + &sub_desc_p + [j]. + subj_id)) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "g_item %u has invalid group %u in ACL -> removing entry!\n", + g_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (g_handle, + &g_desc_p[i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "g_item %u has invalid group %u in ACL!\n", + g_desc_p[i], + sub_desc_p[j].subj_id); + } +#if defined(CONFIG_RSBAC_RC) + else if ((sub_desc_p[j]. + subj_type == ACLS_ROLE) + && (sub_desc_p[j]. + subj_id > + RC_role_max_value) + ) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "g_item %u has invalid role %u in ACL -> removing entry!\n", + g_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (g_handle, + &g_desc_p[i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "g_item %u has invalid role %u in ACL!\n", + g_desc_p[i], + sub_desc_p[j].subj_id); + } +#endif + } + rsbac_kfree(sub_desc_p); + } + } + rsbac_kfree(g_desc_p); + f_sum += desc_count; + } + rsbac_printk(KERN_INFO "rsbac_check_acl(): %li Linux group items\n", + desc_count); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + /* netdev list */ + tmp_count = 0; + desc_count = + rsbac_list_lol_get_all_desc(netdev_handle, + (void **) &netdev_desc_p); + if (desc_count > 0) { + for (i = 0; i < desc_count; i++) { + /* check for group existence of all ACL entries for groups */ + sub_desc_count = + rsbac_list_lol_get_all_subdesc(netdev_handle, + &netdev_desc_p + [i], + (void **) + &sub_desc_p); + if (sub_desc_count > 0) { + for (j = 0; j < sub_desc_count; j++) { + if ((sub_desc_p[j].subj_type == + ACLS_GROUP) + && sub_desc_p[j].subj_id + && + !rsbac_list_exist(group_handle, + &sub_desc_p + [j]. + subj_id)) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "netdev_item %s has invalid group %u in ACL -> removing entry!\n", + netdev_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (netdev_handle, + &netdev_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "netdev_item %s has invalid group %u in ACL!\n", + netdev_desc_p[i], + sub_desc_p[j].subj_id); + } +#if defined(CONFIG_RSBAC_RC) + else if ((sub_desc_p[j]. + subj_type == ACLS_ROLE) + && (sub_desc_p[j]. + subj_id > + RC_role_max_value) + ) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "netdev_item %s has invalid role %u in ACL -> removing entry!\n", + netdev_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (netdev_handle, + &netdev_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "netdev_item %s has invalid role %u in ACL!\n", + netdev_desc_p[i], + sub_desc_p[j].subj_id); + } +#endif + } + rsbac_kfree(sub_desc_p); + } + } + rsbac_kfree(netdev_desc_p); + f_sum += desc_count; + } + rsbac_printk(KERN_INFO "rsbac_check_acl(): %li network device items\n", + desc_count); +#endif /* NET_DEV_PROT */ + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + /* nettemp_nt list */ + tmp_count = 0; + desc_count = + rsbac_list_lol_get_all_desc(nettemp_nt_handle, + (void **) &nettemp_desc_p); + if (desc_count > 0) { + for (i = 0; i < desc_count; i++) { + /* check for group existence of all ACL entries for groups */ + sub_desc_count = + rsbac_list_lol_get_all_subdesc + (nettemp_nt_handle, &nettemp_desc_p[i], + (void **) &sub_desc_p); + if (sub_desc_count > 0) { + for (j = 0; j < sub_desc_count; j++) { + if ((sub_desc_p[j].subj_type == + ACLS_GROUP) + && sub_desc_p[j].subj_id + && + !rsbac_list_exist(group_handle, + &sub_desc_p + [j]. + subj_id)) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "nettemp_nt_item %u has invalid group %u in ACL -> removing entry!\n", + nettemp_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (nettemp_nt_handle, + &nettemp_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "nettemp_nt_item %u has invalid group %u in ACL!\n", + nettemp_desc_p[i], + sub_desc_p[j].subj_id); + } +#if defined(CONFIG_RSBAC_RC) + else if ((sub_desc_p[j]. + subj_type == ACLS_ROLE) + && (sub_desc_p[j]. + subj_id > + RC_role_max_value) + ) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "nettemp_nt_item %u has invalid role %u in ACL -> removing entry!\n", + nettemp_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (nettemp_nt_handle, + &nettemp_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "nettemp_nt_item %u has invalid role %u in ACL!\n", + nettemp_desc_p[i], + sub_desc_p[j].subj_id); + } +#endif + } + rsbac_kfree(sub_desc_p); + } + } + rsbac_kfree(nettemp_desc_p); + f_sum += desc_count; + } + rsbac_printk(KERN_INFO "rsbac_check_acl(): %li network template NT items\n", + desc_count); + + /* nettemp list */ + tmp_count = 0; + desc_count = + rsbac_list_lol_get_all_desc(nettemp_handle, + (void **) &nettemp_desc_p); + if (desc_count > 0) { + for (i = 0; i < desc_count; i++) { + /* check for group existence of all ACL entries for groups */ + sub_desc_count = + rsbac_list_lol_get_all_subdesc(nettemp_handle, + &nettemp_desc_p + [i], + (void **) + &sub_desc_p); + if (sub_desc_count > 0) { + for (j = 0; j < sub_desc_count; j++) { + if ((sub_desc_p[j].subj_type == + ACLS_GROUP) + && sub_desc_p[j].subj_id + && + !rsbac_list_exist(group_handle, + &sub_desc_p + [j]. + subj_id)) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "nettemp_item %u has invalid group %u in ACL -> removing entry!\n", + nettemp_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (nettemp_handle, + &nettemp_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "nettemp_item %u has invalid group %u in ACL!\n", + nettemp_desc_p[i], + sub_desc_p[j].subj_id); + } +#if defined(CONFIG_RSBAC_RC) + else if ((sub_desc_p[j]. + subj_type == ACLS_ROLE) + && (sub_desc_p[j]. + subj_id > + RC_role_max_value) + ) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "nettemp_item %u has invalid role %u in ACL -> removing entry!\n", + nettemp_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (nettemp_handle, + &nettemp_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "nettemp_item %u has invalid role %u in ACL!\n", + nettemp_desc_p[i], + sub_desc_p[j].subj_id); + } +#endif + } + rsbac_kfree(sub_desc_p); + } + } + rsbac_kfree(nettemp_desc_p); + f_sum += desc_count; + } + rsbac_printk(KERN_INFO "rsbac_check_acl(): %li network template items\n", + desc_count); + + /* netobj list */ + tmp_count = 0; + desc_count = + rsbac_list_lol_get_all_desc(netobj_handle, + (void **) &netobj_desc_p); + if (desc_count > 0) { + for (i = 0; i < desc_count; i++) { + /* check for group existence of all ACL entries for groups */ + sub_desc_count = + rsbac_list_lol_get_all_subdesc(netobj_handle, + &netobj_desc_p + [i], + (void **) + &sub_desc_p); + if (sub_desc_count > 0) { + for (j = 0; j < sub_desc_count; j++) { + if ((sub_desc_p[j].subj_type == + ACLS_GROUP) + && sub_desc_p[j].subj_id + && + !rsbac_list_exist(group_handle, + &sub_desc_p + [j]. + subj_id)) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "netobj_item %p has invalid group %u in ACL -> removing entry!\n", + netobj_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (netobj_handle, + &netobj_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "netobj_item %p has invalid group %u in ACL!\n", + netobj_desc_p[i], + sub_desc_p[j].subj_id); + } +#if defined(CONFIG_RSBAC_RC) + else if ((sub_desc_p[j]. + subj_type == ACLS_ROLE) + && (sub_desc_p[j]. + subj_id > + RC_role_max_value) + ) { + if (correct) { + /* remove sub item and complain */ + rsbac_pr_debug(ds, "netobj_item %p has invalid role %u in ACL -> removing entry!\n", + netobj_desc_p[i], + sub_desc_p[j].subj_id); + rsbac_list_lol_subremove + (netobj_handle, + &netobj_desc_p + [i], + &sub_desc_p + [j]); + } else /* complain */ + rsbac_pr_debug(ds, "netobj_item %p has invalid role %u in ACL!\n", + netobj_desc_p[i], + sub_desc_p[j].subj_id); + } +#endif + } + rsbac_kfree(sub_desc_p); + } + } + rsbac_kfree(netobj_desc_p); + f_sum += desc_count; + } + rsbac_printk(KERN_INFO "rsbac_check_acl(): %li network object items\n", + desc_count); +#endif /* NET_OBJ_PROT */ + + rsbac_printk(KERN_INFO "rsbac_check_acl(): Total of %lu registered ACLs\n", + f_sum); + + return 0; +} + +/************************************************* */ +/* Access functions */ +/************************************************* */ + +/* All these procedures handle the spinlocks to protect the targets during */ +/* access. */ + +/* rsbac_acl_set_acl_entry + * Set ACL entry for given target and subject to given rights. If entry does + * not exist, it is created, thus cutting the inheritance from default/parent. + */ + +int rsbac_acl_set_acl_entry(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t rights, + rsbac_time_t ttl) +{ + int err = 0; + struct rsbac_acl_device_list_item_t *device_p; + struct rsbac_acl_entry_desc_t desc; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_acl_set_acl_entry(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (subj_type >= ACLS_NONE) + return -RSBAC_EINVALIDVALUE; +#ifdef CONFIG_RSBAC_DEBUG + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_acl_set_acl_entry(): called from interrupt!\n"); + } +#endif + desc.subj_type = subj_type; + desc.subj_id = subj_id; + + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + inode_nr = tid.file.inode; + rsbac_pr_debug(ds_acl, "Setting file/dir/fifo/symlink ACL for device %02u:%02u, inode %lu\n", + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), tid.file.inode); + /* default entry? */ + if (RSBAC_IS_ZERO_DEV(tid.file.device) && !tid.file.inode + && !tid.file.dentry_p) + return rsbac_ta_list_add_ttl(ta_number, + default_fd_handle, + ttl, &desc, &rights); + srcu_idx = srcu_read_lock(&device_list_srcu); + /* lookup device */ + device_p = acl_lookup_device(tid.file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_acl_set_acl_entry(): Could not lookup device!\n"); + /* free read lock */ + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + if (!rsbac_ta_list_lol_exist + (ta_number, device_p->handle, + &inode_nr)) { + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_FD_MASK; + + err = rsbac_ta_list_lol_add_ttl(ta_number, + device_p->handle, + 0, &inode_nr, + &mask); + if (err) { + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; + } + } + err = + rsbac_ta_list_lol_subadd_ttl(ta_number, + device_p->handle, ttl, + &inode_nr, &desc, + &rights); + srcu_read_unlock(&device_list_srcu, srcu_idx); + /* ready. */ + return err; + + case T_DEV: + rsbac_pr_debug(ds_acl, "Setting device ACL for dev %c %02u:%02u\n", + 'B' + tid.dev.type, tid.dev.major, + tid.dev.minor); + /* default entry? */ + if (RSBAC_IS_ZERO_DEV_DESC(tid.dev)) + return rsbac_ta_list_add_ttl(ta_number, + default_dev_handle, + ttl, &desc, &rights); + + { + switch (tid.dev.type) { + case D_char: + case D_block: + if (!rsbac_ta_list_lol_exist + (ta_number, dev_handle, &tid.dev)) { + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_DEV_MASK; + + err = + rsbac_ta_list_lol_add_ttl + (ta_number, dev_handle, 0, + &tid.dev, &mask); + if (err) + return err; + } + return + rsbac_ta_list_lol_subadd_ttl(ta_number, + dev_handle, + ttl, + &tid.dev, + &desc, + &rights); + + case D_char_major: + case D_block_major: + tid.dev.type -= (D_block_major - D_block); + if (!rsbac_ta_list_lol_exist + (ta_number, dev_major_handle, + &tid.dev)) { + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_DEV_MASK; + + err = + rsbac_ta_list_lol_add_ttl + (ta_number, dev_major_handle, + 0, &tid.dev, &mask); + if (err) + return err; + } + return + rsbac_ta_list_lol_subadd_ttl(ta_number, + dev_major_handle, + ttl, + &tid.dev, + &desc, + &rights); + + default: + return -RSBAC_EINVALIDTARGET; + } + } + + case T_IPC: + /* default entry? */ + if (tid.ipc.type == I_none) + return rsbac_ta_list_add_ttl(ta_number, + default_ipc_handle, + ttl, &desc, &rights); + else + return -RSBAC_EINVALIDTARGET; + + case T_SCD: + /* default entry? */ + if (tid.scd == AST_none) + return rsbac_ta_list_add_ttl(ta_number, + default_scd_handle, + ttl, &desc, &rights); + + if (!rsbac_ta_list_lol_exist + (ta_number, scd_handle, &tid.scd)) { + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_SCD_MASK; + + err = rsbac_ta_list_lol_add_ttl(ta_number, + scd_handle, + 0, + &tid.scd, &mask); + if (err) + return err; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, scd_handle, + ttl, &tid.scd, &desc, + &rights); + + case T_USER: + /* default entry? */ + if (tid.user == RSBAC_NO_USER) + return rsbac_ta_list_add_ttl(ta_number, + default_u_handle, ttl, + &desc, &rights); + if (!rsbac_ta_list_lol_exist + (ta_number, u_handle, &tid.user)) { + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_U_MASK; + + err = rsbac_ta_list_lol_add_ttl(ta_number, + u_handle, + 0, + &tid.user, &mask); + if (err) + return err; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, u_handle, + ttl, &tid.user, &desc, + &rights); + + + case T_PROCESS: + /* default entry? */ + if (!tid.process) + return rsbac_ta_list_add_ttl(ta_number, + default_p_handle, ttl, + &desc, &rights); + else + return -RSBAC_EINVALIDTARGET; + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + case T_GROUP: + /* default entry? */ + if (tid.group == RSBAC_NO_GROUP) + return rsbac_ta_list_add_ttl(ta_number, + default_g_handle, ttl, + &desc, &rights); + if (!rsbac_ta_list_lol_exist + (ta_number, g_handle, &tid.group)) { + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_G_MASK; + + err = rsbac_ta_list_lol_add_ttl(ta_number, + g_handle, + 0, + &tid.group, &mask); + if (err) + return err; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, g_handle, + ttl, &tid.group, &desc, + &rights); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + case T_NETDEV: + rsbac_pr_debug(ds_acl, "Setting network device ACL for netdev %s\n", + tid.netdev); + /* default entry? */ + if (!tid.netdev[0]) + return rsbac_ta_list_add_ttl(ta_number, + default_netdev_handle, + ttl, &desc, &rights); + + if (!rsbac_ta_list_lol_exist + (ta_number, netdev_handle, &tid.netdev)) { + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_NETDEV_MASK; + + err = rsbac_ta_list_lol_add_ttl(ta_number, + netdev_handle, + 0, + &tid.netdev, + &mask); + if (err) + return err; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + netdev_handle, ttl, + &tid.netdev, &desc, + &rights); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + case T_NETTEMP_NT: + rsbac_pr_debug(ds_acl, "Setting network template NT ACL for " + "nettemp_nt %u\n", tid.nettemp); + /* default entry? */ + if (!tid.nettemp) + return rsbac_ta_list_add_ttl(ta_number, + default_nettemp_nt_handle, + ttl, &desc, &rights); + + if (!rsbac_ta_list_lol_exist + (ta_number, nettemp_nt_handle, &tid.nettemp)) { + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_NETTEMP_MASK; + + err = rsbac_ta_list_lol_add_ttl(ta_number, + nettemp_nt_handle, + 0, + &tid.nettemp, + &mask); + if (err) + return err; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + nettemp_nt_handle, ttl, + &tid.nettemp, &desc, + &rights); + + case T_NETTEMP: + rsbac_pr_debug(ds_acl, "Setting network template ACL for nettemp %u\n", + tid.nettemp); + /* default entry? */ + if (!tid.nettemp) + return -RSBAC_EINVALIDTARGET; + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + + if (!rsbac_ta_list_lol_exist + (ta_number, nettemp_handle, &tid.nettemp)) { + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_NETOBJ_MASK; + + err = rsbac_ta_list_lol_add_ttl(ta_number, + nettemp_handle, + 0, + &tid.nettemp, + &mask); + if (err) + return err; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + nettemp_handle, ttl, + &tid.nettemp, &desc, + &rights); + + case T_NETOBJ: + rsbac_pr_debug(ds_acl, "Setting network object ACL for netobj %p\n", + tid.netobj.sock_p); + /* default entry? */ + if (!tid.netobj.sock_p) + return rsbac_ta_list_add_ttl(ta_number, + default_netobj_handle, + ttl, &desc, &rights); + + if (!rsbac_ta_list_lol_exist + (ta_number, netobj_handle, &tid.netobj.sock_p)) { + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_NETOBJ_MASK; + + err = rsbac_ta_list_lol_add_ttl(ta_number, + netobj_handle, + 0, + &tid.netobj.sock_p, + &mask); + if (err) + return err; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + netobj_handle, ttl, + &tid.netobj.sock_p, + &desc, &rights); +#endif /* NET_OBJ_PROT */ + + + default: + err = -RSBAC_EINVALIDTARGET; + } + return err; +} + +/* rsbac_acl_remove_acl_entry + * Remove ACL entry for given target and subject. This reactivates the + * inheritance from default/parent. + */ + +int rsbac_acl_remove_acl_entry(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id) +{ + int err = 0; + struct rsbac_acl_device_list_item_t *device_p; + struct rsbac_acl_entry_desc_t desc; +#ifdef CONFIG_RSBAC_DEBUG + char tmp[RSBAC_MAXNAMELEN]; +#endif + rsbac_acl_rights_vector_t mask; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_acl_remove_acl_entry(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (subj_type >= ACLS_NONE) + return -RSBAC_EINVALIDVALUE; +#ifdef CONFIG_RSBAC_DEBUG + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_acl_remove_acl_entry(): called from interrupt!\n"); + } +#endif + desc.subj_type = subj_type; + desc.subj_id = subj_id; + + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + inode_nr = tid.file.inode; + rsbac_pr_debug(ds_acl, "Removing file/dir/fifo/symlink ACL entry %s %u for device %02u:%02u, inode %lu\n", + get_acl_subject_type_name(tmp, desc.subj_type), + desc.subj_id, + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), tid.file.inode); + /* default entry? */ + if (RSBAC_IS_ZERO_DEV(tid.file.device) && !tid.file.inode + && !tid.file.dentry_p) + return rsbac_ta_list_remove(ta_number, + default_fd_handle, + &desc); + + srcu_idx = srcu_read_lock(&device_list_srcu); + /* lookup device */ + device_p = acl_lookup_device(tid.file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_acl_remove_acl_entry(): Could not lookup device!\n"); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + err = rsbac_ta_list_lol_subremove(ta_number, + device_p->handle, + &inode_nr, &desc); + /* if ACL is empty, remove it */ + if (!err + && !rsbac_ta_list_lol_subcount(ta_number, + device_p->handle, + &inode_nr) + && !rsbac_ta_list_lol_get_data_ttl(ta_number, + device_p->handle, + NULL, + &inode_nr, + &mask) + && (mask == RSBAC_ACL_DEFAULT_FD_MASK) + ) { + err = rsbac_ta_list_lol_remove(ta_number, + device_p->handle, + &inode_nr); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; + + case T_DEV: + rsbac_pr_debug(ds_acl, "Removing device ACL entry for dev %c %02u:%02u\n", + 'B' + tid.dev.type, tid.dev.major, + tid.dev.minor); + /* default entry? */ + if (RSBAC_IS_ZERO_DEV_DESC(tid.dev)) + return rsbac_ta_list_remove(ta_number, + default_dev_handle, + &desc); + + { + switch (tid.dev.type) { + case D_char: + case D_block: + err = + rsbac_ta_list_lol_subremove(ta_number, + dev_handle, + &tid.dev, + &desc); + /* if ACL is empty, remove it */ + if (!err + && + !rsbac_ta_list_lol_subcount(ta_number, + dev_handle, + &tid.dev) + && + !rsbac_ta_list_lol_get_data_ttl + (ta_number, dev_handle, NULL, &tid.dev, + &mask) + && (mask == RSBAC_ACL_DEFAULT_DEV_MASK) + ) { + err = + rsbac_ta_list_lol_remove + (ta_number, dev_handle, + &tid.dev); + } + return err; + + case D_char_major: + case D_block_major: + tid.dev.type -= (D_block_major - D_block); + err = + rsbac_ta_list_lol_subremove(ta_number, + dev_major_handle, + &tid.dev, + &desc); + /* if ACL is empty, remove it */ + if (!err + && + !rsbac_ta_list_lol_subcount(ta_number, + dev_major_handle, + &tid.dev) + && + !rsbac_ta_list_lol_get_data_ttl + (ta_number, dev_major_handle, NULL, + &tid.dev, &mask) + && (mask == RSBAC_ACL_DEFAULT_DEV_MASK) + ) { + err = + rsbac_ta_list_lol_remove + (ta_number, dev_major_handle, + &tid.dev); + } + return err; + + default: + return -RSBAC_EINVALIDTARGET; + } + } + + case T_IPC: + rsbac_pr_debug(ds_acl, "Removing IPC ACL for type %u\n", tid.ipc.type); + /* default entry? */ + if (tid.ipc.type == I_none) + return rsbac_ta_list_remove(ta_number, + default_ipc_handle, + &desc); + else + return -RSBAC_EINVALIDTARGET; + + case T_SCD: + rsbac_pr_debug(ds_acl, "Removing SCD ACL entry for %s\n", + get_acl_scd_type_name(tmp, tid.scd)); + /* default entry? */ + if (tid.scd == AST_none) + return rsbac_ta_list_remove(ta_number, + default_scd_handle, + &desc); + err = + rsbac_ta_list_lol_subremove(ta_number, scd_handle, + &tid.scd, &desc); + /* if ACL is empty, remove it */ + if (!err + && !rsbac_ta_list_lol_subcount(ta_number, scd_handle, + &tid.scd) + && !rsbac_ta_list_lol_get_data_ttl(ta_number, + scd_handle, NULL, + &tid.scd, &mask) + && (mask == RSBAC_ACL_DEFAULT_SCD_MASK) + ) { + err = + rsbac_ta_list_lol_remove(ta_number, scd_handle, + &tid.scd); + } + return err; + + case T_USER: + rsbac_pr_debug(ds_acl, "Removing user ACL for user %u\n", + tid.user); + /* default entry? */ + if (tid.user == RSBAC_NO_USER) + return rsbac_ta_list_remove(ta_number, + default_u_handle, + &desc); + err = + rsbac_ta_list_lol_subremove(ta_number, u_handle, + &tid.user, &desc); + /* if ACL is empty, remove it */ + if (!err + && !rsbac_ta_list_lol_subcount(ta_number, u_handle, + &tid.user) + && !rsbac_ta_list_lol_get_data_ttl(ta_number, u_handle, + NULL, &tid.user, + &mask) + && (mask == RSBAC_ACL_DEFAULT_U_MASK) + ) { + err = + rsbac_ta_list_lol_remove(ta_number, u_handle, + &tid.user); + } + return err; + + case T_PROCESS: + rsbac_pr_debug(ds_acl, "Removing process ACL for pid %u\n", + tid.process); + /* default entry? */ + if (!tid.process) + return rsbac_ta_list_remove(ta_number, + default_p_handle, + &desc); + else + return -RSBAC_EINVALIDTARGET; + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + case T_GROUP: + rsbac_pr_debug(ds_acl, "Removing Linux group ACL for group %u\n", + tid.group); + /* default entry? */ + if (tid.group == RSBAC_NO_GROUP) + return rsbac_ta_list_remove(ta_number, + default_g_handle, + &desc); + err = + rsbac_ta_list_lol_subremove(ta_number, g_handle, + &tid.group, &desc); + /* if ACL is empty, remove it */ + if (!err + && !rsbac_ta_list_lol_subcount(ta_number, g_handle, + &tid.group) + && !rsbac_ta_list_lol_get_data_ttl(ta_number, g_handle, + NULL, &tid.group, + &mask) + && (mask == RSBAC_ACL_DEFAULT_G_MASK) + ) { + err = + rsbac_ta_list_lol_remove(ta_number, g_handle, + &tid.group); + } + return err; +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + case T_NETDEV: + rsbac_pr_debug(ds_acl, "Removing network device ACL entry for netdev %s\n", + tid.netdev); + /* default entry? */ + if (!tid.netdev[0]) + return rsbac_ta_list_remove(ta_number, + default_netdev_handle, + &desc); + + err = + rsbac_ta_list_lol_subremove(ta_number, netdev_handle, + &tid.netdev, &desc); + /* if ACL is empty, remove it */ + if (!err + && !rsbac_ta_list_lol_subcount(ta_number, + netdev_handle, + &tid.netdev) + && !rsbac_ta_list_lol_get_data_ttl(ta_number, + netdev_handle, NULL, + &tid.netdev, &mask) + && (mask == RSBAC_ACL_DEFAULT_NETDEV_MASK) + ) { + err = + rsbac_ta_list_lol_remove(ta_number, + netdev_handle, + &tid.netdev); + } + return err; +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + case T_NETTEMP_NT: + rsbac_pr_debug(ds_acl, "Removing network template NT ACL entry for " + "nettemp_nt %u\n", tid.nettemp); + /* default entry? */ + if (!tid.nettemp) + return rsbac_ta_list_remove(ta_number, + default_nettemp_nt_handle, + &desc); + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + + err = + rsbac_ta_list_lol_subremove(ta_number, + nettemp_nt_handle, + &tid.nettemp, &desc); + /* if ACL is empty, remove it */ + if (!err + && !rsbac_ta_list_lol_subcount(ta_number, + nettemp_nt_handle, + &tid.nettemp) + && !rsbac_ta_list_lol_get_data_ttl(ta_number, + nettemp_nt_handle, + NULL, &tid.nettemp, + &mask) + && (mask == RSBAC_ACL_DEFAULT_NETTEMP_MASK) + ) { + err = + rsbac_ta_list_lol_remove(ta_number, + nettemp_nt_handle, + &tid.nettemp); + } + return err; + + case T_NETTEMP: + rsbac_pr_debug(ds_acl, "Removing network template ACL entry for nettemp_nt %u\n", + tid.nettemp); + /* default entry? */ + if (!tid.nettemp) + return -RSBAC_EINVALIDTARGET; + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + + err = + rsbac_ta_list_lol_subremove(ta_number, nettemp_handle, + &tid.nettemp, &desc); + /* if ACL is empty, remove it */ + if (!err + && !rsbac_ta_list_lol_subcount(ta_number, + nettemp_handle, + &tid.nettemp) + && !rsbac_ta_list_lol_get_data_ttl(ta_number, + nettemp_handle, + NULL, &tid.nettemp, + &mask) + && (mask == RSBAC_ACL_DEFAULT_NETOBJ_MASK) + ) { + err = + rsbac_ta_list_lol_remove(ta_number, + nettemp_handle, + &tid.nettemp); + } + return err; + + case T_NETOBJ: + rsbac_pr_debug(ds_acl, "Removing network object ACL entry for netobj %p\n", + tid.netobj.sock_p); + /* default entry? */ + if (!tid.netobj.sock_p) + return rsbac_ta_list_remove(ta_number, + default_netobj_handle, + &desc); + + err = + rsbac_ta_list_lol_subremove(ta_number, netobj_handle, + &tid.netobj.sock_p, &desc); + /* if ACL is empty, remove it */ + if (!err + && !rsbac_ta_list_lol_subcount(ta_number, + netobj_handle, + &tid.netobj.sock_p) + && !rsbac_ta_list_lol_get_data_ttl(ta_number, + netobj_handle, NULL, + &tid.netobj, &mask) + && (mask == RSBAC_ACL_DEFAULT_NETOBJ_MASK) + ) { + err = + rsbac_ta_list_lol_remove(ta_number, + netobj_handle, + &tid.netobj.sock_p); + } + return err; +#endif /* NET_OBJ_PROT */ + + default: + return -RSBAC_EINVALIDTARGET; + } +} + +/* rsbac_acl_remove_acl + * Remove ACL for given target. For cleanup on delete. + */ + +int rsbac_acl_remove_acl(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid) +{ + int err = 0; +#ifdef CONFIG_RSBAC_DEBUG + char tmp[RSBAC_MAXNAMELEN]; +#endif + struct rsbac_acl_device_list_item_t *device_p; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_acl_remove_acl(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } +#ifdef CONFIG_RSBAC_DEBUG + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_acl_remove_acl(): called from interrupt!\n"); + } +#endif + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + inode_nr = tid.file.inode; + rsbac_pr_debug(ds_acl, "Removing file/dir/fifo/symlink ACL for device %02u:%02u, inode %lu\n", + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), tid.file.inode); + /* default entry? */ + if (RSBAC_IS_ZERO_DEV(tid.file.device) && !tid.file.inode + && !tid.file.dentry_p) + return -RSBAC_EINVALIDTARGET; + + srcu_idx = srcu_read_lock(&device_list_srcu); + /* lookup device */ + device_p = acl_lookup_device(tid.file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_acl_remove_acl(): Could not lookup device!\n"); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + err = rsbac_ta_list_lol_remove(ta_number, + device_p->handle, + &inode_nr); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; + + case T_DEV: + rsbac_pr_debug(ds_acl, "Removing device ACL for dev %c %02u:%02u\n", + 'B' + tid.dev.type, tid.dev.major, + tid.dev.minor); + /* default entry? */ + if (RSBAC_IS_ZERO_DEV_DESC(tid.dev)) + return -RSBAC_EINVALIDTARGET; + switch (tid.dev.type) { + case D_char: + case D_block: + return rsbac_ta_list_lol_remove(ta_number, + dev_handle, + &tid.dev); + + case D_char_major: + case D_block_major: + tid.dev.type -= (D_block_major - D_block); + return rsbac_ta_list_lol_remove(ta_number, + dev_major_handle, + &tid.dev); + + default: + return -RSBAC_EINVALIDTARGET; + } + + case T_SCD: + rsbac_pr_debug(ds_acl, "Removing SCD ACL for %s\n", + get_acl_scd_type_name(tmp, tid.scd)); + /* default entry? */ + if (tid.scd == AST_none) + return -RSBAC_EINVALIDTARGET; + else + return rsbac_ta_list_lol_remove(ta_number, + scd_handle, + &tid.scd); + + case T_USER: + rsbac_pr_debug(ds_acl, "Removing user ACL for user %u\n", + tid.user); + /* default entry? */ + if (tid.user == RSBAC_NO_USER) + return -RSBAC_EINVALIDTARGET; + else + return rsbac_ta_list_lol_remove(ta_number, + u_handle, + &tid.user); + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + case T_GROUP: + rsbac_pr_debug(ds_acl, "Removing Linux group ACL for group %u\n", + tid.group); + /* default entry? */ + if (tid.group == RSBAC_NO_GROUP) + return -RSBAC_EINVALIDTARGET; + else + return rsbac_ta_list_lol_remove(ta_number, + g_handle, + &tid.group); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + case T_NETDEV: + rsbac_pr_debug(ds_acl, "Removing network device ACL for netdev %s\n", + tid.netdev); + /* default entry? */ + if (!tid.netdev[0]) + return -RSBAC_EINVALIDTARGET; + else + return rsbac_ta_list_lol_remove(ta_number, + netdev_handle, + &tid.netdev); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + case T_NETTEMP_NT: + rsbac_pr_debug(ds_acl, "Removing network template NT ACL for nettemp_nt %u\n", + tid.nettemp); + /* default entry? */ + if (!tid.nettemp) + return -RSBAC_EINVALIDTARGET; + else + return rsbac_ta_list_lol_remove(ta_number, + nettemp_nt_handle, + &tid.nettemp); + case T_NETTEMP: + rsbac_pr_debug(ds_acl, "Removing network template ACL for nettemp %u\n", + tid.nettemp); + /* default entry? */ + if (!tid.nettemp) + return -RSBAC_EINVALIDTARGET; + else + return rsbac_ta_list_lol_remove(ta_number, + nettemp_handle, + &tid.nettemp); + case T_NETOBJ: + rsbac_pr_debug(ds_acl, "Removing network object ACL for netobj %p\n", + tid.netobj.sock_p); + /* default entry? */ + if (!tid.netobj.sock_p) + return -RSBAC_EINVALIDTARGET; + else + return rsbac_ta_list_lol_remove(ta_number, + netobj_handle, + &tid.netobj. + sock_p); +#endif + + default: + err = -RSBAC_EINVALIDTARGET; + } + return err; +} + +/* rsbac_acl_add_to_acl_entry + * Add given rights to ACL entry for given target and subject. If entry does + * not exist, behaviour is exactly like rsbac_acl_set_acl_entry. + */ + +int rsbac_acl_add_to_acl_entry(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t rights, + rsbac_time_t ttl) +{ + int err = 0; + struct rsbac_acl_device_list_item_t *device_p; + rsbac_acl_rights_vector_t old_rights; + struct rsbac_acl_entry_desc_t desc; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_acl_add_to_acl_entry(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (subj_type >= ACLS_NONE) + return -RSBAC_EINVALIDVALUE; +#ifdef CONFIG_RSBAC_DEBUG + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_acl_add_to_acl_entry(): called from interrupt!\n"); + } +#endif + desc.subj_type = subj_type; + desc.subj_id = subj_id; + + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + inode_nr = tid.file.inode; + /* default entry? */ + if (RSBAC_IS_ZERO_DEV(tid.file.device) && !tid.file.inode + && !tid.file.dentry_p) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_fd_handle, NULL, &desc, + &old_rights)) + rights |= old_rights; + return rsbac_ta_list_add_ttl(ta_number, + default_fd_handle, + ttl, &desc, &rights); + } + srcu_idx = srcu_read_lock(&device_list_srcu); + /* lookup device */ + device_p = acl_lookup_device(tid.file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_acl_set_acl_entry(): Could not lookup device!\n"); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + /* protect this list */ + if (!rsbac_ta_list_lol_exist(ta_number, device_p->handle, &inode_nr)) { /* new acl */ + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_FD_MASK; + + err = + rsbac_ta_list_lol_add_ttl(ta_number, + device_p->handle, 0, + &inode_nr, + &mask); + if (err) { + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; + } + } else { /* old entry? */ + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + device_p->handle, + NULL, + &inode_nr, + &desc, + &old_rights)) + rights |= old_rights; + } + err = rsbac_ta_list_lol_subadd_ttl(ta_number, + device_p->handle, ttl, + &inode_nr, &desc, + &rights); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; + + case T_DEV: + /* default entry? */ + if (RSBAC_IS_ZERO_DEV_DESC(tid.dev)) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_dev_handle, NULL, &desc, + &old_rights)) + rights |= old_rights; + return rsbac_ta_list_add_ttl(ta_number, + default_dev_handle, + ttl, &desc, &rights); + } + switch (tid.dev.type) { + case D_char: + case D_block: + if (!rsbac_ta_list_lol_exist(ta_number, dev_handle, &tid.dev)) { /* new acl */ + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_DEV_MASK; + + err = + rsbac_ta_list_lol_add_ttl(ta_number, + dev_handle, + 0, &tid.dev, + &mask); + if (err) + return err; + } else { /* old entry? */ + if (!rsbac_ta_list_lol_get_subdata_ttl + (ta_number, dev_handle, NULL, &tid.dev, + &desc, &old_rights)) + rights |= old_rights; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + dev_handle, + ttl, &tid.dev, + &desc, + &rights); + + case D_char_major: + case D_block_major: + tid.dev.type -= (D_block_major - D_block); + if (!rsbac_ta_list_lol_exist(ta_number, dev_major_handle, &tid.dev)) { /* new acl */ + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_DEV_MASK; + + err = + rsbac_ta_list_lol_add_ttl(ta_number, + dev_major_handle, + 0, &tid.dev, + &mask); + if (err) + return err; + } else { /* old entry? */ + if (!rsbac_ta_list_lol_get_subdata_ttl + (ta_number, dev_major_handle, NULL, + &tid.dev, &desc, &old_rights)) + rights |= old_rights; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + dev_major_handle, + ttl, &tid.dev, + &desc, + &rights); + + default: + return -RSBAC_EINVALIDTARGET; + } + + case T_IPC: + /* default entry? */ + if (tid.ipc.type == I_none) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_ipc_handle, NULL, &desc, + &old_rights)) + rights |= old_rights; + return rsbac_ta_list_add_ttl(ta_number, + default_ipc_handle, + ttl, &desc, &rights); + } else + return -RSBAC_EINVALIDTARGET; + + case T_SCD: + /* default entry? */ + if (tid.scd == AST_none) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_scd_handle, NULL, &desc, + &old_rights)) + rights |= old_rights; + return rsbac_ta_list_add_ttl(ta_number, + default_scd_handle, + ttl, &desc, &rights); + } + if (!rsbac_ta_list_lol_exist(ta_number, scd_handle, &tid.scd)) { /* new acl */ + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_SCD_MASK; + + err = + rsbac_ta_list_lol_add_ttl(ta_number, + scd_handle, 0, + &tid.scd, &mask); + if (err) + return err; + } else { /* old entry? */ + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + scd_handle, + NULL, + &tid.scd, + &desc, + &old_rights)) + rights |= old_rights; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + scd_handle, + ttl, + &tid.scd, + &desc, &rights); + + case T_USER: + /* default entry? */ + if (tid.user == RSBAC_NO_USER) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_u_handle, NULL, &desc, + &old_rights)) + rights |= old_rights; + return rsbac_ta_list_add_ttl(ta_number, + default_u_handle, ttl, + &desc, &rights); + } + if (!rsbac_ta_list_lol_exist(ta_number, u_handle, &tid.user)) { /* new acl */ + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_U_MASK; + + err = + rsbac_ta_list_lol_add_ttl(ta_number, u_handle, + 0, &tid.user, &mask); + if (err) + return err; + } else { /* old subentry? */ + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + u_handle, + NULL, + &tid.user, + &desc, + &old_rights)) + rights |= old_rights; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + u_handle, + ttl, + &tid.user, + &desc, &rights); + + case T_PROCESS: + /* default entry? */ + if (!tid.process) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_p_handle, NULL, &desc, + &old_rights)) + rights |= old_rights; + return rsbac_ta_list_add_ttl(ta_number, + default_p_handle, ttl, + &desc, &rights); + } else + return -RSBAC_EINVALIDTARGET; + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + case T_GROUP: + /* default entry? */ + if (tid.group == RSBAC_NO_GROUP) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_g_handle, NULL, &desc, + &old_rights)) + rights |= old_rights; + return rsbac_ta_list_add_ttl(ta_number, + default_g_handle, ttl, + &desc, &rights); + } + if (!rsbac_ta_list_lol_exist(ta_number, g_handle, &tid.group)) { /* new acl */ + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_G_MASK; + + err = + rsbac_ta_list_lol_add_ttl(ta_number, g_handle, + 0, &tid.group, + &mask); + if (err) + return err; + } else { /* old subentry? */ + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + g_handle, + NULL, + &tid.group, + &desc, + &old_rights)) + rights |= old_rights; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + g_handle, + ttl, + &tid.group, + &desc, &rights); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + case T_NETDEV: + /* default entry? */ + if (!tid.netdev[0]) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_netdev_handle, NULL, &desc, + &old_rights)) + rights |= old_rights; + return rsbac_ta_list_add_ttl(ta_number, + default_netdev_handle, + ttl, &desc, &rights); + } + if (!rsbac_ta_list_lol_exist(ta_number, netdev_handle, &tid.netdev)) { /* new acl */ + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_NETDEV_MASK; + + err = + rsbac_ta_list_lol_add_ttl(ta_number, + netdev_handle, 0, + &tid.netdev, &mask); + if (err) + return err; + } else { /* old entry? */ + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + netdev_handle, + NULL, + &tid.netdev, + &desc, + &old_rights)) + rights |= old_rights; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + netdev_handle, + ttl, + &tid.netdev, + &desc, &rights); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + case T_NETTEMP_NT: + /* default entry? */ + if (!tid.nettemp) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_nettemp_nt_handle, NULL, + &desc, &old_rights)) + rights |= old_rights; + return rsbac_ta_list_add_ttl(ta_number, + default_nettemp_nt_handle, + ttl, &desc, &rights); + } + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + if (!rsbac_ta_list_lol_exist(ta_number, nettemp_nt_handle, &tid.nettemp)) { /* new acl */ + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_NETTEMP_MASK; + + err = + rsbac_ta_list_lol_add_ttl(ta_number, + nettemp_nt_handle, 0, + &tid.nettemp, &mask); + if (err) + return err; + } else { /* old entry? */ + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + nettemp_nt_handle, + NULL, + &tid. + nettemp, + &desc, + &old_rights)) + rights |= old_rights; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + nettemp_nt_handle, + ttl, + &tid.nettemp, + &desc, &rights); + case T_NETTEMP: + /* default entry? */ + if (!tid.nettemp) { + return -RSBAC_EINVALIDTARGET; + } + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + if (!rsbac_ta_list_lol_exist(ta_number, nettemp_handle, &tid.nettemp)) { /* new acl */ + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_NETOBJ_MASK; + + err = + rsbac_ta_list_lol_add_ttl(ta_number, + nettemp_handle, 0, + &tid.nettemp, &mask); + if (err) + return err; + } else { /* old entry? */ + if (!rsbac_ta_list_lol_get_subdata_ttl + (ta_number, nettemp_handle, NULL, &tid.nettemp, + &desc, &old_rights)) + rights |= old_rights; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + nettemp_handle, ttl, + &tid.nettemp, &desc, + &rights); + case T_NETOBJ: + /* default entry? */ + if (!tid.netobj.sock_p) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_netobj_handle, NULL, &desc, + &old_rights)) + rights |= old_rights; + return rsbac_ta_list_add_ttl(ta_number, + default_netobj_handle, + ttl, &desc, &rights); + } + if (!rsbac_ta_list_lol_exist(ta_number, netobj_handle, &tid.netobj.sock_p)) { /* new acl */ + rsbac_acl_rights_vector_t mask = + RSBAC_ACL_DEFAULT_NETOBJ_MASK; + + err = + rsbac_ta_list_lol_add_ttl(ta_number, + netobj_handle, 0, + &tid.netobj.sock_p, + &mask); + if (err) + return err; + } else { /* old entry? */ + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + netobj_handle, + NULL, + &tid.netobj. + sock_p, + &desc, + &old_rights)) + rights |= old_rights; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, + netobj_handle, + ttl, + &tid.netobj.sock_p, + &desc, &rights); +#endif /* NET_OBJ_PROT */ + + default: + return -RSBAC_EINVALIDTARGET; + } +} + +/* rsbac_acl_remove_from_acl_entry + * Remove given rights from ACL entry for given target and subject. If entry does + * not exist, nothing happens. + * This function does NOT remove the ACL entry, so removing all rights results in + * NO rights for this subject/target combination! + */ + +int rsbac_acl_remove_from_acl_entry(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t + subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t rights) +{ + int err = 0; + struct rsbac_acl_device_list_item_t *device_p; + rsbac_acl_rights_vector_t old_rights; + struct rsbac_acl_entry_desc_t desc; + rsbac_time_t ttl; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_acl_remove_from_acl_entry(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (subj_type >= ACLS_NONE) + return -RSBAC_EINVALIDVALUE; +#ifdef CONFIG_RSBAC_DEBUG + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_acl_remove_from_acl_entry(): called from interrupt!\n"); + } +#endif + desc.subj_type = subj_type; + desc.subj_id = subj_id; + + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + inode_nr = tid.file.inode; + /* default entry? */ + if (RSBAC_IS_ZERO_DEV(tid.file.device) && !tid.file.inode + && !tid.file.dentry_p) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_fd_handle, &ttl, &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_add_ttl(ta_number, + default_fd_handle, + ttl, &desc, + &old_rights); + } else + return 0; + } + srcu_idx = srcu_read_lock(&device_list_srcu); + /* lookup device */ + device_p = acl_lookup_device(tid.file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_acl_remove_from_acl_entry(): Could not lookup device!\n"); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + device_p->handle, + &ttl, + &inode_nr, + &desc, + &old_rights)) { + old_rights &= ~rights; + err = rsbac_ta_list_lol_subadd_ttl(ta_number, + device_p->handle, + ttl, + &inode_nr, + &desc, + &old_rights); + } else + err = 0; + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; + + case T_DEV: + /* default entry? */ + if (RSBAC_IS_ZERO_DEV_DESC(tid.dev)) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_dev_handle, &ttl, &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_add_ttl(ta_number, + default_dev_handle, + ttl, &desc, + &old_rights); + } else + return 0; + } + switch (tid.dev.type) { + case D_char: + case D_block: + if (!rsbac_ta_list_lol_get_subdata_ttl + (ta_number, dev_handle, &ttl, &tid.dev, &desc, + &old_rights)) { + old_rights &= ~rights; + return + rsbac_ta_list_lol_subadd_ttl(ta_number, + dev_handle, + ttl, + &tid.dev, + &desc, + &old_rights); + } else + return 0; + + case D_char_major: + case D_block_major: + tid.dev.type -= (D_block_major - D_block); + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + dev_major_handle, + &ttl, + &tid.dev, + &desc, + &old_rights)) + { + old_rights &= ~rights; + return + rsbac_ta_list_lol_subadd_ttl(ta_number, + dev_major_handle, + ttl, + &tid.dev, + &desc, + &old_rights); + } else + return 0; + + default: + return -RSBAC_EINVALIDTARGET; + } + + case T_IPC: + /* default entry? */ + if (tid.ipc.type == I_none) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_ipc_handle, &ttl, &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_add_ttl(ta_number, + default_ipc_handle, + ttl, &desc, + &old_rights); + } else + return 0; + } else + return -RSBAC_EINVALIDTARGET; + + case T_SCD: + /* default entry? */ + if (tid.scd == AST_none) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_scd_handle, &ttl, &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_add_ttl(ta_number, + default_scd_handle, + ttl, &desc, + &old_rights); + } else + return 0; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + scd_handle, + &ttl, + &tid.scd, + &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + scd_handle, + ttl, + &tid.scd, + &desc, + &old_rights); + } else + return 0; + + case T_USER: + /* default entry? */ + if (tid.user == RSBAC_NO_USER) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_u_handle, &ttl, &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_add_ttl(ta_number, + default_u_handle, + ttl, &desc, + &old_rights); + } else + return 0; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + u_handle, + &ttl, + &tid.user, + &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + u_handle, + ttl, + &tid.user, + &desc, + &old_rights); + } else + return 0; + + case T_PROCESS: + /* default entry? */ + if (!tid.process) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_p_handle, &ttl, &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_add_ttl(ta_number, + default_p_handle, + ttl, &desc, + &old_rights); + } else + return 0; + } else + return -RSBAC_EINVALIDTARGET; + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + case T_GROUP: + /* default entry? */ + if (tid.group == RSBAC_NO_GROUP) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_g_handle, &ttl, &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_add_ttl(ta_number, + default_g_handle, + ttl, &desc, + &old_rights); + } else + return 0; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + g_handle, + &ttl, + &tid.group, + &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + g_handle, + ttl, + &tid.group, + &desc, + &old_rights); + } else + return 0; +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + case T_NETDEV: + /* default entry? */ + if (!tid.netdev[0]) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_netdev_handle, &ttl, &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_add_ttl(ta_number, + default_netdev_handle, + ttl, &desc, + &old_rights); + } else + return 0; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + netdev_handle, + &ttl, + &tid.netdev, + &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + netdev_handle, + ttl, + &tid.netdev, + &desc, + &old_rights); + } else + return 0; +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + case T_NETTEMP_NT: + /* default entry? */ + if (!tid.nettemp) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_nettemp_nt_handle, &ttl, + &desc, &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_add_ttl(ta_number, + default_nettemp_nt_handle, + ttl, &desc, + &old_rights); + } else + return 0; + } + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + nettemp_nt_handle, + &ttl, + &tid.nettemp, + &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + nettemp_nt_handle, + ttl, + &tid.nettemp, + &desc, + &old_rights); + } else + return 0; + case T_NETTEMP: + /* default entry? */ + if (!tid.nettemp) { + return -RSBAC_EINVALIDTARGET; + } + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + nettemp_handle, + &ttl, + &tid.nettemp, + &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + nettemp_handle, + ttl, + &tid.nettemp, + &desc, + &old_rights); + } else + return 0; + case T_NETOBJ: + /* default entry? */ + if (!tid.netobj.sock_p) { + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_netobj_handle, &ttl, &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_add_ttl(ta_number, + default_netobj_handle, + ttl, &desc, + &old_rights); + } else + return 0; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + netobj_handle, + &ttl, + &tid.netobj.sock_p, + &desc, + &old_rights)) { + old_rights &= ~rights; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + netobj_handle, + ttl, + &tid.netobj. + sock_p, &desc, + &old_rights); + } else + return 0; +#endif /* NET_OBJ_PROT */ + + default: + return -RSBAC_EINVALIDTARGET; + } +} + +/* rsbac_acl_set_mask + * Set inheritance mask for given target to given rights. If item does + * not exist, it is created. + */ + +int rsbac_acl_set_mask(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_acl_rights_vector_t mask) +{ + int err = 0; +#ifdef CONFIG_RSBAC_DEBUG + char tmp[80]; +#endif + struct rsbac_acl_device_list_item_t *device_p; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_acl_set_mask(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (target >= T_NONE) + return -RSBAC_EINVALIDTARGET; +#ifdef CONFIG_RSBAC_DEBUG + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_acl_set_mask(): called from interrupt!\n"); + } +#endif + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + inode_nr = tid.file.inode; + /* default entry? */ + if (RSBAC_IS_ZERO_DEV_DESC(tid.dev)) { + return -RSBAC_EINVALIDTARGET; + } + rsbac_pr_debug(ds_acl, "Setting file/dir/fifo/symlink inheritance mask for device %02u:%02u, inode %lu\n", + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), tid.file.inode); + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = acl_lookup_device(tid.file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_acl_set_mask(): Could not lookup device!\n"); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + err = rsbac_ta_list_lol_add_ttl(ta_number, + device_p->handle, + 0, &inode_nr, &mask); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; + + case T_DEV: + /* default entry? */ + if (tid.dev.type == D_none) { + return -RSBAC_EINVALIDTARGET; + } + rsbac_pr_debug(ds_acl, "Setting device inheritance mask for dev %c %02u:%02u\n", + 'B' + tid.dev.type, + tid.dev.major, tid.dev.minor); + switch (tid.dev.type) { + case D_char: + case D_block: + return rsbac_ta_list_lol_add_ttl(ta_number, + dev_handle, 0, + &tid.dev, &mask); + + case D_char_major: + case D_block_major: + tid.dev.type -= (D_block_major - D_block); + return rsbac_ta_list_lol_add_ttl(ta_number, + dev_major_handle, + 0, &tid.dev, + &mask); + + default: + return -RSBAC_EINVALIDTARGET; + } + + case T_SCD: + /* default entry? */ + if (tid.scd == AST_none) { + return -RSBAC_EINVALIDTARGET; + } + rsbac_pr_debug(ds_acl, "Setting SCD inheritance mask for %s\n", + get_acl_scd_type_name(tmp, tid.scd)); + return rsbac_ta_list_lol_add_ttl(ta_number, scd_handle, 0, + &tid.scd, &mask); + + case T_USER: + /* default entry? */ + if (tid.user == RSBAC_NO_USER) { + return -RSBAC_EINVALIDTARGET; + } + rsbac_pr_debug(ds_acl, "Setting user inheritance mask for user %u\n", + tid.user); + return rsbac_ta_list_lol_add_ttl(ta_number, u_handle, 0, + &tid.user, &mask); + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + case T_GROUP: + /* default entry? */ + if (tid.group == RSBAC_NO_GROUP) { + return -RSBAC_EINVALIDTARGET; + } + rsbac_pr_debug(ds_acl, "Setting Linux group inheritance mask for group %u\n", + tid.group); + return rsbac_ta_list_lol_add_ttl(ta_number, g_handle, 0, + &tid.group, &mask); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + case T_NETDEV: + /* default entry? */ + if (!tid.netdev[0]) { + return -RSBAC_EINVALIDTARGET; + } + rsbac_pr_debug(ds_acl, "Setting network device inheritance mask for netdev %s\n", + tid.netdev); + return rsbac_ta_list_lol_add_ttl(ta_number, netdev_handle, + 0, &tid.netdev, &mask); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + case T_NETTEMP_NT: + /* default entry? */ + if (!tid.nettemp) { + return -RSBAC_EINVALIDTARGET; + } + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + rsbac_pr_debug(ds_acl, "Setting network template NT inheritance mask for nettemp %u\n", + tid.nettemp); + return rsbac_ta_list_lol_add_ttl(ta_number, + nettemp_nt_handle, 0, + &tid.nettemp, &mask); + + case T_NETTEMP: + /* default entry? */ + if (!tid.nettemp) { + return -RSBAC_EINVALIDTARGET; + } + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + rsbac_pr_debug(ds_acl, "Setting network template inheritance mask for nettemp %u\n", + tid.nettemp); + return rsbac_ta_list_lol_add_ttl(ta_number, nettemp_handle, + 0, &tid.nettemp, &mask); + + case T_NETOBJ: + /* default entry? */ + if (!tid.netobj.sock_p) { + return -RSBAC_EINVALIDTARGET; + } + rsbac_pr_debug(ds_acl, "Setting network object inheritance mask for netobj %p\n", + tid.netobj.sock_p); + return rsbac_ta_list_lol_add_ttl(ta_number, netobj_handle, + 0, &tid.netobj.sock_p, + &mask); +#endif /* NET_OBJ_PROT */ + + default: + err = -RSBAC_EINVALIDTARGET; + } + return err; +} + +/* rsbac_acl_get_mask + * Get inheritance mask for given target. If item does + * not exist, default mask is returned. + */ + +int rsbac_acl_get_mask(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + rsbac_acl_rights_vector_t * mask_p) +{ + int err = 0; + struct rsbac_acl_device_list_item_t *device_p; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_acl_get_mask(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (target >= T_NONE) + return -RSBAC_EINVALIDTARGET; +#ifdef CONFIG_RSBAC_DEBUG + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_acl_get_mask(): called from interrupt!\n"); + } +#endif + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + inode_nr = tid.file.inode; + /* default entry? */ + if (RSBAC_IS_ZERO_DEV(tid.file.device) && !tid.file.inode + && !tid.file.dentry_p) { + return -RSBAC_EINVALIDTARGET; + } + + srcu_idx = srcu_read_lock(&device_list_srcu); + /* lookup device */ + device_p = acl_lookup_device(tid.file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_acl_get_mask(): Could not lookup device!\n"); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + err = rsbac_ta_list_lol_get_data_ttl(ta_number, + device_p->handle, NULL, + &inode_nr, + mask_p); + srcu_read_unlock(&device_list_srcu, srcu_idx); + if (err == -RSBAC_ENOTFOUND) { + *mask_p = RSBAC_ACL_DEFAULT_FD_MASK; + err = 0; + } + /* ready. */ + return err; + + case T_DEV: + /* default entry? */ + if (tid.dev.type == D_none) { + return -RSBAC_EINVALIDTARGET; + } + + switch (tid.dev.type) { + case D_char: + case D_block: + err = + rsbac_ta_list_lol_get_data_ttl(ta_number, + dev_handle, + NULL, &tid.dev, + mask_p); + break; + + case D_char_major: + case D_block_major: + tid.dev.type -= (D_block_major - D_block); + err = + rsbac_ta_list_lol_get_data_ttl(ta_number, + dev_major_handle, + NULL, &tid.dev, + mask_p); + break; + + default: + return -RSBAC_EINVALIDTARGET; + } + if (err == -RSBAC_ENOTFOUND) { + *mask_p = RSBAC_ACL_DEFAULT_DEV_MASK; + err = 0; + } + /* ready. */ + return err; + + case T_SCD: + /* default entry? */ + if (tid.scd == AST_none) { + return -RSBAC_EINVALIDTARGET; + } + err = + rsbac_ta_list_lol_get_data_ttl(ta_number, scd_handle, + NULL, &tid.scd, mask_p); + if (err == -RSBAC_ENOTFOUND) { + *mask_p = RSBAC_ACL_DEFAULT_SCD_MASK; + err = 0; + } + /* ready. */ + return err; + + case T_USER: + /* default entry? */ + if (tid.user == RSBAC_NO_USER) { + return -RSBAC_EINVALIDTARGET; + } + err = + rsbac_ta_list_lol_get_data_ttl(ta_number, u_handle, + NULL, &tid.user, + mask_p); + if (err == -RSBAC_ENOTFOUND) { + *mask_p = RSBAC_ACL_DEFAULT_U_MASK; + err = 0; + } + /* ready. */ + return err; + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + case T_GROUP: + /* default entry? */ + if (tid.group == RSBAC_NO_GROUP) { + return -RSBAC_EINVALIDTARGET; + } + err = + rsbac_ta_list_lol_get_data_ttl(ta_number, g_handle, + NULL, &tid.group, + mask_p); + if (err == -RSBAC_ENOTFOUND) { + *mask_p = RSBAC_ACL_DEFAULT_G_MASK; + err = 0; + } + /* ready. */ + return err; +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + case T_NETDEV: + /* default entry? */ + if (!tid.netdev[0]) { + return -RSBAC_EINVALIDTARGET; + } + + err = + rsbac_ta_list_lol_get_data_ttl(ta_number, + netdev_handle, NULL, + &tid.netdev, mask_p); + if (err == -RSBAC_ENOTFOUND) { + *mask_p = RSBAC_ACL_DEFAULT_NETDEV_MASK; + err = 0; + } + /* ready. */ + return err; +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + case T_NETTEMP_NT: + /* default entry? */ + if (!tid.nettemp) { + return -RSBAC_EINVALIDTARGET; + } + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + + err = + rsbac_ta_list_lol_get_data_ttl(ta_number, + nettemp_nt_handle, NULL, + &tid.nettemp, mask_p); + if (err == -RSBAC_ENOTFOUND) { + *mask_p = RSBAC_ACL_DEFAULT_NETTEMP_MASK; + err = 0; + } + /* ready. */ + return err; + case T_NETTEMP: + /* default entry? */ + if (!tid.nettemp) { + return -RSBAC_EINVALIDTARGET; + } + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + + err = + rsbac_ta_list_lol_get_data_ttl(ta_number, + nettemp_handle, NULL, + &tid.nettemp, mask_p); + if (err == -RSBAC_ENOTFOUND) { + *mask_p = RSBAC_ACL_DEFAULT_NETOBJ_MASK; + err = 0; + } + /* ready. */ + return err; + case T_NETOBJ: + /* default entry? */ + if (!tid.netobj.sock_p) { + return -RSBAC_EINVALIDTARGET; + } + + err = + rsbac_ta_list_lol_get_data_ttl(ta_number, + netobj_handle, NULL, + &tid.netobj.sock_p, + mask_p); + if (err == -RSBAC_ENOTFOUND) { + *mask_p = RSBAC_ACL_DEFAULT_NETOBJ_MASK; + err = 0; + } + /* ready. */ + return err; +#endif + + default: + err = -RSBAC_EINVALIDTARGET; + } + return err; +} + +/* rsbac_acl_get_rights + * Get rights from ACL entry for given target and subject. + * If entry does not exist and inherit is on, inherited rights are used. + * If there is no parent, the default rights vector for this target type is returned. + * This function does NOT add role or group rights to user rights! + */ + +int rsbac_acl_get_rights(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + rsbac_acl_rights_vector_t * rights_p, + rsbac_boolean_t inherit) +{ + int err = 0; + struct rsbac_acl_device_list_item_t *device_p; + struct rsbac_acl_entry_desc_t desc; + rsbac_acl_rights_vector_t i_rights = 0; + rsbac_acl_rights_vector_t mask = -1; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_acl_get_rights(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (!rights_p) + return -RSBAC_EINVALIDPOINTER; + if (subj_type >= ACLS_NONE) + return -RSBAC_EINVALIDVALUE; +#ifdef CONFIG_RSBAC_DEBUG + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_acl_get_rights(): called from interrupt!\n"); + } +#endif + desc.subj_type = subj_type; + desc.subj_id = subj_id; + + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + /* default entry? */ + if (RSBAC_IS_ZERO_DEV(tid.file.device) && !tid.file.inode + && !tid.file.dentry_p) { + if (rsbac_ta_list_get_data_ttl + (ta_number, default_fd_handle, NULL, &desc, + rights_p)) { + /* last resort: default rights */ + *rights_p = default_fd_rights; + } + return 0; + } + *rights_p = 0; + srcu_idx = srcu_read_lock(&device_list_srcu); + /* use loop for inheritance - used to be recursive calls */ + for (;;) { + /* lookup device */ + device_p = acl_lookup_device(tid.file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_acl_get_rights(): Could not lookup device %02u:%02u!\n", + RSBAC_MAJOR(tid.file. + device), + RSBAC_MINOR(tid.file. + device)); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + inode_nr = tid.file.inode; + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + device_p->handle, + NULL, + &inode_nr, + &desc, + &i_rights)) + { + *rights_p |= (i_rights & mask); + /* leave loop */ + break; + } else if (inherit) { + enum rsbac_target_t parent_target; + union rsbac_target_id_t parent_tid; + rsbac_acl_rights_vector_t i_mask; + + /* get mask to filter through in next round */ + if (rsbac_ta_list_lol_get_data_ttl + (ta_number, device_p->handle, + NULL, &inode_nr, &i_mask)) { + /* no mask found, set default */ + i_mask = RSBAC_ACL_DEFAULT_FD_MASK; + } + /* mask into cumulative mask */ + mask &= i_mask; + + /* inheritance possible? */ + if (!rsbac_get_parent + (target, tid, &parent_target, + &parent_tid)) { + target = parent_target; + tid = parent_tid; + /* next round */ + continue; + } else { + /* no inheritance possible -> try default_fd_acl */ + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_fd_handle, + NULL, &desc, &i_rights)) { + /* found, use it */ + *rights_p |= + (i_rights & mask); + } else { + /* last resort: default rights */ + *rights_p |= + (default_fd_rights & + mask); + } + } + /* leave loop */ + break; + } else { /* do not inherit */ + + /* last resort: default rights */ + *rights_p |= default_fd_rights; + /* leave loop */ + break; + } + } /* end of for(;;) inheritance loop */ + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; + + case T_DEV: + /* default entry? */ + + if (RSBAC_IS_ZERO_DEV_DESC(tid.dev)) { + if (rsbac_ta_list_get_data_ttl + (ta_number, default_dev_handle, NULL, &desc, + rights_p)) { + /* last resort: default rights */ + *rights_p = default_dev_rights; + } + return 0; + } + if ((tid.dev.type >= D_char_major) + || (tid.dev.type == D_block_major) + ) { + tid.dev.type -= (D_block_major - D_block); + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + dev_major_handle, + NULL, + &tid.dev, + &desc, + &i_rights)) + { + *rights_p |= i_rights; + } else { + rsbac_acl_rights_vector_t mask2; + + /* get mask to filter through */ + if (rsbac_ta_list_lol_get_data_ttl + (ta_number, dev_major_handle, NULL, + &tid.dev, &mask2)) { + /* no mask found, set default */ + mask2 = RSBAC_ACL_DEFAULT_DEV_MASK; + } + /* try default_dev_acl */ + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_dev_handle, NULL, + &desc, rights_p)) { + *rights_p &= mask2; + } else { + /* last resort: default rights */ + *rights_p = + default_dev_rights & mask2; + } + } + return 0; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + dev_handle, + NULL, + &tid.dev, + &desc, &i_rights)) { + *rights_p |= i_rights; + } else { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (rsbac_ta_list_lol_get_data_ttl(ta_number, + dev_handle, + NULL, + &tid.dev, + &mask)) { + /* no mask found, set default */ + mask = RSBAC_ACL_DEFAULT_DEV_MASK; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + dev_major_handle, + NULL, + &tid.dev, + &desc, + &i_rights)) + { + i_rights &= mask; + *rights_p |= i_rights; + } else { + rsbac_acl_rights_vector_t mask2; + + /* get mask to filter through */ + if (rsbac_ta_list_lol_get_data_ttl + (ta_number, dev_major_handle, NULL, + &tid.dev, &mask2)) { + /* no mask found, set default */ + mask2 = RSBAC_ACL_DEFAULT_DEV_MASK; + } + /* try default_dev_acl */ + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_dev_handle, NULL, + &desc, rights_p)) { + *rights_p &= mask; + *rights_p &= mask2; + } else { + /* last resort: default rights */ + *rights_p = + default_dev_rights & mask & + mask2; + } + } + } + return 0; + + case T_IPC: + + /* Use default ACL */ + if (rsbac_ta_list_get_data_ttl + (ta_number, default_ipc_handle, NULL, &desc, + rights_p)) { + /* last resort: default rights */ + *rights_p = default_ipc_rights; + } + return 0; + + case T_SCD: + /* default entry? */ + if ((tid.scd == AST_none) + || (tid.scd == ST_none) + ) { + if (rsbac_ta_list_get_data_ttl + (ta_number, default_scd_handle, NULL, &desc, + rights_p)) { + /* last resort: default rights */ + *rights_p = default_scd_rights; + } + return 0; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + scd_handle, + NULL, + &tid.scd, + &desc, &i_rights)) { + *rights_p |= i_rights; + } else { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (rsbac_ta_list_lol_get_data_ttl(ta_number, + scd_handle, + NULL, + &tid.scd, + &mask)) { + /* no mask found, set default */ + mask = RSBAC_ACL_DEFAULT_SCD_MASK; + } + /* try default_dev_acl */ + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_scd_handle, NULL, &desc, + rights_p)) { + *rights_p &= mask; + } else { + /* last resort: default rights */ + *rights_p = default_scd_rights & mask; + } + } + return 0; + + case T_USER: + /* default entry? */ + if (tid.user == RSBAC_NO_USER) { + if (rsbac_ta_list_get_data_ttl + (ta_number, default_u_handle, NULL, &desc, + rights_p)) { + /* last resort: default rights */ + *rights_p = default_u_rights; + } + return 0; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + u_handle, + NULL, + &tid.user, + &desc, &i_rights)) { + *rights_p |= i_rights; + } else { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (rsbac_ta_list_lol_get_data_ttl(ta_number, + u_handle, + NULL, + &tid.user, + &mask)) { + /* no mask found, set default */ + mask = RSBAC_ACL_DEFAULT_U_MASK; + } + /* try default_u_acl */ + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_u_handle, NULL, &desc, + rights_p)) { + *rights_p &= mask; + } else { + /* last resort: default rights */ + *rights_p = default_u_rights & mask; + } + } + return 0; + + case T_PROCESS: + + /* Use default entry */ + if (rsbac_ta_list_get_data_ttl(ta_number, default_p_handle, + NULL, &desc, rights_p)) { + /* last resort: default rights */ + *rights_p = default_p_rights; + } + return 0; + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + case T_GROUP: + /* default entry? */ + if (tid.group == RSBAC_NO_GROUP) { + if (rsbac_ta_list_get_data_ttl + (ta_number, default_g_handle, NULL, &desc, + rights_p)) { + /* last resort: default rights */ + *rights_p = default_g_rights; + } + return 0; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + g_handle, + NULL, + &tid.group, + &desc, &i_rights)) { + *rights_p |= i_rights; + } else { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (rsbac_ta_list_lol_get_data_ttl(ta_number, + g_handle, + NULL, + &tid.group, + &mask)) { + /* no mask found, set default */ + mask = RSBAC_ACL_DEFAULT_G_MASK; + } + /* try default_u_acl */ + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_g_handle, NULL, &desc, + rights_p)) { + *rights_p &= mask; + } else { + /* last resort: default rights */ + *rights_p = default_g_rights & mask; + } + } + return 0; +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + case T_NETDEV: + /* default entry? */ + + if (!tid.netdev[0]) { + if (rsbac_ta_list_get_data_ttl + (ta_number, default_netdev_handle, NULL, &desc, + rights_p)) { + /* last resort: default rights */ + *rights_p = default_netdev_rights; + } + return 0; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + netdev_handle, + NULL, + &tid.netdev, + &desc, &i_rights)) { + *rights_p |= i_rights; + } else { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (rsbac_ta_list_lol_get_data_ttl(ta_number, + netdev_handle, + NULL, + &tid.netdev, + &mask)) { + /* no mask found, set default */ + mask = RSBAC_ACL_DEFAULT_NETDEV_MASK; + } + /* try default_dev_acl */ + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_netdev_handle, NULL, &desc, + rights_p)) { + *rights_p &= mask; + } else { + /* last resort: default rights */ + *rights_p = default_netdev_rights & mask; + } + } + return 0; +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + /* rights to template itself */ + case T_NETTEMP_NT: + /* default entry? */ + + if (!tid.nettemp) { + if (rsbac_ta_list_get_data_ttl + (ta_number, default_nettemp_nt_handle, NULL, + &desc, rights_p)) { + /* last resort: default rights */ + *rights_p = default_nettemp_nt_rights; + } + return 0; + } + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + nettemp_nt_handle, + NULL, + &tid.nettemp, + &desc, &i_rights)) { + *rights_p |= i_rights; + } else { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (rsbac_ta_list_lol_get_data_ttl(ta_number, + nettemp_nt_handle, + NULL, + &tid.nettemp, + &mask)) { + /* no mask found, set default */ + mask = RSBAC_ACL_DEFAULT_NETTEMP_MASK; + } + /* try default_dev_acl */ + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_nettemp_nt_handle, NULL, + &desc, rights_p)) { + *rights_p &= mask; + } else { + /* last resort: default rights */ + *rights_p = + default_nettemp_nt_rights & mask; + } + } + return 0; + + /* rights to netobjs fitting this template */ + case T_NETTEMP: + /* default entry? */ + + if (!tid.nettemp) { + if (rsbac_ta_list_get_data_ttl + (ta_number, default_netobj_handle, NULL, &desc, + rights_p)) { + /* last resort: default rights */ + *rights_p = default_netobj_rights; + } + return 0; + } + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + nettemp_handle, + NULL, + &tid.nettemp, + &desc, &i_rights)) { + *rights_p |= i_rights; + } else { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (rsbac_ta_list_lol_get_data_ttl(ta_number, + nettemp_handle, + NULL, + &tid.nettemp, + &mask)) { + /* no mask found, set default */ + mask = RSBAC_ACL_DEFAULT_NETOBJ_MASK; + } + /* try default_dev_acl */ + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_netobj_handle, NULL, &desc, + rights_p)) { + *rights_p &= mask; + } else { + /* last resort: default rights */ + *rights_p = default_netobj_rights & mask; + } + } + return 0; + + case T_NETOBJ: + /* default entry? */ + + if (!tid.nettemp) { + if (rsbac_ta_list_get_data_ttl + (ta_number, default_netobj_handle, NULL, &desc, + rights_p)) { + /* last resort: default rights */ + *rights_p = default_netobj_rights; + } + return 0; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + netobj_handle, + NULL, + &tid.netobj.sock_p, + &desc, &i_rights)) { + *rights_p |= i_rights; + } else { + rsbac_acl_rights_vector_t mask; + rsbac_net_temp_id_t temp = 0; + + /* get mask to filter through */ + if (rsbac_ta_list_lol_get_data_ttl(ta_number, + nettemp_handle, + NULL, + &temp, &mask)) { + /* no mask found, set default */ + mask = RSBAC_ACL_DEFAULT_NETOBJ_MASK; + } + /* try nettemp_acl */ + if(!ta_number && tid.netobj.local_temp) + temp = tid.netobj.local_temp; + else + rsbac_ta_net_lookup_templates(ta_number, + &tid.netobj, + &temp, NULL); + + if (temp + && + !rsbac_ta_list_lol_get_subdata_ttl(ta_number, + nettemp_handle, + NULL, &temp, + &desc, + &i_rights)) + { + *rights_p |= i_rights; + } else { + /* get mask to filter through */ + if (temp + && + rsbac_ta_list_lol_get_data_ttl + (ta_number, nettemp_handle, NULL, + &temp, &mask)) { + /* no mask found, set default */ + mask = + RSBAC_ACL_DEFAULT_NETOBJ_MASK; + } + /* try default_netobj_acl */ + if (!rsbac_ta_list_get_data_ttl + (ta_number, default_netobj_handle, + NULL, &desc, rights_p)) { + *rights_p &= mask; + } else { + /* last resort: default rights */ + *rights_p = + default_netobj_rights & mask; + } + } + } + return 0; +#endif /* NET_OBJ_PROT */ + + default: + return -RSBAC_EINVALIDTARGET; + } +} + +/* rsbac_acl_get_single_right + * Show, whether individual right is set for given target and subject. + * If right is not set, it is checked at all parents, unless it has been + * masked out. (Special case SUPERVISOR: unless + * CONFIG_RSBAC_ACL_SUPER_FILTER is set *and* supervisor has been masked out) + */ + +int rsbac_acl_get_single_right(enum rsbac_target_t target, + union rsbac_target_id_t tid, + enum rsbac_acl_subject_type_t subj_type, + rsbac_acl_subject_id_t subj_id, + enum rsbac_adf_request_t right, + rsbac_boolean_t * result) +{ + struct rsbac_acl_device_list_item_t *device_p; + rsbac_acl_rights_vector_t i_rvec; + rsbac_acl_rights_vector_t i_rights; + struct rsbac_acl_entry_desc_t desc; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_acl_get_single_right(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (!result) + return -RSBAC_EINVALIDPOINTER; + if ((subj_type >= ACLS_NONE) + || ((enum rsbac_acl_special_rights_t) right >= ACLR_NONE) + ) + return -RSBAC_EINVALIDVALUE; +#ifdef CONFIG_RSBAC_DEBUG + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_acl_get_single_right(): called from interrupt!\n"); + } +#endif + i_rvec = (rsbac_acl_rights_vector_t) 1 << right; + + desc.subj_type = subj_type; + desc.subj_id = subj_id; + + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + /* default entry? */ + if (RSBAC_IS_ZERO_DEV(tid.file.device) && !tid.file.inode + && !tid.file.dentry_p) { + if (!rsbac_ta_list_get_data_ttl + (0, default_fd_handle, NULL, &desc, + &i_rights)) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_fd_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + } + srcu_idx = srcu_read_lock(&device_list_srcu); + /* use loop for inheritance - used to be recursive calls */ + for (;;) { + /* lookup device */ + device_p = acl_lookup_device(tid.file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_acl_get_single_right(): Could not lookup device, blindly granting access!\n"); + srcu_read_unlock(&device_list_srcu, srcu_idx); + *result = TRUE; + return 0; + } + inode_nr = tid.file.inode; + if (!rsbac_ta_list_lol_get_subdata_ttl(0, + device_p->handle, + NULL, + &inode_nr, + &desc, + &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + srcu_read_unlock(&device_list_srcu, srcu_idx); + return 0; + } + + { + enum rsbac_target_t parent_target; + union rsbac_target_id_t parent_tid; + +#ifndef CONFIG_RSBAC_ACL_SUPER_FILTER + if ((enum rsbac_acl_special_rights_t) right != ACLR_SUPERVISOR) +#endif + { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (!rsbac_ta_list_lol_get_data_ttl + (0, device_p->handle, + NULL, &inode_nr, &mask) + && !(mask & i_rvec) + ) { + srcu_read_unlock(&device_list_srcu, srcu_idx); + *result = FALSE; + return 0; + } + } + + /* inheritance possible? */ + if (!rsbac_get_parent + (target, tid, &parent_target, + &parent_tid)) { + target = parent_target; + tid = parent_tid; + continue; + } else { + /* no inheritance possible -> try default_fd_acl */ + if (!rsbac_ta_list_get_data_ttl + (0, default_fd_handle, NULL, + &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_fd_rights & + i_rvec) + *result = TRUE; + else + *result = FALSE; + } + /* free access to device_list_head - see above */ + srcu_read_unlock(&device_list_srcu, srcu_idx); + return 0; + } + } + } /* end of for(;;) for inheritance */ + + case T_DEV: + if (RSBAC_IS_ZERO_DEV_DESC(tid.dev)) { + if (!rsbac_ta_list_get_data_ttl + (0, default_dev_handle, NULL, &desc, + &i_rights)) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_dev_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + } + + if (tid.dev.type >= D_block_major) { + tid.dev.type -= (D_block_major - D_block); + if (!rsbac_ta_list_lol_get_subdata_ttl + (0, dev_major_handle, NULL, &tid.dev, &desc, + &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + return 0; + } +#ifndef CONFIG_RSBAC_ACL_SUPER_FILTER + if ((enum rsbac_acl_special_rights_t) right != ACLR_SUPERVISOR) +#endif + { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (!rsbac_ta_list_lol_get_data_ttl + (0, dev_major_handle, NULL, &tid.dev, + &mask) + && !(mask & i_rvec) + ) { + *result = FALSE; + return 0; + } + } + /* no inheritance possible -> try default acl */ + if (!rsbac_ta_list_get_data_ttl + (0, default_dev_handle, NULL, &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_dev_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + } + if (!rsbac_ta_list_lol_get_subdata_ttl(0, dev_handle, + NULL, + &tid.dev, + &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + return 0; + } +#ifndef CONFIG_RSBAC_ACL_SUPER_FILTER + if ((enum rsbac_acl_special_rights_t) right != ACLR_SUPERVISOR) +#endif + { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (!rsbac_ta_list_lol_get_data_ttl(0, dev_handle, + NULL, + &tid.dev, + &mask) + && !(mask & i_rvec) + ) { + *result = FALSE; + return 0; + } + } + if (!rsbac_ta_list_lol_get_subdata_ttl(0, dev_major_handle, + NULL, + &tid.dev, + &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + return 0; + } +#ifndef CONFIG_RSBAC_ACL_SUPER_FILTER + if ((enum rsbac_acl_special_rights_t) right != ACLR_SUPERVISOR) +#endif + { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (!rsbac_ta_list_lol_get_data_ttl + (0, dev_major_handle, NULL, &tid.dev, &mask) + && !(mask & i_rvec) + ) { + *result = FALSE; + return 0; + } + } + /* no inheritance possible -> try default acl */ + if (!rsbac_ta_list_get_data_ttl(0, default_dev_handle, + NULL, &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_dev_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + + case T_IPC: + /* Use default entry */ + if (!rsbac_ta_list_get_data_ttl(0, default_ipc_handle, + NULL, &desc, &i_rights)) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_ipc_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + + case T_SCD: + if (tid.scd == AST_none) { + if (!rsbac_ta_list_get_data_ttl + (0, default_scd_handle, NULL, &desc, + &i_rights)) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_scd_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + } + + if (!rsbac_ta_list_lol_get_subdata_ttl(0, scd_handle, + NULL, + &tid.scd, + &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + return 0; + } +#ifndef CONFIG_RSBAC_ACL_SUPER_FILTER + if ((enum rsbac_acl_special_rights_t) right != ACLR_SUPERVISOR) +#endif + { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (!rsbac_ta_list_lol_get_data_ttl(0, scd_handle, + NULL, + &tid.scd, + &mask) + && !(mask & i_rvec) + ) { + *result = FALSE; + return 0; + } + } + + /* no inheritance possible -> try default acl */ + if (!rsbac_ta_list_get_data_ttl(0, default_scd_handle, + NULL, &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_scd_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + + case T_USER: + if (tid.user == RSBAC_NO_USER) { + if (!rsbac_ta_list_get_data_ttl + (0, default_u_handle, NULL, &desc, + &i_rights)) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_u_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + } + + if (!rsbac_ta_list_lol_get_subdata_ttl(0, u_handle, + NULL, + &tid.user, + &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + return 0; + } +#ifndef CONFIG_RSBAC_ACL_SUPER_FILTER + if ((enum rsbac_acl_special_rights_t) right != ACLR_SUPERVISOR) +#endif + { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (!rsbac_ta_list_lol_get_data_ttl(0, u_handle, + NULL, + &tid.user, + &mask) + && !(mask & i_rvec) + ) { + *result = FALSE; + return 0; + } + } + + /* no inheritance possible -> try default acl */ + if (!rsbac_ta_list_get_data_ttl(0, default_u_handle, + NULL, &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_u_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + + case T_PROCESS: + /* Use default entry */ + if (!rsbac_ta_list_get_data_ttl(0, default_p_handle, + NULL, &desc, &i_rights)) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_p_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + case T_GROUP: + if (tid.group == RSBAC_NO_GROUP) { + if (!rsbac_ta_list_get_data_ttl + (0, default_g_handle, NULL, &desc, + &i_rights)) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_g_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + } + + if (!rsbac_ta_list_lol_get_subdata_ttl(0, g_handle, + NULL, + &tid.group, + &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + return 0; + } +#ifndef CONFIG_RSBAC_ACL_SUPER_FILTER + if ((enum rsbac_acl_special_rights_t) right != ACLR_SUPERVISOR) +#endif + { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (!rsbac_ta_list_lol_get_data_ttl(0, g_handle, + NULL, + &tid.group, + &mask) + && !(mask & i_rvec) + ) { + *result = FALSE; + return 0; + } + } + + /* no inheritance possible -> try default acl */ + if (!rsbac_ta_list_get_data_ttl(0, default_g_handle, + NULL, &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_g_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; +#endif + +#if defined(CONFIG_RSBAC_ACL_NET_DEV_PROT) + case T_NETDEV: + if (!tid.netdev[0]) { + if (!rsbac_ta_list_get_data_ttl + (0, default_netdev_handle, NULL, &desc, + &i_rights)) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_netdev_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + } + + if (!rsbac_ta_list_lol_get_subdata_ttl(0, netdev_handle, + NULL, + &tid.netdev, + &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + return 0; + } +#ifndef CONFIG_RSBAC_ACL_SUPER_FILTER + if ((enum rsbac_acl_special_rights_t) right != ACLR_SUPERVISOR) +#endif + { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (!rsbac_ta_list_lol_get_data_ttl + (0, netdev_handle, NULL, &tid.netdev, &mask) + && !(mask & i_rvec) + ) { + *result = FALSE; + return 0; + } + } + + /* no inheritance possible -> try default acl */ + if (!rsbac_ta_list_get_data_ttl(0, default_netdev_handle, + NULL, &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_netdev_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; +#endif + +#if defined(CONFIG_RSBAC_ACL_NET_OBJ_PROT) + case T_NETTEMP_NT: + case T_NETTEMP: + if (!tid.nettemp) { + if (!rsbac_ta_list_get_data_ttl + (0, default_nettemp_nt_handle, NULL, &desc, + &i_rights)) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_nettemp_nt_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + } + + /* There should be no template, which is to be created, so skip nettemp_nt list */ + if (right != R_CREATE) { + if (!rsbac_net_template_exist(tid.nettemp)) + return FALSE; + if (!rsbac_ta_list_lol_get_subdata_ttl + (0, nettemp_nt_handle, NULL, &tid.nettemp, + &desc, &i_rights) + && (i_rights & i_rvec) + ) { + *result = TRUE; + return 0; + } +#ifndef CONFIG_RSBAC_ACL_SUPER_FILTER + if ((enum rsbac_acl_special_rights_t) right != ACLR_SUPERVISOR) +#endif + { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (!rsbac_ta_list_lol_get_data_ttl + (0, nettemp_nt_handle, NULL, + &tid.nettemp, &mask) + && !(mask & i_rvec) + ) { + *result = FALSE; + return 0; + } + } + } + + /* no inheritance possible -> try default acl */ + if (!rsbac_ta_list_get_data_ttl + (0, default_nettemp_nt_handle, NULL, &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_nettemp_nt_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + + case T_NETOBJ: + if (!tid.netobj.sock_p) { + if (!rsbac_ta_list_get_data_ttl + (0, default_netobj_handle, NULL, &desc, + &i_rights)) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_netobj_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; + } + + if (!rsbac_ta_list_lol_get_subdata_ttl(0, netobj_handle, + NULL, + &tid.netobj.sock_p, + &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + return 0; + } +#ifndef CONFIG_RSBAC_ACL_SUPER_FILTER + if ((enum rsbac_acl_special_rights_t) right != ACLR_SUPERVISOR) +#endif + { + rsbac_acl_rights_vector_t mask; + + /* get mask to filter through */ + if (!rsbac_ta_list_lol_get_data_ttl + (0, netobj_handle, NULL, &tid.netobj.sock_p, + &mask) + && !(mask & i_rvec) + ) { + *result = FALSE; + return 0; + } + } + /* Try net template */ + { + rsbac_net_temp_id_t temp = 0; + + if (rsbac_net_remote_request(right)) { + if(tid.netobj.remote_temp) + temp = tid.netobj.remote_temp; + else + rsbac_ta_net_lookup_templates(0, + &tid.netobj, + NULL, &temp); + } else { + if(tid.netobj.local_temp) + temp = tid.netobj.local_temp; + else + rsbac_ta_net_lookup_templates(0, + &tid.netobj, + &temp, NULL); + } + if (temp + && !rsbac_ta_list_lol_get_subdata_ttl(0, + nettemp_handle, + NULL, + &temp, + &desc, + &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + return 0; + } +#ifndef CONFIG_RSBAC_ACL_SUPER_FILTER + if ((enum rsbac_acl_special_rights_t) right != ACLR_SUPERVISOR) +#endif + { + rsbac_acl_rights_vector_t mask; + + /* get mask from template to filter through */ + if (!rsbac_ta_list_lol_get_data_ttl + (0, nettemp_handle, NULL, &temp, &mask) + && !(mask & i_rvec) + ) { + *result = FALSE; + return 0; + } + } + } + + /* no inheritance possible -> try default acl */ + if (!rsbac_ta_list_get_data_ttl(0, default_netobj_handle, + NULL, &desc, &i_rights) + ) { + if (i_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } else { + if (default_netobj_rights & i_rvec) + *result = TRUE; + else + *result = FALSE; + } + return 0; +#endif /* NET_OBJ_PROT */ + + default: + return -RSBAC_EINVALIDTARGET; + } +} + +/************************************************* + * rsbac_acl_get_tlist + * Get subjects from ACL entries for given target. + */ + +int rsbac_acl_get_tlist(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t tid, + struct rsbac_acl_entry_t **entry_pp, + rsbac_time_t ** ttl_pp) +{ + int count = 0; + struct rsbac_acl_device_list_item_t *device_p; + int srcu_idx; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_acl_get_tlist(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (!entry_pp) + return -RSBAC_EINVALIDPOINTER; +#ifdef CONFIG_RSBAC_DEBUG + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_acl_get_tlist(): called from interrupt!\n"); + } +#endif + switch (target) { + case T_FD: + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + /* default entry? */ + if (RSBAC_IS_ZERO_DEV(tid.file.device) && !tid.file.inode + && !tid.file.dentry_p) + return rsbac_ta_list_get_all_items_ttl(ta_number, + default_fd_handle, + (void **) + entry_pp, + ttl_pp); + srcu_idx = srcu_read_lock(&device_list_srcu); + /* lookup device */ + device_p = acl_lookup_device(tid.file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_acl_get_tlist(): Could not lookup device!\n"); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + /* protect this list */ + count = rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + device_p-> + handle, + &tid.file. + inode, + (void **) + entry_pp, + ttl_pp); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return count; + + case T_DEV: + if (RSBAC_IS_ZERO_DEV_DESC(tid.dev)) + return rsbac_ta_list_get_all_items_ttl(ta_number, + default_dev_handle, + (void **) + entry_pp, + ttl_pp); + else + switch (tid.dev.type) { + case D_char: + case D_block: + return + rsbac_ta_list_lol_get_all_subitems_ttl + (ta_number, dev_handle, &tid.dev, + (void **) entry_pp, ttl_pp); + + case D_char_major: + case D_block_major: + tid.dev.type -= (D_block_major - D_block); + return + rsbac_ta_list_lol_get_all_subitems_ttl + (ta_number, dev_major_handle, &tid.dev, + (void **) entry_pp, ttl_pp); + + default: + return -RSBAC_EINVALIDTARGET; + } + + case T_IPC: + /* default entry */ + return rsbac_ta_list_get_all_items_ttl(ta_number, + default_ipc_handle, + (void **) entry_pp, + ttl_pp); + + case T_SCD: + if ((tid.scd == AST_none) + || (tid.scd == ST_none) + ) + return rsbac_ta_list_get_all_items_ttl(ta_number, + default_scd_handle, + (void **) + entry_pp, + ttl_pp); + else + return + rsbac_ta_list_lol_get_all_subitems_ttl + (ta_number, scd_handle, &tid.scd, + (void **) entry_pp, ttl_pp); + + case T_USER: + if (tid.user == RSBAC_NO_USER) + return rsbac_ta_list_get_all_items_ttl(ta_number, + default_u_handle, + (void **) + entry_pp, + ttl_pp); + else + return + rsbac_ta_list_lol_get_all_subitems_ttl + (ta_number, u_handle, &tid.user, + (void **) entry_pp, ttl_pp); + + case T_PROCESS: + return rsbac_ta_list_get_all_items_ttl(ta_number, + default_p_handle, + (void **) entry_pp, + ttl_pp); + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + case T_GROUP: + if (tid.group == RSBAC_NO_GROUP) + return rsbac_ta_list_get_all_items_ttl(ta_number, + default_g_handle, + (void **) + entry_pp, + ttl_pp); + else + return + rsbac_ta_list_lol_get_all_subitems_ttl + (ta_number, g_handle, &tid.group, + (void **) entry_pp, ttl_pp); +#endif + +#if defined(CONFIG_RSBAC_ACL_NET_DEV_PROT) + case T_NETDEV: + if (!tid.netdev[0]) + return rsbac_ta_list_get_all_items_ttl(ta_number, + default_netdev_handle, + (void **) + entry_pp, + ttl_pp); + else + return + rsbac_ta_list_lol_get_all_subitems_ttl + (ta_number, netdev_handle, &tid.netdev, + (void **) entry_pp, ttl_pp); +#endif + +#if defined(CONFIG_RSBAC_ACL_NET_OBJ_PROT) + case T_NETTEMP_NT: + if (!tid.nettemp) + return rsbac_ta_list_get_all_items_ttl(ta_number, + default_nettemp_nt_handle, + (void **) + entry_pp, + ttl_pp); + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + return rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + nettemp_nt_handle, + &tid.nettemp, + (void **) + entry_pp, + ttl_pp); + + case T_NETTEMP: + if (!tid.nettemp) + return -RSBAC_EINVALIDTARGET; + if (!rsbac_ta_net_template_exist(ta_number, tid.nettemp)) + return -RSBAC_EINVALIDTARGET; + return rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + nettemp_handle, + &tid.nettemp, + (void **) + entry_pp, + ttl_pp); + + case T_NETOBJ: + if (!tid.nettemp) + return rsbac_ta_list_get_all_items_ttl(ta_number, + default_netobj_handle, + (void **) + entry_pp, + ttl_pp); + else + return + rsbac_ta_list_lol_get_all_subitems_ttl + (ta_number, netobj_handle, &tid.netobj.sock_p, + (void **) entry_pp, ttl_pp); +#endif /* NET_OBJ_PROT */ + + default: + return -RSBAC_EINVALIDTARGET; + } +} + +/* Remove a subject from all acls (but not from group memberships, see remove_user) */ +int rsbac_acl_remove_subject(rsbac_list_ta_number_t ta_number, + struct rsbac_acl_entry_desc_t desc) +{ + struct rsbac_acl_device_list_head_t *head_p; + struct rsbac_acl_device_list_item_t *device_p; + int srcu_idx; + + if (desc.subj_type >= ACLS_NONE) + return -RSBAC_EINVALIDVALUE; + + /* remove from default ACLs */ + rsbac_ta_list_remove(ta_number, default_fd_handle, &desc); + rsbac_ta_list_remove(ta_number, default_dev_handle, &desc); + rsbac_ta_list_remove(ta_number, default_ipc_handle, &desc); + rsbac_ta_list_remove(ta_number, default_scd_handle, &desc); + rsbac_ta_list_remove(ta_number, default_u_handle, &desc); + rsbac_ta_list_remove(ta_number, default_p_handle, &desc); +#ifdef CONFIG_RSBAC_ACL_UM_PROT + rsbac_ta_list_remove(ta_number, default_g_handle, &desc); +#endif +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + rsbac_ta_list_remove(ta_number, default_netdev_handle, &desc); +#endif +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + rsbac_ta_list_remove(ta_number, default_nettemp_nt_handle, &desc); + rsbac_ta_list_remove(ta_number, default_netobj_handle, &desc); +#endif + + srcu_idx = srcu_read_lock(&device_list_srcu); + head_p = srcu_dereference(device_list_head_p, &device_list_srcu); + device_p = srcu_dereference(head_p->head, &device_list_srcu); + while (device_p) { + rsbac_ta_list_lol_subremove_from_all(ta_number, + device_p->handle, + &desc); + device_p = srcu_dereference(device_p->next, &device_list_srcu); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + + /* dev list */ + rsbac_ta_list_lol_subremove_from_all(ta_number, dev_major_handle, + &desc); + rsbac_ta_list_lol_subremove_from_all(ta_number, dev_handle, &desc); + + /* scd list */ + rsbac_ta_list_lol_subremove_from_all(ta_number, scd_handle, &desc); + + /* user list */ + rsbac_ta_list_lol_subremove_from_all(ta_number, u_handle, &desc); + +#ifdef CONFIG_RSBAC_ACL_UM_PROT + /* Linux group list */ + rsbac_ta_list_lol_subremove_from_all(ta_number, g_handle, &desc); +#endif + +#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT + /* netdev list */ + rsbac_ta_list_lol_subremove_from_all(ta_number, netdev_handle, + &desc); +#endif +#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT + rsbac_ta_list_lol_subremove_from_all(ta_number, nettemp_nt_handle, + &desc); + rsbac_ta_list_lol_subremove_from_all(ta_number, nettemp_handle, + &desc); + rsbac_ta_list_lol_subremove_from_all(ta_number, netobj_handle, + &desc); +#endif + + return 0; +} + +/* add a group with new id and fill this id into *group_id_p */ +/* if old content of group_id_p is 0, make new id, else try given id */ +int rsbac_acl_add_group(rsbac_list_ta_number_t ta_number, + rsbac_uid_t owner, + enum rsbac_acl_group_type_t type, + const char *name, rsbac_acl_group_id_t * group_id_p) +{ + struct rsbac_acl_group_entry_t entry; + int err = 0; + + if (type >= ACLG_NONE) + return -RSBAC_EINVALIDVALUE; + if (!name || !group_id_p) + return -RSBAC_EINVALIDPOINTER; + if (!name[0]) + return -RSBAC_EINVALIDVALUE; + entry.owner = owner; + entry.type = type; + strncpy(entry.name, name, RSBAC_ACL_GROUP_NAMELEN - 1); + entry.name[RSBAC_ACL_GROUP_NAMELEN - 1] = 0; + if (!*group_id_p) { + /* step new group counter */ + group_last_new++; + /* Just in case the counter has wrapped. It is almost impossible that all IDs are in use. */ + while (!group_last_new + || rsbac_ta_list_exist(ta_number, group_handle, + &group_last_new)) + group_last_new++; + + entry.id = group_last_new; + } else { + if (rsbac_ta_list_exist + (ta_number, group_handle, group_id_p)) { + return -RSBAC_EEXISTS; + } else + entry.id = *group_id_p; + } + if (rsbac_ta_list_add_ttl + (ta_number, group_handle, 0, &entry.id, &entry)) + err = -RSBAC_ECOULDNOTADDITEM; + else { + *group_id_p = entry.id; + } + return err; +} + +int rsbac_acl_change_group(rsbac_list_ta_number_t ta_number, + rsbac_acl_group_id_t id, + rsbac_uid_t owner, + enum rsbac_acl_group_type_t type, const char *name) +{ + struct rsbac_acl_group_entry_t entry; + + if (!id) + return -RSBAC_EINVALIDVALUE; + if (!rsbac_ta_list_exist(ta_number, group_handle, &id)) + return -RSBAC_ENOTFOUND; + if (!name) + return -RSBAC_EINVALIDPOINTER; + if (!name[0]) + return -RSBAC_EINVALIDVALUE; + entry.id = id; + entry.owner = owner; + entry.type = type; + strncpy(entry.name, name, RSBAC_ACL_GROUP_NAMELEN); + entry.name[RSBAC_ACL_GROUP_NAMELEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, group_handle, 0, &entry.id, + &entry); +} + +int rsbac_acl_remove_group(rsbac_list_ta_number_t ta_number, + rsbac_acl_group_id_t id) +{ + int err = 0; + + if (!id) + return -RSBAC_EINVALIDVALUE; + + err = rsbac_ta_list_remove(ta_number, group_handle, &id); + if (!err) { + struct rsbac_acl_entry_desc_t desc; + + /* cleanup group memberships */ + rsbac_ta_list_lol_subremove_from_all(ta_number, gm_handle, + &id); + desc.subj_type = ACLS_GROUP; + desc.subj_id = id; + err = rsbac_acl_remove_subject(ta_number, desc); + } + return err; +} + +int rsbac_acl_get_group_entry(rsbac_list_ta_number_t ta_number, + rsbac_acl_group_id_t group, + struct rsbac_acl_group_entry_t *entry_p) +{ + if (!group) + return -RSBAC_EINVALIDVALUE; + if (!entry_p) + return -RSBAC_EINVALIDPOINTER; + return rsbac_ta_list_get_data_ttl(ta_number, group_handle, NULL, + &group, entry_p); +} + +int rsbac_acl_list_groups(rsbac_list_ta_number_t ta_number, + rsbac_uid_t owner, + rsbac_boolean_t include_global, + struct rsbac_acl_group_entry_t **entry_pp) +{ + long count; + struct rsbac_acl_group_entry_t *local_entry_p; + + if (!entry_pp) + return -RSBAC_EINVALIDPOINTER; + count = + rsbac_ta_list_get_all_data(ta_number, group_handle, + (void **) &local_entry_p); + if (count > 0) { + long i; + long rescount = 0; + + *entry_pp = rsbac_kmalloc(count * sizeof(**entry_pp)); + if (!*entry_pp) { + rsbac_kfree(local_entry_p); + return -RSBAC_ENOMEM; + } + for (i = 0; i < count; i++) { + if ((local_entry_p[i].owner == owner) + || (include_global + && (local_entry_p[i].type == ACLG_GLOBAL) + ) + ) { + memcpy(&(*entry_pp)[rescount], + &local_entry_p[i], + sizeof(local_entry_p[i])); + rescount++; + } + } + rsbac_kfree(local_entry_p); + count = rescount; + } + return count; +} + +/* check group existence */ +rsbac_boolean_t rsbac_acl_group_exist(rsbac_acl_group_id_t group) +{ + if (!group) + return TRUE; + return rsbac_ta_list_exist(0, group_handle, &group); +} + +int rsbac_acl_add_group_member(rsbac_list_ta_number_t ta_number, + rsbac_acl_group_id_t group, + rsbac_uid_t user, rsbac_time_t ttl) +{ + int err = 0; + + if (!group) + return -RSBAC_EINVALIDVALUE; + if (!rsbac_ta_list_exist(ta_number, group_handle, &group)) + return -RSBAC_EINVALIDVALUE; + + if (!rsbac_ta_list_lol_exist(ta_number, gm_handle, &user)) { + err = + rsbac_ta_list_lol_add_ttl(ta_number, gm_handle, 0, + &user, NULL); + if (err) + return err; + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, gm_handle, ttl, + &user, &group, NULL); +} + +int rsbac_acl_remove_group_member(rsbac_list_ta_number_t ta_number, + rsbac_acl_group_id_t group, + rsbac_uid_t user) +{ + int err; + + if (!group) + return -RSBAC_EINVALIDVALUE; + if (!rsbac_ta_list_exist(ta_number, group_handle, &group)) + return -RSBAC_EINVALIDVALUE; + + err = + rsbac_ta_list_lol_subremove(ta_number, gm_handle, &user, + &group); + /* cleanup empty gm items */ + if (!err + && !rsbac_ta_list_lol_subcount(ta_number, gm_handle, &user) + ) + err = + rsbac_ta_list_lol_remove(ta_number, gm_handle, &user); + + return err; +} + +/* check membership */ +rsbac_boolean_t rsbac_acl_group_member(rsbac_acl_group_id_t group, + rsbac_uid_t user) +{ + return rsbac_ta_list_lol_subexist(0, gm_handle, &user, &group); +} + +/* build rsbac_kmalloc'd array of all group memberships of the given user */ +/* returns number of groups or negative error */ +/* Attention: memory deallocation with rsbac_kfree (if result > 0) must be done by caller! */ +int rsbac_acl_get_user_groups(rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + rsbac_acl_group_id_t ** group_pp, + rsbac_time_t ** ttl_pp) +{ + return rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + gm_handle, + &user, + (void **) group_pp, + ttl_pp); +} + +/* Returns number of members or negative error */ +int rsbac_acl_get_group_members(rsbac_list_ta_number_t ta_number, + rsbac_acl_group_id_t group, + rsbac_uid_t user_array[], + rsbac_time_t ttl_array[], int maxnum) +{ + long desc_count; + long i; + rsbac_uid_t *user_p; + int err = 0; + + if (!group || (maxnum <= 0)) + return -RSBAC_EINVALIDVALUE; + if (!rsbac_ta_list_exist(ta_number, group_handle, &group)) + return -RSBAC_EINVALIDVALUE; + if (!user_array) + return -RSBAC_EINVALIDPOINTER; + + /* traverse group memberships */ + desc_count = + rsbac_ta_list_lol_get_all_desc(ta_number, gm_handle, + (void **) &user_p); + if (desc_count > 0) { + rsbac_time_t ttl; + + for (i = 0; i < desc_count; i++) { + if (!rsbac_ta_list_lol_get_subdata_ttl + (ta_number, gm_handle, &ttl, &user_p[i], + &group, NULL)) { + user_array[err] = user_p[i]; + if (ttl_array) + ttl_array[err] = ttl; + err++; + if (err >= maxnum) + break; + } + } + rsbac_kfree(user_p); + } + return err; +} + +int rsbac_acl_list_all_dev(rsbac_list_ta_number_t ta_number, + struct rsbac_dev_desc_t **id_pp) +{ + if (id_pp) + return rsbac_ta_list_lol_get_all_desc(ta_number, + dev_handle, + (void **) id_pp); + else + return rsbac_ta_list_lol_count(ta_number, dev_handle); +} + +int rsbac_acl_list_all_major_dev(rsbac_list_ta_number_t ta_number, + struct rsbac_dev_desc_t **id_pp) +{ + if (id_pp) { + int count; + + count = + rsbac_ta_list_lol_get_all_desc(ta_number, + dev_major_handle, + (void **) id_pp); + if (count > 0) { + u_int i; + struct rsbac_dev_desc_t *tmp_p; + + tmp_p = *id_pp; + for (i = 0; i < count; i++) + tmp_p[i].type += (D_block_major - D_block); + } + return count; + } else + return rsbac_ta_list_lol_count(ta_number, + dev_major_handle); +} + +int rsbac_acl_list_all_user(rsbac_list_ta_number_t ta_number, + rsbac_uid_t ** id_pp) +{ + if (id_pp) + return rsbac_ta_list_lol_get_all_desc(ta_number, u_handle, + (void **) id_pp); + else + return rsbac_ta_list_lol_count(ta_number, u_handle); +} + +#ifdef CONFIG_RSBAC_ACL_UM_PROT +int rsbac_acl_list_all_group(rsbac_list_ta_number_t ta_number, + rsbac_gid_t ** id_pp) +{ + if (id_pp) + return rsbac_ta_list_lol_get_all_desc(ta_number, g_handle, + (void **) id_pp); + else + return rsbac_ta_list_lol_count(ta_number, g_handle); +} +#endif + +/********************************************/ +/* remove user from all groups and all ACLs */ +int rsbac_acl_remove_user(rsbac_list_ta_number_t ta_number, + rsbac_uid_t user) +{ + u_long i; + struct rsbac_acl_group_entry_t *entry_p; + long desc_count; + struct rsbac_acl_entry_desc_t desc; + + rsbac_ta_list_lol_remove(ta_number, gm_handle, &user); + /* traverse groups for this owner */ + desc_count = + rsbac_ta_list_get_all_data(ta_number, group_handle, + (void **) &entry_p); + if (desc_count > 0) { + for (i = 0; i < desc_count; i++) { + if (entry_p[i].owner == user) { + rsbac_ta_list_remove(ta_number, + group_handle, + &entry_p[i].id); + /* cleanup group memberships */ + rsbac_ta_list_lol_subremove_from_all + (ta_number, gm_handle, &entry_p[i].id); + } + } + rsbac_kfree(entry_p); + } + + desc.subj_type = ACLS_USER; + desc.subj_id = user; + + return rsbac_acl_remove_subject(ta_number, desc); +} diff --git a/rsbac/data_structures/auth_data_structures.c b/rsbac/data_structures/auth_data_structures.c new file mode 100644 index 000000000000..19181d2a6109 --- /dev/null +++ b/rsbac/data_structures/auth_data_structures.c @@ -0,0 +1,4011 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of AUTH data structures */ +/* Author and (c) 1999-2017: Amon Ott */ +/* */ +/* Last modified: 22/Mar/2017 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************** */ +/* Global Variables */ +/************************************************************************** */ + +/* The following global variables are needed for access to AUTH data. */ + +static struct rsbac_auth_device_list_head_t * device_list_head_p; +static spinlock_t device_list_lock; +static struct srcu_struct device_list_srcu; +static struct lock_class_key device_list_lock_class; + +static rsbac_list_handle_t process_handle = NULL; +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER +static rsbac_list_handle_t process_eff_handle = NULL; +static rsbac_list_handle_t process_fs_handle = NULL; +#endif + +#ifdef CONFIG_RSBAC_AUTH_GROUP +static rsbac_list_handle_t process_group_handle = NULL; +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP +static rsbac_list_handle_t process_group_eff_handle = NULL; +static rsbac_list_handle_t process_group_fs_handle = NULL; +#endif +#endif + +#if defined(CONFIG_RSBAC_AUTH_LEARN) +#ifdef CONFIG_RSBAC_AUTH_LEARN_TA +rsbac_list_ta_number_t auth_learn_ta = CONFIG_RSBAC_AUTH_LEARN_TA; +#else +rsbac_list_ta_number_t auth_learn_ta = 0; +#endif +#endif + +static struct kmem_cache * auth_device_item_slab = NULL; + +/**************************************************/ +/* Declarations of external functions */ +/**************************************************/ + +rsbac_boolean_t writable(struct super_block *sb_p); + +/**************************************************/ +/* Declarations of internal functions */ +/**************************************************/ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +static u_int nr_fd_hash_bits = RSBAC_AUTH_NR_CAP_FD_LIST_HASH_BITS; + +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER +static u_int nr_eff_fd_hash_bits = RSBAC_AUTH_NR_CAP_EFF_FD_LIST_HASH_BITS; +static u_int nr_fs_fd_hash_bits = RSBAC_AUTH_NR_CAP_FS_FD_LIST_HASH_BITS; +#endif + +#ifdef CONFIG_RSBAC_AUTH_GROUP +static u_int nr_group_fd_hash_bits = RSBAC_AUTH_NR_CAP_GROUP_FD_LIST_HASH_BITS; + +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP +static u_int nr_group_eff_fd_hash_bits = RSBAC_AUTH_NR_CAP_GROUP_EFF_FD_LIST_HASH_BITS; +static u_int nr_group_fs_fd_hash_bits = RSBAC_AUTH_NR_CAP_GROUP_FS_FD_LIST_HASH_BITS; +#endif +#endif + +static int cap_compare(void *desc1, void *desc2) +{ + struct rsbac_auth_cap_range_t *range1 = desc1; + struct rsbac_auth_cap_range_t *range2 = desc2; + + if (!desc1 || !desc2) + return 0; + if (range1->first < range2->first) + return -1; + if (range1->first > range2->first) + return 1; + if (range1->last < range2->last) + return -1; + if (range1->last > range2->last) + return 1; + return 0; +} + +static int single_cap_compare(void *desc1, void *desc2) +{ + struct rsbac_auth_cap_range_t *range = desc1; + rsbac_uid_t *uid = desc2; + + if (!desc1 || !desc2) + return 0; + if ((*uid < range->first) + || (*uid > range->last) + ) + return 1; + else + return 0; +} + +static int auth_subconv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_auth_cap_range_t *tmp_new_desc = new_desc; + struct rsbac_auth_old_cap_range_t *tmp_old_desc = old_desc; + + tmp_new_desc->first = tmp_old_desc->first; + tmp_new_desc->last = tmp_old_desc->last; + return 0; +} + +static rsbac_list_conv_function_t *auth_get_subconv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_AUTH_FD_OLD_LIST_VERSION: + return auth_subconv; + default: + return NULL; + } +} + +static int auth_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + return 0; +} + +static rsbac_list_conv_function_t *auth_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_AUTH_FD_OLD_LIST_VERSION: + return auth_conv; + default: + return NULL; + } +} + + +/* auth_register_fd_lists() */ +/* register fd ACL lists for device */ + +static int auth_register_fd_lists(struct rsbac_auth_device_list_item_t + *device_p, kdev_t kdev) +{ + int err = 0; + int tmperr; + struct rsbac_list_lol_info_t lol_info; + + if (!device_p) + return -RSBAC_EINVALIDPOINTER; + + lol_info.version = RSBAC_AUTH_FD_LIST_VERSION; + lol_info.key = RSBAC_AUTH_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_old_inode_nr_t); + lol_info.data_size = 0; + lol_info.subdesc_size = + sizeof(struct rsbac_auth_cap_range_t); + lol_info.subdata_size = 0; /* rights */ + lol_info.max_age = 0; + tmperr = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &device_p->handle, + &lol_info, + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + cap_compare, + auth_get_conv, auth_get_subconv, + NULL, NULL, + RSBAC_AUTH_FD_FILENAME, kdev, + nr_fd_hash_bits, + rsbac_list_hash_old_fd, + RSBAC_AUTH_FD_OLD_FILENAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "auth_register_fd_lists(): registering list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_FILENAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + /* register all the AUTH DAC lists of lists */ + lol_info.version = RSBAC_AUTH_FD_EFF_LIST_VERSION; + lol_info.key = RSBAC_AUTH_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_old_inode_nr_t); + lol_info.data_size = 0; + lol_info.subdesc_size = + sizeof(struct rsbac_auth_cap_range_t); + lol_info.subdata_size = 0; /* rights */ + lol_info.max_age = 0; + tmperr = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &device_p->eff_handle, + &lol_info, + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + cap_compare, + auth_get_conv, auth_get_subconv, + NULL, NULL, + RSBAC_AUTH_FD_EFF_FILENAME, kdev, + nr_eff_fd_hash_bits, + rsbac_list_hash_old_fd, + RSBAC_AUTH_FD_OLD_EFF_FILENAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "auth_register_fd_lists(): registering list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_EFF_FILENAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + lol_info.version = RSBAC_AUTH_FD_FS_LIST_VERSION; + lol_info.key = RSBAC_AUTH_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_old_inode_nr_t); + lol_info.data_size = 0; + lol_info.subdesc_size = + sizeof(struct rsbac_auth_cap_range_t); + lol_info.subdata_size = 0; /* rights */ + lol_info.max_age = 0; + tmperr = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &device_p->fs_handle, + &lol_info, + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + cap_compare, + auth_get_conv, auth_get_subconv, + NULL, NULL, + RSBAC_AUTH_FD_FS_FILENAME, kdev, + nr_fs_fd_hash_bits, + rsbac_list_hash_old_fd, + RSBAC_AUTH_FD_OLD_FS_FILENAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "auth_register_fd_lists(): registering list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_FS_FILENAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif + +#ifdef CONFIG_RSBAC_AUTH_GROUP + lol_info.version = RSBAC_AUTH_FD_GROUP_LIST_VERSION; + lol_info.key = RSBAC_AUTH_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_old_inode_nr_t); + lol_info.data_size = 0; + lol_info.subdesc_size = + sizeof(struct rsbac_auth_cap_range_t); + lol_info.subdata_size = 0; /* rights */ + lol_info.max_age = 0; + tmperr = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &device_p->group_handle, + &lol_info, + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + cap_compare, + auth_get_conv, auth_get_subconv, + NULL, NULL, + RSBAC_AUTH_FD_GROUP_FILENAME, kdev, + nr_group_fd_hash_bits, + rsbac_list_hash_old_fd, + RSBAC_AUTH_FD_OLD_GROUP_FILENAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "auth_register_fd_lists(): registering list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_GROUP_FILENAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + lol_info.version = RSBAC_AUTH_FD_GROUP_EFF_LIST_VERSION; + lol_info.key = RSBAC_AUTH_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_old_inode_nr_t); + lol_info.data_size = 0; + lol_info.subdesc_size = + sizeof(struct rsbac_auth_cap_range_t); + lol_info.subdata_size = 0; /* rights */ + lol_info.max_age = 0; + tmperr = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &device_p->group_eff_handle, + &lol_info, + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + cap_compare, + auth_get_conv, auth_get_subconv, + NULL, NULL, + RSBAC_AUTH_FD_GROUP_EFF_FILENAME, kdev, + nr_group_eff_fd_hash_bits, + rsbac_list_hash_old_fd, + RSBAC_AUTH_FD_OLD_GROUP_EFF_FILENAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "auth_register_fd_lists(): registering list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_GROUP_EFF_FILENAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + lol_info.version = RSBAC_AUTH_FD_GROUP_FS_LIST_VERSION; + lol_info.key = RSBAC_AUTH_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_old_inode_nr_t); + lol_info.data_size = 0; + lol_info.subdesc_size = + sizeof(struct rsbac_auth_cap_range_t); + lol_info.subdata_size = 0; /* rights */ + lol_info.max_age = 0; + tmperr = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &device_p->group_fs_handle, + &lol_info, + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + cap_compare, + auth_get_conv, auth_get_subconv, + NULL, NULL, + RSBAC_AUTH_FD_GROUP_FS_FILENAME, kdev, + nr_group_fs_fd_hash_bits, + rsbac_list_hash_old_fd, + RSBAC_AUTH_FD_OLD_GROUP_FS_FILENAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "auth_register_fd_lists(): registering list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_GROUP_FS_FILENAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif +#endif /* AUTH_GROUP */ + + return err; +} + +/* auth_detach_fd_lists() */ +/* detach from fd AUTH lists for device */ + +static int auth_detach_fd_lists(struct rsbac_auth_device_list_item_t + *device_p) +{ + int err = 0; + int tmperr; + + if (!device_p) + return -RSBAC_EINVALIDPOINTER; + + /* detach all the AUTH lists of lists */ + tmperr = rsbac_list_lol_detach(&device_p->handle, + RSBAC_AUTH_LIST_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "auth_detach_fd_lists(): detaching from list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_FILENAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + tmperr = rsbac_list_lol_detach(&device_p->eff_handle, + RSBAC_AUTH_LIST_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "auth_detach_fd_lists(): detaching from list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_EFF_FILENAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + tmperr = rsbac_list_lol_detach(&device_p->fs_handle, + RSBAC_AUTH_LIST_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "auth_detach_fd_lists(): detaching from list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_FS_FILENAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif + +#ifdef CONFIG_RSBAC_AUTH_GROUP + tmperr = rsbac_list_lol_detach(&device_p->group_handle, + RSBAC_AUTH_LIST_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "auth_detach_fd_lists(): detaching from list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_GROUP_FILENAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + tmperr = rsbac_list_lol_detach(&device_p->group_eff_handle, + RSBAC_AUTH_LIST_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "auth_detach_fd_lists(): detaching from list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_GROUP_EFF_FILENAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + tmperr = rsbac_list_lol_detach(&device_p->group_fs_handle, + RSBAC_AUTH_LIST_KEY); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "auth_detach_fd_lists(): detaching from list %s for device %02u:%02u failed with error %s!\n", + RSBAC_AUTH_FD_GROUP_FS_FILENAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } +#endif +#endif /* AUTH_GROUP */ + + return err; +} + +/************************************************************************** */ +/* The lookup functions return NULL, if the item is not found, and a */ +/* pointer to the item otherwise. */ + +/* first the device item lookup */ +static struct rsbac_auth_device_list_item_t *lookup_device(kdev_t kdev) +{ + struct rsbac_auth_device_list_head_t *head_p = srcu_dereference(device_list_head_p, &device_list_srcu); + struct rsbac_auth_device_list_item_t *curr = srcu_dereference(head_p->curr, &device_list_srcu); + + /* if there is no current item or it is not the right one, search... */ + if (!(curr && (RSBAC_MAJOR(curr->id) == RSBAC_MAJOR(kdev)) + && (RSBAC_MINOR(curr->id) == RSBAC_MINOR(kdev)) + ) + ) { + curr = srcu_dereference(head_p->head, &device_list_srcu); + while (curr + && ((RSBAC_MAJOR(curr->id) != RSBAC_MAJOR(kdev)) + || (RSBAC_MINOR(curr->id) != RSBAC_MINOR(kdev)) + ) + ) { + curr = srcu_dereference(curr->next, &device_list_srcu); + } + if (curr) + device_list_head_p->curr = curr; + } + /* it is the current item -> return it */ + return curr; +} + +static struct rsbac_auth_device_list_item_t *lookup_device_locked(kdev_t kdev) +{ + struct rsbac_auth_device_list_item_t *curr = device_list_head_p->curr; + + /* if there is no current item or it is not the right one, search... */ + if (!(curr && (RSBAC_MAJOR(curr->id) == RSBAC_MAJOR(kdev)) + && (RSBAC_MINOR(curr->id) == RSBAC_MINOR(kdev)) + ) + ) { + curr = device_list_head_p->head; + while (curr + && ((RSBAC_MAJOR(curr->id) != RSBAC_MAJOR(kdev)) + || (RSBAC_MINOR(curr->id) != RSBAC_MINOR(kdev)) + ) + ) { + curr = curr->next; + } + if (curr) + device_list_head_p->curr = curr; + } + /* it is the current item -> return it */ + return curr; +} + +/************************************************************************** */ +/* The add_item() functions add an item to the list, set head.curr to it, */ +/* and return a pointer to the item. */ +/* These functions will NOT check, if there is already an item under the */ +/* same ID! If this happens, the lookup functions will return the old item! */ +/* All list manipulation is protected by rw-spinlocks to prevent inconsistency */ +/* and undefined behaviour in other concurrent functions. */ + +/* Create a device item without adding to list. No locking needed. */ +static struct rsbac_auth_device_list_item_t +*create_device_item(kdev_t kdev) +{ + struct rsbac_auth_device_list_item_t *new_item_p; + + /* allocate memory for new device, return NULL, if failed */ + if (!(new_item_p = rsbac_smalloc_clear_unlocked(auth_device_item_slab))) + return NULL; + + new_item_p->id = kdev; + new_item_p->mount_count = 1; + return new_item_p; +} + +/* Add an existing device item to list. Locking needed. */ +static struct rsbac_auth_device_list_item_t +*add_device_item(struct rsbac_auth_device_list_item_t *device_p) +{ + struct rsbac_auth_device_list_head_t * new_p; + struct rsbac_auth_device_list_head_t * old_p; + + if (!device_p) + return NULL; + + spin_lock(&device_list_lock); + old_p = device_list_head_p; + new_p = rsbac_kmalloc(sizeof(*new_p)); + *new_p = *old_p; + /* add new device to device list */ + if (!new_p->head) { /* first device */ + new_p->head = device_p; + new_p->tail = device_p; + new_p->curr = device_p; + new_p->count = 1; + device_p->prev = NULL; + device_p->next = NULL; + } else { /* there is another device -> hang to tail */ + device_p->prev = new_p->tail; + device_p->next = NULL; + new_p->tail->next = device_p; + new_p->tail = device_p; + new_p->curr = device_p; + new_p->count++; + } + rcu_assign_pointer(device_list_head_p, new_p); + spin_unlock(&device_list_lock); + synchronize_srcu(&device_list_srcu); + rsbac_kfree(old_p); + return device_p; +} + +/************************************************************************** */ +/* The remove_item() functions remove an item from the list. If this item */ +/* is head, tail or curr, these pointers are set accordingly. */ +/* To speed up removing several subsequent items, curr is set to the next */ +/* item, if possible. */ +/* If the item is not found, nothing is done. */ + +static void clear_device_item(struct rsbac_auth_device_list_item_t *item_p) +{ + if (!item_p) + return; + + auth_detach_fd_lists(item_p); + rsbac_sfree(auth_device_item_slab, item_p); +} + +static void remove_device_item(kdev_t kdev) +{ + struct rsbac_auth_device_list_item_t *item_p; + struct rsbac_auth_device_list_head_t * new_p; + struct rsbac_auth_device_list_head_t * old_p; + + old_p = device_list_head_p; + new_p = rsbac_kmalloc(sizeof(*new_p)); + *new_p = *old_p; + /* first we must locate the item. */ + if ((item_p = lookup_device_locked(kdev))) { /* ok, item was found */ + if (new_p->head == item_p) { /* item is head */ + if (new_p->tail == item_p) { /* item is head and tail = only item -> list will be empty */ + new_p->head = NULL; + new_p->tail = NULL; + } else { /* item is head, but not tail -> next item becomes head */ + item_p->next->prev = NULL; + new_p->head = item_p->next; + } + } else { /* item is not head */ + if (new_p->tail == item_p) { /*item is not head, but tail -> previous item becomes tail */ + item_p->prev->next = NULL; + new_p->tail = item_p->prev; + } else { /* item is neither head nor tail -> item is cut out */ + item_p->prev->next = item_p->next; + item_p->next->prev = item_p->prev; + } + } + + /* curr is no longer valid -> reset. */ + new_p->curr = NULL; + /* adjust counter */ + new_p->count--; + rcu_assign_pointer(device_list_head_p, new_p); + spin_unlock(&device_list_lock); + synchronize_srcu(&device_list_srcu); + rsbac_kfree(old_p); + + /* now we can remove the item from memory. This means cleaning up */ + /* everything below. */ + clear_device_item(item_p); + } /* end of if: item was found */ + else + spin_unlock(&device_list_lock); +} + +/************************************************************************** */ +/* The copy_fp_cap_set_item() function copies a file cap set to a process */ +/* cap set */ + +static int copy_fp_cap_set_item(struct rsbac_auth_device_list_item_t + *device_p, rsbac_auth_file_t file, + rsbac_pid_t pid) +{ + struct rsbac_auth_cap_range_t *cap_item_p; + rsbac_time_t *ttl_p; + int i; + long count; + enum rsbac_target_t target = T_FILE; + union rsbac_target_id_t tid; + rsbac_old_inode_nr_t inode_nr = file.inode; + + rsbac_list_lol_remove(process_handle, &pid); + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->handle, + &inode_nr, + (void **) &cap_item_p, + &ttl_p); + if (!count || (count == -RSBAC_ENOTFOUND) + ) { + tid.file = file; + if (!rsbac_get_parent(target, tid, &target, &tid)) { + inode_nr = tid.file.inode; + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->handle, + &inode_nr, + (void **) &cap_item_p, + &ttl_p); + } + } + if (count > 0) { + for (i = 0; i < count; i++) { + rsbac_list_lol_subadd_ttl(process_handle, + ttl_p[i], + &pid, + &cap_item_p[i], NULL); + } + rsbac_kfree(cap_item_p); + rsbac_kfree(ttl_p); + } else { + if ((count < 0) + && (count != -RSBAC_ENOTFOUND) + ) + return count; + } + +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + rsbac_list_lol_remove(process_eff_handle, &pid); + inode_nr = file.inode; + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->eff_handle, + &inode_nr, + (void **) &cap_item_p, + &ttl_p); + if (!count || (count == -RSBAC_ENOTFOUND) + ) { + tid.file = file; + if (!rsbac_get_parent(target, tid, &target, &tid)) { + inode_nr = tid.file.inode; + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->eff_handle, + &inode_nr, + (void **) + &cap_item_p, + &ttl_p); + } + } + if (count > 0) { + for (i = 0; i < count; i++) { + rsbac_list_lol_subadd_ttl(process_eff_handle, + ttl_p[i], + &pid, + &cap_item_p[i], NULL); + } + rsbac_kfree(cap_item_p); + rsbac_kfree(ttl_p); + } else { + if ((count < 0) + && (count != -RSBAC_ENOTFOUND) + ) + return count; + } + rsbac_list_lol_remove(process_fs_handle, &pid); + inode_nr = file.inode; + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->fs_handle, + &inode_nr, + (void **) &cap_item_p, + &ttl_p); + if (!count || (count == -RSBAC_ENOTFOUND) + ) { + tid.file = file; + if (!rsbac_get_parent(target, tid, &target, &tid)) { + inode_nr = tid.file.inode; + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->fs_handle, + &inode_nr, + (void **) + &cap_item_p, + &ttl_p); + } + } + if (count > 0) { + for (i = 0; i < count; i++) { + rsbac_list_lol_subadd_ttl(process_fs_handle, + ttl_p[i], + &pid, + &cap_item_p[i], NULL); + } + rsbac_kfree(cap_item_p); + rsbac_kfree(ttl_p); + } else { + if ((count < 0) + && (count != -RSBAC_ENOTFOUND) + ) + return count; + } +#endif + +#ifdef CONFIG_RSBAC_AUTH_GROUP + rsbac_list_lol_remove(process_group_handle, &pid); + inode_nr = file.inode; + count = rsbac_list_lol_get_all_subdesc_ttl(device_p-> + group_handle, + &inode_nr, + (void **) &cap_item_p, + &ttl_p); + if (!count || (count == -RSBAC_ENOTFOUND) + ) { + tid.file = file; + if (!rsbac_get_parent(target, tid, &target, &tid)) { + inode_nr = tid.file.inode; + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->group_handle, + &inode_nr, + (void **) + &cap_item_p, + &ttl_p); + } + } + if (count > 0) { + for (i = 0; i < count; i++) { + rsbac_list_lol_subadd_ttl(process_group_handle, + ttl_p[i], + &pid, + &cap_item_p[i], NULL); + } + rsbac_kfree(cap_item_p); + rsbac_kfree(ttl_p); + } else { + if ((count < 0) + && (count != -RSBAC_ENOTFOUND) + ) + return count; + } + +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + rsbac_list_lol_remove(process_group_eff_handle, &pid); + inode_nr = file.inode; + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->group_eff_handle, + &inode_nr, + (void **) &cap_item_p, + &ttl_p); + if (!count || (count == -RSBAC_ENOTFOUND) + ) { + tid.file = file; + if (!rsbac_get_parent(target, tid, &target, &tid)) { + inode_nr = tid.file.inode; + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->group_eff_handle, + &inode_nr, + (void **) + &cap_item_p, + &ttl_p); + } + } + if (count > 0) { + for (i = 0; i < count; i++) { + rsbac_list_lol_subadd_ttl(process_group_eff_handle, + ttl_p[i], + &pid, + &cap_item_p[i], NULL); + } + rsbac_kfree(cap_item_p); + rsbac_kfree(ttl_p); + } else { + if ((count < 0) + && (count != -RSBAC_ENOTFOUND) + ) + return count; + } + rsbac_list_lol_remove(process_group_fs_handle, &pid); + inode_nr = file.inode; + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->group_fs_handle, + &inode_nr, + (void **) &cap_item_p, + &ttl_p); + if (!count || (count == -RSBAC_ENOTFOUND) + ) { + tid.file = file; + if (!rsbac_get_parent(target, tid, &target, &tid)) { + inode_nr = tid.file.inode; + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->group_fs_handle, + &inode_nr, + (void **) + &cap_item_p, + &ttl_p); + } + } + if (count > 0) { + for (i = 0; i < count; i++) { + rsbac_list_lol_subadd_ttl(process_group_fs_handle, + ttl_p[i], + &pid, + &cap_item_p[i], NULL); + } + rsbac_kfree(cap_item_p); + rsbac_kfree(ttl_p); + } else { + if ((count < 0) + && (count != -RSBAC_ENOTFOUND) + ) + return count; + } +#endif +#endif /* AUTH_GROUP */ + + return 0; +} /* end of copy_fp_cap_set_item() */ + +/************************************************************************** */ +/* The copy_pp_cap_set_item() function copies a process cap set to another */ + +static int copy_pp_cap_set_item_handle(rsbac_list_handle_t handle, + rsbac_pid_t old_pid, + rsbac_pid_t new_pid) +{ + struct rsbac_auth_cap_range_t *cap_item_p; + rsbac_time_t *ttl_p; + int i; + long count; + + rsbac_list_lol_remove(handle, &new_pid); + count = rsbac_list_lol_get_all_subdesc_ttl(handle, + &old_pid, + (void **) &cap_item_p, + &ttl_p); + if (count > 0) { + for (i = 0; i < count; i++) { + rsbac_list_lol_subadd_ttl(handle, + ttl_p[i], + &new_pid, + &cap_item_p[i], NULL); + } + rsbac_kfree(cap_item_p); + rsbac_kfree(ttl_p); + } else { + if (count < 0) + return count; + } + return 0; +} + +static int copy_pp_cap_set_item(rsbac_pid_t old_pid, rsbac_pid_t new_pid) +{ + int res; + + res = + copy_pp_cap_set_item_handle(process_handle, old_pid, new_pid); + +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + if (res) + return res; + res = + copy_pp_cap_set_item_handle(process_eff_handle, old_pid, + new_pid); + if (res) + return res; + res = + copy_pp_cap_set_item_handle(process_fs_handle, old_pid, + new_pid); +#endif + +#ifdef CONFIG_RSBAC_AUTH_GROUP + res = + copy_pp_cap_set_item_handle(process_group_handle, old_pid, + new_pid); + +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + if (res) + return res; + res = + copy_pp_cap_set_item_handle(process_group_eff_handle, old_pid, + new_pid); + if (res) + return res; + res = + copy_pp_cap_set_item_handle(process_group_fs_handle, old_pid, + new_pid); +#endif +#endif + + return res; +} /* end of copy_pp_cap_set_item() */ + +/************************************************* */ +/* proc functions */ +/************************************************* */ + +#if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS) +static int +auth_devices_proc_show(struct seq_file *m, void *v) +{ + struct rsbac_auth_device_list_head_t *head_p; + struct rsbac_auth_device_list_item_t *device_p; + int srcu_idx; + + if (!rsbac_is_initialized()) + return -ENOSYS; + + seq_printf(m, + "%u RSBAC AUTH Devices\n--------------------\n", + device_list_head_p->count); + + srcu_idx = srcu_read_lock(&device_list_srcu); + head_p = srcu_dereference(device_list_head_p, &device_list_srcu); + for (device_p = srcu_dereference(head_p->head, &device_list_srcu); device_p; + device_p = srcu_dereference(device_p->next, &device_list_srcu)) { + seq_printf(m, + "%02u:%02u with mount_count = %u\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + device_p->mount_count); + } + + srcu_read_unlock(&device_list_srcu, srcu_idx); + + return 0; +} + +static int auth_devices_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, auth_devices_proc_show, NULL); +} + +static const struct file_operations auth_devices_proc_fops = { + .owner = THIS_MODULE, + .open = auth_devices_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *auth_devices; + +static int +stats_auth_proc_show(struct seq_file *m, void *v) +{ + u_int cap_set_count = 0; + u_int member_count = 0; + struct rsbac_auth_device_list_head_t *head_p; + struct rsbac_auth_device_list_item_t *device_p; + int srcu_idx; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "stats_auth_proc_info(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(aef_auth, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, "AUTH Status\n-----------\n"); + + seq_printf(m, + "%lu process cap set items, sum of %lu members\n", + rsbac_list_lol_count(process_handle), + rsbac_list_lol_all_subcount(process_handle)); +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + seq_printf(m, + "%lu process eff cap set items, sum of %lu members\n", + rsbac_list_lol_count(process_eff_handle), + rsbac_list_lol_all_subcount(process_eff_handle)); + seq_printf(m, + "%lu process fs cap set items, sum of %lu members\n", + rsbac_list_lol_count(process_fs_handle), + rsbac_list_lol_all_subcount(process_fs_handle)); +#endif + +#ifdef CONFIG_RSBAC_AUTH_GROUP + seq_printf(m, + "%lu process group cap set items, sum of %lu members\n", + rsbac_list_lol_count(process_group_handle), + rsbac_list_lol_all_subcount(process_group_handle)); +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + seq_printf(m, + "%lu process group eff cap set items, sum of %lu members\n", + rsbac_list_lol_count(process_group_eff_handle), + rsbac_list_lol_all_subcount(process_group_eff_handle)); + seq_printf(m, + "%lu process group fs cap set items, sum of %lu members\n", + rsbac_list_lol_count(process_group_fs_handle), + rsbac_list_lol_all_subcount(process_group_fs_handle)); +#endif +#endif /* AUTH_GROUP */ + + srcu_idx = srcu_read_lock(&device_list_srcu); + head_p = srcu_dereference(device_list_head_p, &device_list_srcu); + device_p = srcu_dereference(head_p->head, &device_list_srcu); + while (device_p) { + /* reset counters */ + cap_set_count = rsbac_list_lol_count(device_p->handle); + member_count = rsbac_list_lol_all_subcount(device_p->handle); + seq_printf(m, + "device %02u:%02u has %u file cap set items, sum of %u members\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), cap_set_count, + member_count); +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + cap_set_count = rsbac_list_lol_count(device_p->eff_handle); + member_count = rsbac_list_lol_all_subcount(device_p->eff_handle); + seq_printf(m, + "device %02u:%02u has %u file eff cap set items, sum of %u members\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), cap_set_count, + member_count); + cap_set_count = rsbac_list_lol_count(device_p->fs_handle); + member_count = rsbac_list_lol_all_subcount(device_p->fs_handle); + seq_printf(m, + "device %02u:%02u has %u file fs cap set items, sum of %u members\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), cap_set_count, + member_count); +#endif + +#ifdef CONFIG_RSBAC_AUTH_GROUP + cap_set_count = rsbac_list_lol_count(device_p->group_handle); + member_count = rsbac_list_lol_all_subcount(device_p->group_handle); + seq_printf(m, + "device %02u:%02u has %u file group cap set items, sum of %u members\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), cap_set_count, + member_count); +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + cap_set_count = rsbac_list_lol_count(device_p->group_eff_handle); + member_count = rsbac_list_lol_all_subcount(device_p->group_eff_handle); + seq_printf(m, + "device %02u:%02u has %u file group eff cap set items, sum of %u members\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), cap_set_count, + member_count); + cap_set_count = rsbac_list_lol_count(device_p->group_fs_handle); + member_count = rsbac_list_lol_all_subcount(device_p->group_fs_handle); + seq_printf(m, + "device %02u:%02u has %u file group fs cap set items, sum of %u members\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), cap_set_count, + member_count); +#endif +#endif /* AUTH_GROUP */ + + device_p = srcu_dereference(device_p->next, &device_list_srcu); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + + return 0; +} + +static int stats_auth_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, stats_auth_proc_show, NULL); +} + +static const struct file_operations stats_auth_proc_fops = { + .owner = THIS_MODULE, + .open = stats_auth_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *stats_auth; + +static int +auth_caplist_proc_show(struct seq_file *m, void *v) +{ + u_int count = 0; + u_int member_count = 0; + u_long all_count; + u_long all_member_count; + int i, j; + struct rsbac_auth_device_list_head_t *head_p; + struct rsbac_auth_device_list_item_t *device_p; + rsbac_pid_t *p_list; + rsbac_old_inode_nr_t *f_list; + struct rsbac_auth_cap_range_t *cap_list; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + int srcu_idx; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "auth_caplist_proc_info(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(aef_auth, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, "AUTH Cap Lists\n--------------\n"); + + seq_printf(m, + "Process capabilities:\nset-id count cap-members"); + all_member_count = 0; + count = rsbac_list_lol_get_all_desc(process_handle, + (void **) &p_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc(process_handle, + &p_list[i], + (void **) + &cap_list); + seq_printf(m, "\n %u\t%u\t", pid_vnr(p_list[i]), + member_count); + if (member_count > 0) { + for (j = 0; j < member_count; j++) { + if (cap_list[j].first != + cap_list[j].last) { + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first) + || RSBAC_UID_SET(cap_list[j].last) + ) + seq_printf(m, + "%u/%u:%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_SET(cap_list[j].last), + RSBAC_UID_NUM(cap_list[j].last)); + else +#endif + seq_printf(m, + "%u:%u ", + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].last)); + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first)) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first)); + else +#endif + seq_printf(m, + "%u ", + RSBAC_UID_NUM(cap_list[j].first)); + } + } + rsbac_kfree(cap_list); + all_member_count += member_count; + } + } + rsbac_kfree(p_list); + } + seq_printf(m, + "\n%u process cap set items, sum of %lu members\n", + count, all_member_count); +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + seq_printf(m, + "\nProcess eff capabilities:\nset-id count cap-members"); + + all_member_count = 0; + count = rsbac_list_lol_get_all_desc(process_eff_handle, + (void **) &p_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc + (process_eff_handle, &p_list[i], + (void **) &cap_list); + seq_printf(m, "\n %u\t%u\t", pid_vnr(p_list[i]), + member_count); + if (member_count > 0) { + for (j = 0; j < member_count; j++) { + if (cap_list[j].first != + cap_list[j].last) { + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first) + || RSBAC_UID_SET(cap_list[j].last) + ) + seq_printf(m, + "%u/%u:%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_SET(cap_list[j].last), + RSBAC_UID_NUM(cap_list[j].last)); + else +#endif + seq_printf(m, + "%u:%u ", + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].last)); + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first)) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first)); + else +#endif + seq_printf(m, + "%u ", + RSBAC_UID_NUM(cap_list[j].first)); + } + } + rsbac_kfree(cap_list); + all_member_count += member_count; + } + } + rsbac_kfree(p_list); + } + seq_printf(m, + "\n%u process eff cap set items, sum of %lu members\n", + count, all_member_count); + seq_printf(m, + "\nProcess fs capabilities:\nset-id count cap-members"); + + all_member_count = 0; + count = rsbac_list_lol_get_all_desc(process_fs_handle, + (void **) &p_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc + (process_fs_handle, &p_list[i], + (void **) &cap_list); + seq_printf(m, "\n %u\t%u\t", pid_vnr(p_list[i]), + member_count); + if (member_count > 0) { + for (j = 0; j < member_count; j++) { + if (cap_list[j].first != + cap_list[j].last) { + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first) + || RSBAC_UID_SET(cap_list[j].last) + ) + seq_printf(m, + "%u/%u:%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_SET(cap_list[j].last), + RSBAC_UID_NUM(cap_list[j].last)); + else +#endif + seq_printf(m, + "%u:%u ", + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].last)); + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first)) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first)); + else +#endif + seq_printf(m, + "%u ", + RSBAC_UID_NUM(cap_list[j].first)); + } + } + rsbac_kfree(cap_list); + all_member_count += member_count; + } + } + rsbac_kfree(p_list); + } + seq_printf(m, + "\n\n%u process fs cap set items, sum of %lu members\n", + count, all_member_count); +#endif + +#ifdef CONFIG_RSBAC_AUTH_GROUP + seq_printf(m, + "\nProcess group capabilities:\nset-id count cap-members"); + all_member_count = 0; + count = rsbac_list_lol_get_all_desc(process_group_handle, + (void **) &p_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc + (process_group_handle, &p_list[i], + (void **) &cap_list); + seq_printf(m, "\n %u\t%u\t", pid_vnr(p_list[i]), + member_count); + if (member_count > 0) { + for (j = 0; j < member_count; j++) { + if (cap_list[j].first != + cap_list[j].last) { + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first) + || RSBAC_UID_SET(cap_list[j].last) + ) + seq_printf(m, + "%u/%u:%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_SET(cap_list[j].last), + RSBAC_UID_NUM(cap_list[j].last)); + else +#endif + seq_printf(m, + "%u:%u ", + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].last)); + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first)) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first)); + else +#endif + seq_printf(m, + "%u ", + RSBAC_UID_NUM(cap_list[j].first)); + } + } + rsbac_kfree(cap_list); + all_member_count += member_count; + } + } + rsbac_kfree(p_list); + } + seq_printf(m, + "\n%u process group cap set items, sum of %lu members\n", + count, all_member_count); + +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + seq_printf(m, + "\nProcess group eff capabilities:\nset-id count cap-members"); + all_member_count = 0; + count = rsbac_list_lol_get_all_desc(process_group_eff_handle, + (void **) &p_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc + (process_group_eff_handle, &p_list[i], + (void **) &cap_list); + seq_printf(m, "\n %u\t%u\t", pid_vnr(p_list[i]), + member_count); + if (member_count > 0) { + for (j = 0; j < member_count; j++) { + if (cap_list[j].first != + cap_list[j].last) { + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first) + || RSBAC_UID_SET(cap_list[j].last) + ) + seq_printf(m, + "%u/%u:%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_SET(cap_list[j].last), + RSBAC_UID_NUM(cap_list[j].last)); + else +#endif + seq_printf(m, + "%u:%u ", + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].last)); + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first)) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first)); + else +#endif + seq_printf(m, + "%u ", + RSBAC_UID_NUM(cap_list[j].first)); + } + } + rsbac_kfree(cap_list); + all_member_count += member_count; + } + } + rsbac_kfree(p_list); + } + seq_printf(m, + "\n%u process group eff cap set items, sum of %lu members\n", + count, all_member_count); + seq_printf(m, + "\nProcess group fs capabilities:\nset-id count cap-members"); + + all_member_count = 0; + count = rsbac_list_lol_get_all_desc(process_group_fs_handle, + (void **) &p_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc + (process_group_fs_handle, &p_list[i], + (void **) &cap_list); + seq_printf(m, "\n %u\t%u\t", pid_vnr(p_list[i]), + member_count); + if (member_count > 0) { + for (j = 0; j < member_count; j++) { + if (cap_list[j].first != + cap_list[j].last) { + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first) + || RSBAC_UID_SET(cap_list[j].last) + ) + seq_printf(m, + "%u/%u:%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_SET(cap_list[j].last), + RSBAC_UID_NUM(cap_list[j].last)); + else +#endif + seq_printf(m, + "%u:%u ", + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].last)); + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first)) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first)); + else +#endif + seq_printf(m, + "%u ", + RSBAC_UID_NUM(cap_list[j].first)); + } + } + rsbac_kfree(cap_list); + all_member_count += member_count; + } + } + rsbac_kfree(p_list); + } + seq_printf(m, + "\n\n%u process group fs cap set items, sum of %lu members\n", + count, all_member_count); +#endif +#endif /* AUTH_GROUP */ + + seq_printf(m, + "\nFile capabilities:\nset-id count cap-members"); + + srcu_idx = srcu_read_lock(&device_list_srcu); + head_p = srcu_dereference(device_list_head_p, &device_list_srcu); + device_p = srcu_dereference(head_p->head, &device_list_srcu); + while (device_p) { + /* reset counters */ + all_member_count = 0; + all_count = 0; + count = rsbac_list_lol_get_all_desc(device_p->handle, + (void **) &f_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc + (device_p->handle, + &f_list[i], + (void **) &cap_list); + seq_printf(m, + "\n %u\t%u\t", + f_list[i], + member_count); + if (member_count > 0) { + for (j = 0; + j < member_count; + j++) { + if (cap_list[j]. + first != + cap_list[j]. + last) { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first) + || RSBAC_UID_SET(cap_list[j].last) + ) + seq_printf(m, + "%u/%u:%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_SET(cap_list[j].last), + RSBAC_UID_NUM(cap_list[j].last)); + else +#endif + seq_printf + (m, + "%u:%u ", + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].last)); + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first)) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first)); + else +#endif + seq_printf(m, + "%u ", + RSBAC_UID_NUM(cap_list[j].first)); + } + } + rsbac_kfree(cap_list); + all_member_count += + member_count; + } + } + rsbac_kfree(f_list); + all_count += count; + } + seq_printf(m, + "\ndevice %02u:%02u has %lu file cap set items, sum of %lu members, list is clean\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), all_count, + all_member_count); +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + all_member_count = 0; + all_count = 0; + count = + rsbac_list_lol_get_all_desc(device_p->eff_handle, + (void **) &f_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc + (device_p->eff_handle, + &f_list[i], + (void **) &cap_list); + seq_printf(m, + "\n %u\t%u\t", + f_list[i], + member_count); + if (member_count > 0) { + for (j = 0; + j < member_count; + j++) { + if (cap_list[j].first != + cap_list[j].last) { + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first) + || RSBAC_UID_SET(cap_list[j].last) + ) + seq_printf(m, + "%u/%u:%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_SET(cap_list[j].last), + RSBAC_UID_NUM(cap_list[j].last)); + else +#endif + seq_printf(m, + "%u:%u ", + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].last)); + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first)) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first)); + else +#endif + seq_printf(m, + "%u ", + RSBAC_UID_NUM(cap_list[j].first)); + } + } + rsbac_kfree(cap_list); + all_member_count += + member_count; + } + } + rsbac_kfree(f_list); + all_count += count; + } + seq_printf(m, + "\ndevice %02u:%02u has %lu file eff cap set items, sum of %lu members, list is clean\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), all_count, + all_member_count); + all_member_count = 0; + all_count = 0; + count = + rsbac_list_lol_get_all_desc(device_p-> + fs_handle, + (void **) &f_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc + (device_p->fs_handle, + &f_list[i], + (void **) &cap_list); + seq_printf(m, + "\n %u\t%u\t", + f_list[i], + member_count); + if (member_count > 0) { + for (j = 0; + j < member_count; + j++) { + if (cap_list[j].first != + cap_list[j].last) { + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first) + || RSBAC_UID_SET(cap_list[j].last) + ) + seq_printf(m, + "%u/%u:%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_SET(cap_list[j].last), + RSBAC_UID_NUM(cap_list[j].last)); + else +#endif + seq_printf(m, + "%u:%u ", + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].last)); + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first)) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first)); + else +#endif + seq_printf(m, + "%u ", + RSBAC_UID_NUM(cap_list[j].first)); + } + } + rsbac_kfree(cap_list); + all_member_count += + member_count; + } + } + rsbac_kfree(f_list); + all_count += count; + } + seq_printf(m, + "\ndevice %02u:%02u has %lu file fs cap set items, sum of %lu members, list is clean\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), all_count, + all_member_count); +#endif + +#ifdef CONFIG_RSBAC_AUTH_GROUP + all_member_count = 0; + all_count = 0; + count = + rsbac_list_lol_get_all_desc(device_p-> + group_handle, + (void **) &f_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc + (device_p->group_handle, + &f_list[i], + (void **) &cap_list); + seq_printf(m, + "\n %u\t%u\t", + f_list[i], + member_count); + if (member_count > 0) { + for (j = 0; + j < member_count; + j++) { + if (cap_list[j].first != + cap_list[j].last) { + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first) + || RSBAC_UID_SET(cap_list[j].last) + ) + seq_printf(m, + "%u/%u:%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_SET(cap_list[j].last), + RSBAC_UID_NUM(cap_list[j].last)); + else +#endif + seq_printf(m, + "%u:%u ", + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].last)); + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first)) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first)); + else +#endif + seq_printf(m, + "%u ", + RSBAC_UID_NUM(cap_list[j].first)); + } + } + rsbac_kfree(cap_list); + all_member_count += + member_count; + } + } + rsbac_kfree(f_list); + all_count += count; + } + seq_printf(m, + "\ndevice %02u:%02u has %lu file group cap set items, sum of %lu members, list is clean\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), all_count, + all_member_count); +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + all_member_count = 0; + all_count = 0; + count = rsbac_list_lol_get_all_desc(device_p-> + group_eff_handle, + (void **) &f_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc + (device_p->group_eff_handle, + &f_list[i], + (void **) &cap_list); + seq_printf(m, + "\n %u\t%u\t", + f_list[i], + member_count); + if (member_count > 0) { + for (j = 0; + j < member_count; + j++) { + if (cap_list[j].first != + cap_list[j].last) { + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first) + || RSBAC_UID_SET(cap_list[j].last) + ) + seq_printf(m, + "%u/%u:%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_SET(cap_list[j].last), + RSBAC_UID_NUM(cap_list[j].last)); + else +#endif + seq_printf(m, + "%u:%u ", + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].last)); + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first)) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first)); + else +#endif + seq_printf(m, + "%u ", + RSBAC_UID_NUM(cap_list[j].first)); + } + } + rsbac_kfree(cap_list); + all_member_count += + member_count; + } + } + rsbac_kfree(f_list); + all_count += count; + } + seq_printf(m, + "\ndevice %02u:%02u has %lu file group eff cap set items, sum of %lu members, list is clean\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), all_count, + all_member_count); + all_member_count = 0; + all_count = 0; + count = rsbac_list_lol_get_all_desc(device_p-> + group_fs_handle, + (void **) &f_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc + (device_p->group_fs_handle, + &f_list[i], + (void **) &cap_list); + seq_printf(m, + "\n %u\t%u\t", + f_list[i], + member_count); + if (member_count > 0) { + for (j = 0; + j < member_count; + j++) { + if (cap_list[j].first != + cap_list[j].last) { + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first) + || RSBAC_UID_SET(cap_list[j].last) + ) + seq_printf(m, + "%u/%u:%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_SET(cap_list[j].last), + RSBAC_UID_NUM(cap_list[j].last)); + else +#endif + seq_printf(m, + "%u:%u ", + RSBAC_UID_NUM(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].last)); + } else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_list[j].first)) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(cap_list[j].first), + RSBAC_UID_NUM(cap_list[j].first)); + else +#endif + seq_printf(m, + "%u ", + RSBAC_UID_NUM(cap_list[j].first)); + } + } + rsbac_kfree(cap_list); + all_member_count += + member_count; + } + } + rsbac_kfree(f_list); + all_count += count; + } + seq_printf(m, + "\ndevice %02u:%02u has %lu file group fs cap set items, sum of %lu members, list is clean\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), all_count, + all_member_count); +#endif +#endif /* AUTH_GROUP */ + + device_p = srcu_dereference(device_p->next, &device_list_srcu); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + + return 0; +} + +static int auth_caplist_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, auth_caplist_proc_show, NULL); +} + +static const struct file_operations auth_caplist_proc_fops = { + .owner = THIS_MODULE, + .open = auth_caplist_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *auth_caplist; +#endif /* CONFIG_PROC_FS && CONFIG_RSBAC_PROC */ + +/************************************************* */ +/* Init functions */ +/************************************************* */ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac/error.h. */ + +/************************************************************************** */ +/* Initialization of all AUTH data structures. After this call, all AUTH */ +/* data is kept in memory for performance reasons, but is written to disk */ +/* on every change. */ + +/* Because there can be no access to aci data structures before init, */ +/* rsbac_init_auth() will initialize all rw-spinlocks to unlocked. */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_init_auth(void) +#else +int __init rsbac_init_auth(void) +#endif +{ + int err = 0; + struct rsbac_auth_device_list_item_t *device_p = NULL; + struct rsbac_list_lol_info_t lol_info; + + if (rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_init_auth(): RSBAC already initialized\n"); + return -RSBAC_EREINIT; + } + + rsbac_printk(KERN_INFO "rsbac_init_auth(): Initializing RSBAC: AUTH subsystem\n"); + + lol_info.version = RSBAC_AUTH_P_LIST_VERSION; + lol_info.key = RSBAC_AUTH_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_pid_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(struct rsbac_auth_cap_range_t); + lol_info.subdata_size = 0; + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &process_handle, + &lol_info, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + cap_compare, + NULL, + NULL, + NULL, + NULL, + RSBAC_AUTH_P_LIST_NAME, + RSBAC_AUTO_DEV, + RSBAC_LIST_MIN_MAX_HASH_BITS, + rsbac_list_hash_pid, + NULL); + if (err) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_auth(): Registering AUTH process cap list failed with error %s\n", + get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + lol_info.version = RSBAC_AUTH_P_LIST_VERSION; + lol_info.key = RSBAC_AUTH_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_pid_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(struct rsbac_auth_cap_range_t); + lol_info.subdata_size = 0; + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &process_eff_handle, + &lol_info, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + cap_compare, + NULL, + NULL, + NULL, + NULL, + RSBAC_AUTH_P_EFF_LIST_NAME, + RSBAC_AUTO_DEV, + RSBAC_LIST_MIN_MAX_HASH_BITS, + rsbac_list_hash_pid, + NULL); + if (err) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_auth(): Registering AUTH process eff cap list failed with error %s\n", + get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } + lol_info.version = RSBAC_AUTH_P_LIST_VERSION; + lol_info.key = RSBAC_AUTH_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_pid_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(struct rsbac_auth_cap_range_t); + lol_info.subdata_size = 0; + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &process_fs_handle, + &lol_info, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + cap_compare, + NULL, + NULL, + NULL, + NULL, + RSBAC_AUTH_P_FS_LIST_NAME, + RSBAC_AUTO_DEV, + RSBAC_LIST_MIN_MAX_HASH_BITS, + rsbac_list_hash_pid, + NULL); + if (err) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_auth(): Registering AUTH process fs cap list failed with error %s\n", + get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } +#endif + +#ifdef CONFIG_RSBAC_AUTH_GROUP + lol_info.version = RSBAC_AUTH_P_LIST_VERSION; + lol_info.key = RSBAC_AUTH_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_pid_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(struct rsbac_auth_cap_range_t); + lol_info.subdata_size = 0; + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &process_group_handle, + &lol_info, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + cap_compare, + NULL, + NULL, + NULL, + NULL, + RSBAC_AUTH_P_GROUP_LIST_NAME, + RSBAC_AUTO_DEV, + RSBAC_LIST_MIN_MAX_HASH_BITS, + rsbac_list_hash_pid, + NULL); + if (err) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_auth(): Registering AUTH process group cap list failed with error %s\n", + get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + lol_info.version = RSBAC_AUTH_P_LIST_VERSION; + lol_info.key = RSBAC_AUTH_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_pid_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(struct rsbac_auth_cap_range_t); + lol_info.subdata_size = 0; + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &process_group_eff_handle, + &lol_info, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + cap_compare, + NULL, + NULL, + NULL, + NULL, + RSBAC_AUTH_P_GROUP_EFF_LIST_NAME, + RSBAC_AUTO_DEV, + RSBAC_LIST_MIN_MAX_HASH_BITS, + rsbac_list_hash_pid, + NULL); + if (err) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_auth(): Registering AUTH process group eff cap list failed with error %s\n", + get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } + lol_info.version = RSBAC_AUTH_P_LIST_VERSION; + lol_info.key = RSBAC_AUTH_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_pid_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(struct rsbac_auth_cap_range_t); + lol_info.subdata_size = 0; + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &process_group_fs_handle, + &lol_info, + RSBAC_LIST_DEF_DATA | RSBAC_LIST_AUTO_HASH_RESIZE | RSBAC_LIST_OWN_SLAB, + NULL, + cap_compare, + NULL, + NULL, + NULL, + NULL, + RSBAC_AUTH_P_GROUP_FS_LIST_NAME, + RSBAC_AUTO_DEV, + RSBAC_LIST_MIN_MAX_HASH_BITS, + rsbac_list_hash_pid, + NULL); + if (err) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_auth(): Registering AUTH process group fs cap list failed with error %s\n", + get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } +#endif +#endif /* AUTH_GROUP */ + + auth_device_item_slab = rsbac_slab_create_rcu("rsbac_auth_device_item", + sizeof(struct rsbac_auth_device_list_item_t)); + + /* Init FD lists */ + device_list_head_p = kmalloc(sizeof(*device_list_head_p), GFP_KERNEL); + if (!device_list_head_p) { + rsbac_printk(KERN_WARNING + "rsbac_init_auth(): Failed to allocate device_list_head\n"); + return -ENOMEM; + } + spin_lock_init(&device_list_lock); + init_srcu_struct(&device_list_srcu); + lockdep_set_class(&device_list_lock, &device_list_lock_class); + device_list_head_p->head = NULL; + device_list_head_p->tail = NULL; + device_list_head_p->curr = NULL; + device_list_head_p->count = 0; + + /* read all data */ + rsbac_pr_debug(ds_auth, "rsbac_init_auth(): Registering FD lists\n"); + device_p = create_device_item(rsbac_root_dev); + if (!device_p) { + rsbac_printk(KERN_CRIT + "rsbac_init_auth(): Could not add device!\n"); + return -RSBAC_ECOULDNOTADDDEVICE; + } + if ((err = auth_register_fd_lists(device_p, rsbac_root_dev))) { + char tmp[RSBAC_MAXNAMELEN]; + + rsbac_printk(KERN_WARNING "rsbac_init_auth(): File/Dir cap set registration failed for dev %02u:%02u, err %s!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev), + get_error_name(tmp, err)); + } + device_p = add_device_item(device_p); + if (!device_p) { + rsbac_printk(KERN_CRIT + "rsbac_init_auth(): Could not add device!\n"); + return -RSBAC_ECOULDNOTADDDEVICE; + } +#if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS) + auth_devices = proc_create("auth_devices", + S_IFREG | S_IRUGO, + proc_rsbac_root_p, + &auth_devices_proc_fops); + stats_auth = proc_create("stats_auth", + S_IFREG | S_IRUGO, + proc_rsbac_root_p, + &stats_auth_proc_fops); + auth_caplist = proc_create("auth_caplist", + S_IFREG | S_IRUGO, + proc_rsbac_root_p, + &auth_caplist_proc_fops); +#endif + + rsbac_pr_debug(ds_auth, "Ready.\n"); + return err; +} + +int rsbac_mount_auth(kdev_t kdev) +{ + int err = 0; + struct rsbac_auth_device_list_item_t *device_p; + struct rsbac_auth_device_list_item_t *new_device_p; + int srcu_idx; + + rsbac_pr_debug(ds_auth, "mounting device %02u:%02u\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(kdev); + /* repeated mount? */ + if (device_p) { + rsbac_printk(KERN_WARNING "rsbac_mount_auth: repeated mount %u of device %02u:%02u\n", + device_p->mount_count, RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev)); + device_p->mount_count++; + srcu_read_unlock(&device_list_srcu, srcu_idx); + return 0; + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + + new_device_p = create_device_item(kdev); + if (!new_device_p) + return -RSBAC_ECOULDNOTADDDEVICE; + + /* register lists */ + if ((err = auth_register_fd_lists(new_device_p, kdev))) { + char tmp[RSBAC_MAXNAMELEN]; + + rsbac_printk(KERN_WARNING "rsbac_mount_auth(): File/Dir ACL registration failed for dev %02u:%02u, err %s!\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev), + get_error_name(tmp, err)); + } + + srcu_idx = srcu_read_lock(&device_list_srcu); + /* make sure to only add, if this device item has not been added in the meantime */ + device_p = lookup_device(kdev); + if (device_p) { + rsbac_printk(KERN_WARNING "rsbac_mount_auth(): mount race for device %02u:%02u detected!\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + device_p->mount_count++; + srcu_read_unlock(&device_list_srcu, srcu_idx); + clear_device_item(new_device_p); + } else { + srcu_read_unlock(&device_list_srcu, srcu_idx); + device_p = add_device_item(new_device_p); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_mount_auth: adding device %02u:%02u failed!\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + clear_device_item(new_device_p); + err = -RSBAC_ECOULDNOTADDDEVICE; + } + } + return err; +} + +/* When umounting a device, its file cap set list must be removed. */ + +int rsbac_umount_auth(kdev_t kdev) +{ + struct rsbac_auth_device_list_item_t *device_p; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_umount(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(ds_auth, "umounting device %02u:%02u\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + /* sync of attribute lists was done in rsbac_umount */ + spin_lock(&device_list_lock); + device_p = lookup_device_locked(kdev); + if (device_p) { + if (device_p->mount_count == 1) + remove_device_item(kdev); + else { + if (device_p->mount_count > 1) { + device_p->mount_count--; + spin_unlock(&device_list_lock); + } else { + spin_unlock(&device_list_lock); + rsbac_printk(KERN_WARNING "rsbac_mount_auth: device %02u:%02u has mount_count < 1!\n", + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev)); + } + } + } + else + spin_unlock(&device_list_lock); + return 0; +} + +/***************************************************/ +/* We also need some status information... */ + +int rsbac_stats_auth(void) +{ + u_int cap_set_count = 0; + u_int member_count = 0; + struct rsbac_auth_device_list_head_t *head_p; + struct rsbac_auth_device_list_item_t *device_p; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + int srcu_idx; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_stats_auth(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(aef_auth, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + rsbac_printk(KERN_INFO "AUTH Status\n-----------\n"); + + rsbac_printk(KERN_INFO "%lu process cap set items, sum of %lu members\n", + rsbac_list_lol_count(process_handle), + rsbac_list_lol_all_subcount(process_handle)); + + srcu_idx = srcu_read_lock(&device_list_srcu); + head_p = srcu_dereference(device_list_head_p, &device_list_srcu); + device_p = srcu_dereference(head_p->head, &device_list_srcu); + while (device_p) { + /* reset counters */ + cap_set_count = rsbac_list_lol_count(device_p->handle); + member_count = rsbac_list_lol_all_subcount(device_p->handle); + rsbac_printk(KERN_INFO "device %02u:%02u has %u file cap set items, sum of %u members\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), cap_set_count, + member_count); + device_p = srcu_dereference(device_p->next, &device_list_srcu); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + return 0; +} + +/************************************************* */ +/* Access functions */ +/************************************************* */ + +/* All these procedures handle the rw-spinlocks to protect the targets during */ +/* access. */ +/* Trying to access a never created or removed set returns an error! */ + +/* rsbac_auth_add_to_capset */ +/* Add a set member to a set sublist. Set behaviour: also returns success, */ +/* if member was already in set! */ + +int rsbac_auth_add_to_p_capset(rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range, + rsbac_time_t ttl) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_auth_add_to_p_capset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_auth_add_to_p_capset(): called from interrupt!\n"); + } + if (cap_range.first > cap_range.last) + return -RSBAC_EINVALIDVALUE; + switch (cap_type) { + case ACT_real: + return rsbac_ta_list_lol_subadd_ttl(ta_number, + process_handle, ttl, + &pid, &cap_range, + NULL); +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + case ACT_eff: + return rsbac_ta_list_lol_subadd_ttl(ta_number, + process_eff_handle, + ttl, &pid, &cap_range, + NULL); + case ACT_fs: + return rsbac_ta_list_lol_subadd_ttl(ta_number, + process_fs_handle, ttl, + &pid, &cap_range, + NULL); +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + case ACT_group_real: + return rsbac_ta_list_lol_subadd_ttl(ta_number, + process_group_handle, + ttl, &pid, &cap_range, + NULL); +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case ACT_group_eff: + return rsbac_ta_list_lol_subadd_ttl(ta_number, + process_group_eff_handle, + ttl, &pid, &cap_range, + NULL); + case ACT_group_fs: + return rsbac_ta_list_lol_subadd_ttl(ta_number, + process_group_fs_handle, + ttl, &pid, &cap_range, + NULL); +#endif +#endif /* AUTH_GROUP */ + + default: + return -RSBAC_EINVALIDATTR; + } +} + +int rsbac_auth_add_to_f_capset(rsbac_list_ta_number_t ta_number, + rsbac_auth_file_t file, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range, + rsbac_time_t ttl) +{ + int err = 0; + struct rsbac_auth_device_list_item_t *device_p; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr = file.inode; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_auth_add_to_f_capset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_auth_add_to_f_capset(): called from interrupt!\n"); + } + if (cap_range.first > cap_range.last) + return -RSBAC_EINVALIDVALUE; + + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_auth_add_to_f_capset(): invalid device %02u:%02u!\n", + RSBAC_MAJOR(file.device), + RSBAC_MINOR(file.device)); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + + switch (cap_type) { + case ACT_real: + err = rsbac_ta_list_lol_subadd_ttl(ta_number, + device_p->handle, + ttl, &inode_nr, + &cap_range, NULL); + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + case ACT_eff: + err = rsbac_ta_list_lol_subadd_ttl(ta_number, + device_p->eff_handle, + ttl, &inode_nr, + &cap_range, NULL); + break; + case ACT_fs: + err = rsbac_ta_list_lol_subadd_ttl(ta_number, + device_p->fs_handle, + ttl, &inode_nr, + &cap_range, NULL); + break; +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + case ACT_group_real: + err = rsbac_ta_list_lol_subadd_ttl(ta_number, + device_p->group_handle, + ttl, + &inode_nr, &cap_range, + NULL); + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case ACT_group_eff: + err = rsbac_ta_list_lol_subadd_ttl(ta_number, + device_p->group_eff_handle, + ttl, + &inode_nr, &cap_range, + NULL); + break; + case ACT_group_fs: + err = rsbac_ta_list_lol_subadd_ttl(ta_number, + device_p->group_fs_handle, + ttl, + &inode_nr, &cap_range, + NULL); + break; +#endif +#endif /* AUTH_GROUP */ + + default: + err = -RSBAC_EINVALIDATTR; + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; +} + +/* rsbac_auth_remove_from_capset */ +/* Remove a set member from a sublist. Set behaviour: Returns no error, if */ +/* member is not in list. */ + +int rsbac_auth_remove_from_p_capset(rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t + cap_range) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_auth_remove_from_p_capset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_auth_remove_from_p_capset(): called from interrupt!\n"); + } + if (cap_range.first > cap_range.last) + return -RSBAC_EINVALIDVALUE; + switch (cap_type) { + case ACT_real: + return rsbac_ta_list_lol_subremove(ta_number, + process_handle, &pid, + &cap_range); +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + case ACT_eff: + return rsbac_ta_list_lol_subremove(ta_number, + process_eff_handle, + &pid, &cap_range); + case ACT_fs: + return rsbac_ta_list_lol_subremove(ta_number, + process_fs_handle, &pid, + &cap_range); +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + case ACT_group_real: + return rsbac_ta_list_lol_subremove(ta_number, + process_group_handle, + &pid, &cap_range); +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case ACT_group_eff: + return rsbac_ta_list_lol_subremove(ta_number, + process_group_eff_handle, + &pid, &cap_range); + case ACT_group_fs: + return rsbac_ta_list_lol_subremove(ta_number, + process_group_fs_handle, + &pid, &cap_range); +#endif +#endif /* AUTH_GROUP */ + + default: + return -RSBAC_EINVALIDATTR; + } +} + +int rsbac_auth_remove_from_f_capset(rsbac_list_ta_number_t ta_number, + rsbac_auth_file_t file, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t + cap_range) +{ + int err = 0; + struct rsbac_auth_device_list_item_t *device_p; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr = file.inode; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_auth_remove_from_f_capset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_auth_remove_from_f_capset(): called from interrupt!\n"); + } + if (cap_range.first > cap_range.last) + return -RSBAC_EINVALIDVALUE; + + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_auth_remove_from_f_capset(): invalid device %02u:%02u!\n", + RSBAC_MAJOR(file.device), + RSBAC_MINOR(file.device)); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + switch (cap_type) { + case ACT_real: + err = rsbac_ta_list_lol_subremove(ta_number, + device_p->handle, + &inode_nr, &cap_range); + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + case ACT_eff: + err = rsbac_ta_list_lol_subremove(ta_number, + device_p->eff_handle, + &inode_nr, &cap_range); + break; + case ACT_fs: + err = rsbac_ta_list_lol_subremove(ta_number, + device_p->fs_handle, + &inode_nr, &cap_range); + break; +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + case ACT_group_real: + err = rsbac_ta_list_lol_subremove(ta_number, + device_p->group_handle, + &inode_nr, &cap_range); + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case ACT_group_eff: + err = rsbac_ta_list_lol_subremove(ta_number, + device_p->group_eff_handle, + &inode_nr, &cap_range); + break; + case ACT_group_fs: + err = rsbac_ta_list_lol_subremove(ta_number, + device_p->group_fs_handle, + &inode_nr, &cap_range); + break; +#endif +#endif /* AUTH_GROUP */ + + default: + err = -RSBAC_EINVALIDATTR; + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; +} + +/* rsbac_auth_clear_capset */ +/* Remove all set members from a sublist. Set behaviour: Returns no error, */ +/* if list is empty. */ + +int rsbac_auth_clear_p_capset(rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_auth_clear_p_capset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_auth_clear_p_capset(): called from interrupt!\n"); + } + switch (cap_type) { + case ACT_real: + return rsbac_ta_list_lol_remove(ta_number, process_handle, + &pid); +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + case ACT_eff: + return rsbac_ta_list_lol_remove(ta_number, + process_eff_handle, &pid); + case ACT_fs: + return rsbac_ta_list_lol_remove(ta_number, + process_fs_handle, &pid); +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + case ACT_group_real: + return rsbac_ta_list_lol_remove(ta_number, + process_group_handle, + &pid); +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case ACT_group_eff: + return rsbac_ta_list_lol_remove(ta_number, + process_group_eff_handle, + &pid); + case ACT_group_fs: + return rsbac_ta_list_lol_remove(ta_number, + process_group_fs_handle, + &pid); +#endif +#endif /* AUTH_GROUP */ + + default: + return -RSBAC_EINVALIDTARGET; + } +} + +int rsbac_auth_clear_f_capset(rsbac_list_ta_number_t ta_number, + rsbac_auth_file_t file, + enum rsbac_auth_cap_type_t cap_type) +{ + int err = 0; + struct rsbac_auth_device_list_item_t *device_p; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr = file.inode; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_auth_clear_f_capset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_auth_clear_f_capset(): called from interrupt!\n"); + } + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_auth_clear_f_capset(): invalid device %02u:%02u!\n", + RSBAC_MAJOR(file.device), + RSBAC_MINOR(file.device)); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + switch (cap_type) { + case ACT_real: + err = rsbac_ta_list_lol_remove(ta_number, + device_p->handle, + &inode_nr); + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + case ACT_eff: + err = rsbac_ta_list_lol_remove(ta_number, + device_p->eff_handle, + &inode_nr); + break; + case ACT_fs: + err = rsbac_ta_list_lol_remove(ta_number, + device_p->fs_handle, + &inode_nr); + break; +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + case ACT_group_real: + err = rsbac_ta_list_lol_remove(ta_number, + device_p->group_handle, + &inode_nr); + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case ACT_group_eff: + err = rsbac_ta_list_lol_remove(ta_number, + device_p->group_eff_handle, + &inode_nr); + break; + case ACT_group_fs: + err = rsbac_ta_list_lol_remove(ta_number, + device_p-> group_fs_handle, + &inode_nr); + break; +#endif +#endif /* AUTH_GROUP */ + + default: + err = -RSBAC_EINVALIDTARGET; + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; +} + +/* rsbac_auth_capset_member */ +/* Return truth value, whether member is in set */ + +rsbac_boolean_t rsbac_auth_p_capset_member(rsbac_pid_t pid, + enum rsbac_auth_cap_type_t + cap_type, rsbac_uid_t member) +{ + rsbac_boolean_t result; +#if defined(CONFIG_RSBAC_AUTH_LEARN) + int srcu_idx; +#endif + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_auth_p_capset_member(): RSBAC not initialized\n"); + return FALSE; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_auth_p_capset_member(): called from interrupt!\n"); + } + switch (cap_type) { + case ACT_real: + result = rsbac_list_lol_subexist_compare(process_handle, &pid, + &member, + single_cap_compare); +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + /* check for pseudo set "all" */ + if (!result) { + rsbac_uid_t amember; + + amember = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_ALL, member); + result = rsbac_list_lol_subexist_compare(process_handle, + &pid, + &amember, + single_cap_compare); + } +#endif +#if defined(CONFIG_RSBAC_AUTH_LEARN) + if (!result && (RSBAC_UID_NUM(member) <= RSBAC_AUTH_MAX_RANGE_UID) + ) { + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val; + rsbac_boolean_t learn; + + learn = rsbac_auth_learn; + if (!learn) { + tid.process = pid; + /* check learn on process */ + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, A_auth_learn, + &attr_val, FALSE)) + learn = attr_val.auth_learn; + } + if (learn) { + struct rsbac_auth_cap_range_t range; + struct file *file_p; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(member)) + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH capability for uid %u/%u to pid %u(%s) to transaction %u!\n", + RSBAC_UID_SET(member), + RSBAC_UID_NUM(member), + pid_nr(pid), + current->comm, + auth_learn_ta); + else +#endif + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH capability for uid %u to pid %u(%s) to transaction %u!\n", + RSBAC_UID_NUM(member), pid_nr(pid), current->comm, auth_learn_ta); + range.first = member; + range.last = member; +#ifdef CONFIG_RSBAC_AUTH_LEARN_TA + if (!rsbac_list_ta_exist(auth_learn_ta)) + rsbac_list_ta_begin(CONFIG_RSBAC_LIST_TRANS_MAX_TTL, + &auth_learn_ta, + RSBAC_ALL_USERS, + RSBAC_AUTH_LEARN_TA_NAME, + NULL); +#endif + rsbac_ta_list_lol_subadd_ttl(auth_learn_ta, + process_handle, + RSBAC_LIST_TTL_KEEP, + &pid, + &range, + NULL); + + tid.process = pid; + file_p = get_task_exe_file(pid_task(pid, PIDTYPE_PID)); + if (file_p && file_p->f_path.dentry && file_p->f_path.dentry->d_inode) { + struct + rsbac_auth_device_list_item_t + *device_p; + union rsbac_attribute_value_t + attr_val2; + char * target_id_name; + rsbac_old_inode_nr_t inode_nr = file_p->f_path.dentry->d_inode->i_ino; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, + A_auth_start_uid, &attr_val2, + FALSE) + && (range.first == + attr_val2.auth_start_uid) + ) { + range.first = + RSBAC_AUTH_OWNER_F_CAP; + range.last = range.first; + } + tid.file.device = file_p->f_path.dentry->d_sb->s_dev; + tid.file.inode = file_p->f_path.dentry->d_inode->i_ino; + tid.file.dentry_p = file_p->f_path.dentry; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(range.first)) + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH capability for uid %u/%u to FILE %s to transaction %u!\n", + RSBAC_UID_SET(range.first), + RSBAC_UID_NUM(range.first), + get_target_name(NULL, T_FILE, target_id_name, tid), + auth_learn_ta); + else +#endif + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH capability for uid %u to FILE %s to transaction %u!\n", + RSBAC_UID_NUM(range.first), + get_target_name(NULL, T_FILE, target_id_name, tid), + auth_learn_ta); + rsbac_kfree(target_id_name); + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(tid.file.device); + if (device_p) { + rsbac_ta_list_lol_subadd_ttl( + auth_learn_ta, + device_p->handle, + RSBAC_LIST_TTL_KEEP, + &inode_nr, + &range, + NULL); + } else { + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): unknown device %02u:%02u!\n", + MAJOR(tid.file.device), + MINOR(tid.file.device)); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + } + result = TRUE; + } + } +#endif + break; + +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + case ACT_eff: + result = + rsbac_list_lol_subexist_compare(process_eff_handle, + &pid, &member, + single_cap_compare); +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + /* check for pseudo set "all" */ + if (!result) { + rsbac_uid_t amember; + + amember = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_ALL, member); + result = rsbac_list_lol_subexist_compare(process_eff_handle, + &pid, + &amember, + single_cap_compare); + } +#endif + +#if defined(CONFIG_RSBAC_AUTH_LEARN) + if (!result && (RSBAC_UID_NUM(member) <= RSBAC_AUTH_MAX_RANGE_UID) + ) { + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val; + rsbac_boolean_t learn; + + learn = rsbac_auth_learn; + if (!learn) { + tid.process = pid; + /* check learn on process */ + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, A_auth_learn, + &attr_val, FALSE)) + learn = attr_val.auth_learn; + } + if (learn) { + struct rsbac_auth_cap_range_t range; + struct file *file_p; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(member)) + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH eff capability for uid %u/%u to pid %u(%s) to transaction %u!\n", + RSBAC_UID_SET(member), + RSBAC_UID_NUM(member), + pid_nr(pid), + current->comm, + auth_learn_ta); + else +#endif + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH eff capability for uid %u to pid %u(%s) to transaction %u!\n", + RSBAC_UID_NUM(member), pid_nr(pid), current->comm, auth_learn_ta); + range.first = member; + range.last = member; +#ifdef CONFIG_RSBAC_AUTH_LEARN_TA + if (!rsbac_list_ta_exist(auth_learn_ta)) + rsbac_list_ta_begin(CONFIG_RSBAC_LIST_TRANS_MAX_TTL, + &auth_learn_ta, + RSBAC_ALL_USERS, + RSBAC_AUTH_LEARN_TA_NAME, + NULL); +#endif + rsbac_ta_list_lol_subadd_ttl(auth_learn_ta, + process_eff_handle, + RSBAC_LIST_TTL_KEEP, + &pid, + &range, + NULL); + + tid.process = pid; + file_p = get_task_exe_file(pid_task(pid, PIDTYPE_PID)); + if (file_p && file_p->f_path.dentry && file_p->f_path.dentry->d_inode) { + struct + rsbac_auth_device_list_item_t + *device_p; + union rsbac_attribute_value_t + attr_val2; + char * target_id_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, + A_auth_start_uid, &attr_val2, + FALSE) + && (range.first == + attr_val2.auth_start_uid) + ) { + range.first = + RSBAC_AUTH_OWNER_F_CAP; + range.last = range.first; + } else + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, + A_auth_start_euid, + &attr_val2, FALSE) + && (range.first == + attr_val2. + auth_start_euid) + ) { + range.first = + RSBAC_AUTH_DAC_OWNER_F_CAP; + range.last = range.first; + } + tid.file.device = file_p->f_path.dentry->d_sb->s_dev; + tid.file.inode = file_p->f_path.dentry->d_inode->i_ino; + tid.file.dentry_p = file_p->f_path.dentry; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(range.first)) + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH eff capability for uid %u/%u to FILE %s to transaction %u!\n", + RSBAC_UID_SET(range.first), + RSBAC_UID_NUM(range.first), + get_target_name(NULL, T_FILE, target_id_name, tid), + auth_learn_ta); + else +#endif + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH eff capability for uid %u to FILE %s to transaction %u!\n", + RSBAC_UID_NUM(range.first), + get_target_name(NULL, T_FILE, target_id_name, tid), + auth_learn_ta); + rsbac_kfree(target_id_name); + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(tid.file.device); + if (device_p) { + rsbac_ta_list_lol_subadd_ttl( + auth_learn_ta, + device_p->eff_handle, + RSBAC_LIST_TTL_KEEP, + &tid.file.inode, + &range, + NULL); + } else { + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): unknown device %02u:%02u!\n", + MAJOR(tid.file.device), + MINOR(tid.file.device)); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + } + result = TRUE; + } + } +#endif + break; + + case ACT_fs: + result = + rsbac_list_lol_subexist_compare(process_fs_handle, + &pid, &member, + single_cap_compare); +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + /* check for pseudo set "all" */ + if (!result) { + rsbac_uid_t amember; + + amember = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_ALL, member); + result = rsbac_list_lol_subexist_compare(process_fs_handle, + &pid, + &amember, + single_cap_compare); + } +#endif + +#if defined(CONFIG_RSBAC_AUTH_LEARN) + if (!result && (RSBAC_UID_NUM(member) <= RSBAC_AUTH_MAX_RANGE_UID) + ) { + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val; + rsbac_boolean_t learn; + + learn = rsbac_auth_learn; + if (!learn) { + tid.process = pid; + /* check learn on process */ + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, A_auth_learn, + &attr_val, FALSE)) + learn = attr_val.auth_learn; + } + if (learn) { + struct rsbac_auth_cap_range_t range; + struct file *file_p; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(member)) + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH fs capability for uid %u/%u to pid %u(%s) to transaction %u!\n", + RSBAC_UID_SET(member), + RSBAC_UID_NUM(member), + pid_nr(pid), + current->comm, + auth_learn_ta); + else +#endif + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH fs capability for uid %u to pid %u(%s) to transaction %u!\n", + RSBAC_UID_NUM(member), pid_nr(pid), current->comm, auth_learn_ta); + range.first = member; + range.last = member; +#ifdef CONFIG_RSBAC_AUTH_LEARN_TA + if (!rsbac_list_ta_exist(auth_learn_ta)) + rsbac_list_ta_begin(CONFIG_RSBAC_LIST_TRANS_MAX_TTL, + &auth_learn_ta, + RSBAC_ALL_USERS, + RSBAC_AUTH_LEARN_TA_NAME, + NULL); +#endif + rsbac_ta_list_lol_subadd_ttl(auth_learn_ta, + process_fs_handle, + RSBAC_LIST_TTL_KEEP, + &pid, + &range, + NULL); + + tid.process = pid; + file_p = get_task_exe_file(pid_task(pid, PIDTYPE_PID)); + if (file_p && file_p->f_path.dentry && file_p->f_path.dentry->d_inode) { + struct + rsbac_auth_device_list_item_t + *device_p; + union rsbac_attribute_value_t + attr_val2; + char * target_id_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, + A_auth_start_uid, &attr_val2, + FALSE) + && (range.first == + attr_val2.auth_start_uid) + ) { + range.first = + RSBAC_AUTH_OWNER_F_CAP; + range.last = range.first; + } else + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, + A_auth_start_euid, + &attr_val2, FALSE) + && (range.first == + attr_val2. + auth_start_euid) + ) { + range.first = + RSBAC_AUTH_DAC_OWNER_F_CAP; + range.last = range.first; + } + tid.file.device = file_p->f_path.dentry->d_sb->s_dev; + tid.file.inode = file_p->f_path.dentry->d_inode->i_ino; + tid.file.dentry_p = file_p->f_path.dentry; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(range.first)) + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH fs capability for uid %u/%u to FILE %s to transaction %u!\n", + RSBAC_UID_SET(range.first), + RSBAC_UID_NUM(range.first), + get_target_name(NULL, T_FILE, target_id_name, tid), + auth_learn_ta); + else +#endif + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH fs capability for uid %u to FILE %s to transaction %u!\n", + RSBAC_UID_NUM(range.first), + get_target_name(NULL, T_FILE, target_id_name, tid), + auth_learn_ta); + rsbac_kfree(target_id_name); + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(tid.file.device); + if (device_p) { + rsbac_ta_list_lol_subadd_ttl( + auth_learn_ta, + device_p->fs_handle, + RSBAC_LIST_TTL_KEEP, + &tid.file.inode, + &range, + NULL); + } else { + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): unknown device %02u:%02u!\n", + MAJOR(tid.file.device), + MINOR(tid.file.device)); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + } + result = TRUE; + } + } +#endif + break; +#endif /* AUTH_DAC_OWNER */ + +#ifdef CONFIG_RSBAC_AUTH_GROUP + case ACT_group_real: + result = + rsbac_list_lol_subexist_compare(process_group_handle, + &pid, &member, + single_cap_compare); +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + /* check for pseudo set "all" */ + if (!result) { + rsbac_uid_t amember; + + amember = RSBAC_GEN_GID(RSBAC_UM_VIRTUAL_ALL, member); + result = rsbac_list_lol_subexist_compare(process_group_handle, + &pid, + &amember, + single_cap_compare); + } +#endif + +#if defined(CONFIG_RSBAC_AUTH_LEARN) + if (!result && (RSBAC_GID_NUM(member) <= RSBAC_AUTH_MAX_RANGE_GID) + ) { + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val; + rsbac_boolean_t learn; + + learn = rsbac_auth_learn; + if (!learn) { + tid.process = pid; + /* check learn on process */ + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, A_auth_learn, + &attr_val, FALSE)) + learn = attr_val.auth_learn; + } + if (learn) { + struct rsbac_auth_cap_range_t range; + struct file *file_p; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_GID_SET(member)) + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH group capability for gid %u/%u to pid %u(%s) to transaction %u!\n", + RSBAC_GID_SET(member), + RSBAC_GID_NUM(member), + pid_nr(pid), + current->comm, + auth_learn_ta); + else +#endif + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH group capability for gid %u to pid %u(%s) to transaction %u!\n", + RSBAC_GID_NUM(member), pid_nr(pid), current->comm, auth_learn_ta); + range.first = member; + range.last = member; +#ifdef CONFIG_RSBAC_AUTH_LEARN_TA + if (!rsbac_list_ta_exist(auth_learn_ta)) + rsbac_list_ta_begin(CONFIG_RSBAC_LIST_TRANS_MAX_TTL, + &auth_learn_ta, + RSBAC_ALL_USERS, + RSBAC_AUTH_LEARN_TA_NAME, + NULL); +#endif + rsbac_ta_list_lol_subadd_ttl(auth_learn_ta, + process_group_handle, + RSBAC_LIST_TTL_KEEP, + &pid, + &range, + NULL); + + tid.process = pid; + file_p = get_task_exe_file(pid_task(pid, PIDTYPE_PID)); + if (file_p && file_p->f_path.dentry && file_p->f_path.dentry->d_inode) { + struct + rsbac_auth_device_list_item_t + *device_p; + union rsbac_attribute_value_t + attr_val2; + char * target_id_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, + A_auth_start_gid, &attr_val2, + FALSE) + && (range.first == + attr_val2.auth_start_gid) + ) { + range.first = + RSBAC_AUTH_GROUP_F_CAP; + range.last = range.first; + } + tid.file.device = file_p->f_path.dentry->d_sb->s_dev; + tid.file.inode = file_p->f_path.dentry->d_inode->i_ino; + tid.file.dentry_p = file_p->f_path.dentry; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_GID_SET(range.first)) + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH group capability for gid %u/%u to FILE %s to transaction %u!\n", + RSBAC_GID_SET(range.first), + RSBAC_GID_NUM(range.first), + get_target_name(NULL, T_FILE, target_id_name, tid), + auth_learn_ta); + else +#endif + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH group capability for gid %u to FILE %s to transaction %u!\n", + RSBAC_GID_NUM(range.first), + get_target_name(NULL, T_FILE, target_id_name, tid), + auth_learn_ta); + rsbac_kfree(target_id_name); + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(tid.file.device); + if (device_p) { + rsbac_ta_list_lol_subadd_ttl( + auth_learn_ta, + device_p->group_handle, + RSBAC_LIST_TTL_KEEP, + &tid.file.inode, + &range, + NULL); + } else { + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): unknown device %02u:%02u!\n", + MAJOR(tid.file.device), + MINOR(tid.file.device)); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + } + result = TRUE; + } + } +#endif + break; + +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case ACT_group_eff: + result = + rsbac_list_lol_subexist_compare + (process_group_eff_handle, &pid, &member, + single_cap_compare); +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + /* check for pseudo set "all" */ + if (!result) { + rsbac_uid_t amember; + + amember = RSBAC_GEN_GID(RSBAC_UM_VIRTUAL_ALL, member); + result = rsbac_list_lol_subexist_compare(process_group_eff_handle, + &pid, + &amember, + single_cap_compare); + } +#endif + +#if defined(CONFIG_RSBAC_AUTH_LEARN) + if (!result && (RSBAC_GID_NUM(member) <= RSBAC_AUTH_MAX_RANGE_GID) + ) { + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val; + rsbac_boolean_t learn; + + learn = rsbac_auth_learn; + if (!learn) { + tid.process = pid; + /* check learn on process */ + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, A_auth_learn, + &attr_val, FALSE)) + learn = attr_val.auth_learn; + } + if (learn) { + struct rsbac_auth_cap_range_t range; + struct file *file_p; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_GID_SET(member)) + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH group eff capability for gid %u/%u to pid %u(%s) to transaction %u!\n", + RSBAC_GID_SET(member), + RSBAC_GID_NUM(member), + pid_nr(pid), + current->comm, + auth_learn_ta); + else +#endif + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH group eff capability for gid %u to pid %u(%s) to transaction %u!\n", + RSBAC_GID_NUM(member), pid_nr(pid), current->comm, auth_learn_ta); + range.first = member; + range.last = member; +#ifdef CONFIG_RSBAC_AUTH_LEARN_TA + if (!rsbac_list_ta_exist(auth_learn_ta)) + rsbac_list_ta_begin(CONFIG_RSBAC_LIST_TRANS_MAX_TTL, + &auth_learn_ta, + RSBAC_ALL_USERS, + RSBAC_AUTH_LEARN_TA_NAME, + NULL); +#endif + rsbac_ta_list_lol_subadd_ttl(auth_learn_ta, + process_group_eff_handle, + RSBAC_LIST_TTL_KEEP, + &pid, + &range, + NULL); + + tid.process = pid; + file_p = get_task_exe_file(pid_task(pid, PIDTYPE_PID)); + if (file_p && file_p->f_path.dentry && file_p->f_path.dentry->d_inode) { + struct + rsbac_auth_device_list_item_t + *device_p; + union rsbac_attribute_value_t + attr_val2; + char * target_id_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, + A_auth_start_gid, &attr_val2, + FALSE) + && (range.first == + attr_val2.auth_start_gid) + ) { + range.first = + RSBAC_AUTH_GROUP_F_CAP; + range.last = range.first; + } else + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, + A_auth_start_egid, + &attr_val2, FALSE) + && (range.first == + attr_val2. + auth_start_egid) + ) { + range.first = + RSBAC_AUTH_DAC_GROUP_F_CAP; + range.last = range.first; + } + tid.file.device = file_p->f_path.dentry->d_sb->s_dev; + tid.file.inode = file_p->f_path.dentry->d_inode->i_ino; + tid.file.dentry_p = file_p->f_path.dentry; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_GID_SET(range.first)) + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH group eff capability for gid %u/%u to FILE %s to transaction %u!\n", + RSBAC_GID_SET(range.first), + RSBAC_GID_NUM(range.first), + get_target_name(NULL, T_FILE, target_id_name, tid), + auth_learn_ta); + else +#endif + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH group eff capability for gid %u to FILE %s to transaction %u!\n", + RSBAC_GID_NUM(range.first), + get_target_name(NULL, T_FILE, target_id_name, tid), + auth_learn_ta); + rsbac_kfree(target_id_name); + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(tid.file.device); + if (device_p) { + rsbac_ta_list_lol_subadd_ttl( + auth_learn_ta, + device_p->group_eff_handle, + RSBAC_LIST_TTL_KEEP, + &tid.file.inode, + &range, + NULL); + } else { + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): unknown device %02u:%02u!\n", + MAJOR(tid.file.device), + MINOR(tid.file.device)); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + } + result = TRUE; + } + } +#endif + break; + + case ACT_group_fs: + result = + rsbac_list_lol_subexist_compare + (process_group_fs_handle, &pid, &member, + single_cap_compare); +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + /* check for pseudo set "all" */ + if (!result) { + rsbac_uid_t amember; + + amember = RSBAC_GEN_GID(RSBAC_UM_VIRTUAL_ALL, member); + result = rsbac_list_lol_subexist_compare(process_group_fs_handle, + &pid, + &amember, + single_cap_compare); + } +#endif + +#if defined(CONFIG_RSBAC_AUTH_LEARN) + if (!result && (RSBAC_GID_NUM(member) <= RSBAC_AUTH_MAX_RANGE_GID) + ) { + union rsbac_target_id_t tid; + union rsbac_attribute_value_t attr_val; + rsbac_boolean_t learn; + + learn = rsbac_auth_learn; + if (!learn) { + tid.process = pid; + /* check learn on process */ + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, A_auth_learn, + &attr_val, FALSE)) + learn = attr_val.auth_learn; + } + if (learn) { + struct rsbac_auth_cap_range_t range; + struct file *file_p; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_GID_SET(member)) + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH group fs capability for gid %u/%u to pid %u(%s) to transaction %u!\n", + RSBAC_GID_SET(member), + RSBAC_GID_NUM(member), + pid_nr(pid), + current->comm, + auth_learn_ta); + else +#endif + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH group fs capability for gid %u to pid %u(%s) to transaction %u!\n", + RSBAC_GID_NUM(member), pid_nr(pid), current->comm, auth_learn_ta); + range.first = member; + range.last = member; +#ifdef CONFIG_RSBAC_AUTH_LEARN_TA + if (!rsbac_list_ta_exist(auth_learn_ta)) + rsbac_list_ta_begin(CONFIG_RSBAC_LIST_TRANS_MAX_TTL, + &auth_learn_ta, + RSBAC_ALL_USERS, + RSBAC_AUTH_LEARN_TA_NAME, + NULL); +#endif + rsbac_ta_list_lol_subadd_ttl(auth_learn_ta, + process_group_fs_handle, + RSBAC_LIST_TTL_KEEP, + &pid, + &range, + NULL); + + tid.process = pid; + file_p = get_task_exe_file(pid_task(pid, PIDTYPE_PID)); + if (file_p && file_p->f_path.dentry && file_p->f_path.dentry->d_inode) { + struct + rsbac_auth_device_list_item_t + *device_p; + union rsbac_attribute_value_t + attr_val2; + char * target_id_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name + = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, + A_auth_start_gid, &attr_val2, + FALSE) + && (range.first == + attr_val2.auth_start_gid) + ) { + range.first = + RSBAC_AUTH_GROUP_F_CAP; + range.last = range.first; + } else + if (!rsbac_get_attr + (SW_AUTH, T_PROCESS, tid, + A_auth_start_egid, + &attr_val2, FALSE) + && (range.first == + attr_val2. + auth_start_egid) + ) { + range.first = + RSBAC_AUTH_DAC_GROUP_F_CAP; + range.last = range.first; + } + tid.file.device = file_p->f_path.dentry->d_sb->s_dev; + tid.file.inode = file_p->f_path.dentry->d_inode->i_ino; + tid.file.dentry_p = file_p->f_path.dentry; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_GID_SET(range.first)) + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH group fs capability for gid %u/%u to FILE %s to transaction %u!\n", + RSBAC_GID_SET(range.first), + RSBAC_GID_NUM(range.first), + get_target_name(NULL, T_FILE, target_id_name, tid), + auth_learn_ta); + else +#endif + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): adding AUTH group fs capability for gid %u to FILE %s to transaction %u!\n", + RSBAC_GID_NUM(range.first), + get_target_name(NULL, T_FILE, target_id_name, tid), + auth_learn_ta); + rsbac_kfree(target_id_name); + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(tid.file.device); + if (device_p) { + rsbac_ta_list_lol_subadd_ttl( + auth_learn_ta, + device_p->group_fs_handle, + RSBAC_LIST_TTL_KEEP, + &tid.file.inode, + &range, + NULL); + } else { + rsbac_printk(KERN_INFO "rsbac_auth_p_capset_member(): unknown device %02u:%02u!\n", + MAJOR(tid.file.device), + MINOR(tid.file.device)); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + } + result = TRUE; + } + } +#endif + break; +#endif /* AUTH_DAC_GROUP */ +#endif /* AUTH_GROUP */ + + default: + return FALSE; + } + return result; +} + +/* rsbac_auth_remove_capset */ +/* Remove a full set. For cleanup, if object is deleted. */ +/* To empty an existing set use rsbac_auth_clear_capset. */ + +int rsbac_auth_remove_p_capsets(rsbac_pid_t pid) +{ + int err; + + err = rsbac_auth_clear_p_capset(0, pid, ACT_real); +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + err = rsbac_auth_clear_p_capset(0, pid, ACT_eff); + err = rsbac_auth_clear_p_capset(0, pid, ACT_fs); +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + err = rsbac_auth_clear_p_capset(0, pid, ACT_group_real); +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + err = rsbac_auth_clear_p_capset(0, pid, ACT_group_eff); + err = rsbac_auth_clear_p_capset(0, pid, ACT_group_fs); +#endif +#endif /* AUTH_GROUP */ + + return err; +} + +int rsbac_auth_remove_f_capsets(rsbac_auth_file_t file) +{ + int err; + + err = rsbac_auth_clear_f_capset(0, file, ACT_real); +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + if (!err) + err = rsbac_auth_clear_f_capset(0, file, ACT_eff); + if (!err) + err = rsbac_auth_clear_f_capset(0, file, ACT_fs); +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + err = rsbac_auth_clear_f_capset(0, file, ACT_group_real); +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + if (!err) + err = rsbac_auth_clear_f_capset(0, file, ACT_group_eff); + if (!err) + err = rsbac_auth_clear_f_capset(0, file, ACT_group_fs); +#endif +#endif /* AUTH_GROUP */ + + return err; +} + +int rsbac_auth_copy_fp_capset(rsbac_auth_file_t file, + rsbac_pid_t p_cap_set_id) +{ + struct rsbac_auth_device_list_item_t *device_p; + int err = 0; + int srcu_idx; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_auth_copy_fp_capset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_auth_copy_fp_capset(): called from interrupt!\n"); + } +/* + rsbac_pr_debug(ds_auth, "Copying file cap set data to process cap set\n"); +*/ + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_auth_copy_fp_capset(): invalid device %02u:%02u!\n", + RSBAC_MAJOR(file.device), + RSBAC_MINOR(file.device)); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + /* call the copy function */ + err = copy_fp_cap_set_item(device_p, file, p_cap_set_id); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; +} + +int rsbac_auth_copy_pp_capset(rsbac_pid_t old_p_set_id, + rsbac_pid_t new_p_set_id) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_auth_copy_pp_capset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_auth_copy_pp_capset(): called from interrupt!\n"); + } +/* + rsbac_pr_debug(ds_auth, "Copying process cap set data to process cap set\n"); +*/ + /* call the copy function */ + return copy_pp_cap_set_item(old_p_set_id, new_p_set_id); +} + +int rsbac_auth_get_f_caplist(rsbac_list_ta_number_t ta_number, + rsbac_auth_file_t file, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t **caplist_p, + rsbac_time_t ** ttllist_p) +{ + struct rsbac_auth_device_list_item_t *device_p; + long count; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr = file.inode; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_auth_get_f_caplist(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_auth_get_f_caplist(): called from interrupt!\n"); + } +/* + rsbac_pr_debug(ds_auth, "Getting file/dir cap set list\n"); +*/ + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_auth_get_f_caplist(): invalid device %02u:%02u!\n", + RSBAC_MAJOR(file.device), + RSBAC_MINOR(file.device)); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + switch (cap_type) { + case ACT_real: + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + device_p->handle, + &inode_nr, + (void **) + caplist_p, + ttllist_p); + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + case ACT_eff: + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + device_p->eff_handle, + &inode_nr, + (void **) + caplist_p, + ttllist_p); + break; + case ACT_fs: + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + device_p->fs_handle, + &inode_nr, + (void **) + caplist_p, + ttllist_p); + break; +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + case ACT_group_real: + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + device_p->group_handle, + &inode_nr, + (void **) + caplist_p, + ttllist_p); + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case ACT_group_eff: + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + device_p->group_eff_handle, + &inode_nr, + (void **) + caplist_p, + ttllist_p); + break; + case ACT_group_fs: + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + device_p->group_fs_handle, + &inode_nr, + (void **) + caplist_p, + ttllist_p); + break; +#endif +#endif /* AUTH_GROUP */ + + default: + count = -RSBAC_EINVALIDTARGET; + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + return count; +} + +int rsbac_auth_get_p_caplist(rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t **caplist_p, + rsbac_time_t ** ttllist_p) +{ + long count; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_auth_get_p_caplist(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_auth_get_p_caplist(): called from interrupt!\n"); + } +/* + rsbac_pr_debug(ds_auth, "Getting process cap set list\n"); +*/ + switch (cap_type) { + case ACT_real: + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + process_handle, + &pid, + (void **) + caplist_p, + ttllist_p); + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_OWNER + case ACT_eff: + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + process_eff_handle, + &pid, + (void **) + caplist_p, + ttllist_p); + break; + case ACT_fs: + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + process_fs_handle, + &pid, + (void **) + caplist_p, + ttllist_p); + break; +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + case ACT_group_real: + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + process_group_handle, + &pid, + (void **) + caplist_p, + ttllist_p); + break; +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case ACT_group_eff: + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + process_group_eff_handle, + &pid, + (void **) + caplist_p, + ttllist_p); + break; + case ACT_group_fs: + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + process_group_fs_handle, + &pid, + (void **) + caplist_p, + ttllist_p); + break; +#endif +#endif /* AUTH_GROUP */ + + default: + count = -RSBAC_EINVALIDTARGET; + } + return count; +} diff --git a/rsbac/data_structures/gen_lists.c b/rsbac/data_structures/gen_lists.c new file mode 100644 index 000000000000..ebd80bf16404 --- /dev/null +++ b/rsbac/data_structures/gen_lists.c @@ -0,0 +1,13086 @@ +/************************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2017: */ +/* Amon Ott */ +/* Generic lists for all parts */ +/* Last modified: 21/Jul/2017 */ +/************************************* */ + +#include +#include +#include +#ifdef CONFIG_RSBAC_LIST_TRANS_RANDOM_TA +#include +#endif +#include +#include +#ifndef CONFIG_RSBAC_NO_WRITE +#include +#endif +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************/ +/* Global Variables */ +/********************/ + +static struct rsbac_list_reg_head_t reg_head; +static struct rsbac_list_lol_reg_head_t lol_reg_head; +static rsbac_boolean_t list_initialized = FALSE; +static struct srcu_struct reg_list_srcu; +static struct srcu_struct lol_reg_list_srcu; + +static struct kmem_cache * reg_item_slab = NULL; +static struct kmem_cache * lol_reg_item_slab = NULL; + +static struct lock_class_key list_lock_class; + +static u_int rsbac_list_max_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; + +#ifdef CONFIG_RSBAC_LIST_TRANS +static struct rsbac_list_reg_item_t *ta_handle = NULL; +static DEFINE_SPINLOCK(ta_lock); +static rsbac_boolean_t ta_committing = FALSE; +DECLARE_WAIT_QUEUE_HEAD(ta_wait); +#ifndef CONFIG_RSBAC_LIST_TRANS_RANDOM_TA +rsbac_list_ta_number_t ta_next = 1; +#endif +#endif + +#ifdef CONFIG_RSBAC_LIST_TRANS +static int do_forget(rsbac_list_ta_number_t ta_number); +#endif + +#ifdef CONFIG_RSBAC_AUTO_WRITE +static rsbac_time_t next_rehash = 0; +#endif + +static u_int rsbac_list_read_errors = 0; + +#ifdef CONFIG_RSBAC_LIST_STATS +static __u64 rcu_free_calls = 0; +static __u64 rcu_free_item_chain_calls = 0; +static __u64 rcu_free_lol_calls = 0; +static __u64 rcu_free_lol_sub_calls = 0; +static __u64 rcu_free_lol_item_chain_calls = 0; +static __u64 rcu_free_lol_subitem_chain_calls = 0; +static __u64 rcu_free_do_cleanup_calls = 0; +static __u64 rcu_free_do_cleanup_lol_calls = 0; +static __u64 rcu_free_callback_calls = 0; +static __u64 rcu_free_callback_lol_calls = 0; +static __u32 max_rcu_callback_count = 0; +#endif + +/* Limit RCU callback calls to RCURATE per second, switch to sync when exceeded */ +#if CONFIG_RSBAC_RCU_RATE < 0 +#define RCURATE 0 +#else +#if CONFIG_RSBAC_RCU_RATE > 1000 +#define RCURATE 1000 +#else +#define RCURATE CONFIG_RSBAC_RCU_RATE +#endif +#endif +u_int rsbac_list_rcu_rate = RCURATE; +static u_int rcu_callback_count = 0; +static struct timer_list rcu_rate_timer; + +static struct kmem_cache * rcu_free_item_slab = NULL; +static struct kmem_cache * rcu_free_head_slab = NULL; +static struct kmem_cache * rcu_free_head_lol_slab = NULL; + + +/*********************************/ +/* Data Structures */ +/*********************************/ + +/* RCU garbage collector */ + +/* Call spinlocked */ +static inline struct rsbac_list_rcu_free_head_t * + get_rcu_free(struct rsbac_list_reg_item_t * list) +{ + if (list->rcu_free) { + struct rsbac_list_rcu_free_head_t * rcu_free; + + rcu_free = list->rcu_free; + list->rcu_free = NULL; + return rcu_free; + } else + return NULL; +} + +/* Call spinlocked */ +static inline struct rsbac_list_rcu_free_head_lol_t * + get_rcu_free_lol(struct rsbac_list_lol_reg_item_t * list) +{ + if (list->rcu_free) { + struct rsbac_list_rcu_free_head_lol_t * rcu_free; + + rcu_free = list->rcu_free; + list->rcu_free = NULL; + return rcu_free; + } else + return NULL; +} + +/* Call spinlocked */ +static struct rsbac_list_rcu_free_head_t * + create_rcu_free(struct rsbac_list_reg_item_t * list) +{ + /* Just to be sure */ + if (unlikely(!list)) + return NULL; + /* Exists, all fine */ + if (list->rcu_free) + return list->rcu_free; + + list->rcu_free = rsbac_smalloc_clear(rcu_free_head_slab); + if (unlikely(!list->rcu_free)) + return NULL; + list->rcu_free->slab = list->slab; + return list->rcu_free; +} + +/* Call spinlocked */ +static struct rsbac_list_rcu_free_head_lol_t * + create_rcu_free_lol(struct rsbac_list_lol_reg_item_t * list) +{ + /* Just to be sure */ + if (unlikely(!list)) + return NULL; + /* Exists, all fine */ + if (list->rcu_free) + return list->rcu_free; + + list->rcu_free = rsbac_smalloc_clear(rcu_free_head_lol_slab); + if (unlikely(!list->rcu_free)) + return NULL; + list->rcu_free->slab = list->slab; + list->rcu_free->subslab = list->subslab; + return list->rcu_free; +} + +/* Call spinlocked */ +static void rcu_free(struct rsbac_list_reg_item_t * list, void * mem) +{ + struct rsbac_list_rcu_free_item_t * rcu_item; + + if (unlikely(!create_rcu_free(list))) { + rsbac_printk(KERN_WARNING "rcu_free(): cannot allocate rcu_free_head for list %s, loosing item %p!\n", + list->name, mem); + return; + } +#ifdef CONFIG_RSBAC_LIST_STATS + rcu_free_calls++; +#endif +#if 0 + /* Sanity check for dupes - to be removed after test phase */ + rcu_item = list->rcu_free->head; + while (rcu_item) { + if (unlikely(rcu_item->mem == mem)) { + BUG(); + return; + } + rcu_item = rcu_item->next; + } +#endif + rcu_item = rsbac_smalloc(rcu_free_item_slab); + if (likely(rcu_item)) { + rcu_item->mem = mem; + rcu_item->next = list->rcu_free->head; + list->rcu_free->head = rcu_item; + } else { + rsbac_printk(KERN_WARNING "rcu_free(): cannot allocate rcu_free for list %s, loosing item %p!\n", + list->name, mem); + rcu_callback_count = rsbac_list_rcu_rate; + } +} + +/* Call spinlocked */ +static void rcu_free_lol(struct rsbac_list_lol_reg_item_t * list, void * mem) +{ + struct rsbac_list_rcu_free_item_t * rcu_item; + + if (unlikely(!create_rcu_free_lol(list))) { + rsbac_printk(KERN_WARNING "rcu_free_lol(): cannot allocate rcu_free_head for list of lists %s, loosing item %p!\n", + list->name, mem); + return; + } +#ifdef CONFIG_RSBAC_LIST_STATS + rcu_free_lol_calls++; +#endif +#if 0 + /* Sanity check for dupes - to be removed after test phase */ + rcu_item = list->rcu_free->head; + while (rcu_item) { + if (unlikely(rcu_item->mem == mem)) { + BUG(); + return; + } + rcu_item = rcu_item->next; + } +#endif + rcu_item = rsbac_smalloc(rcu_free_item_slab); + if (likely(rcu_item)) { + rcu_item->mem = mem; + rcu_item->next = list->rcu_free->head; + list->rcu_free->head = rcu_item; + } else { + rsbac_printk(KERN_WARNING "rcu_free_lol(): cannot allocate rcu_free for list of lists %s, loosing item %p!\n", + list->name, mem); + rcu_callback_count = rsbac_list_rcu_rate; + } +} + +/* Call spinlocked */ +static void rcu_free_lol_sub(struct rsbac_list_lol_reg_item_t * list, void * mem) +{ + struct rsbac_list_rcu_free_item_t * rcu_item; + + if (unlikely(!create_rcu_free_lol(list))) { + rsbac_printk(KERN_WARNING "rcu_free_lol_sub(): cannot allocate rcu_free_head for list of lists %s, loosing subitem %p!\n", + list->name, mem); + return; + } +#ifdef CONFIG_RSBAC_LIST_STATS + rcu_free_lol_calls++; +#endif +#if 0 + /* Sanity check for dupes - to be removed after test phase */ + rcu_item = list->rcu_free->subhead; + while (rcu_item) { + if (unlikely(rcu_item->mem == mem)) { + BUG(); + return; + } + rcu_item = rcu_item->next; + } +#endif + rcu_item = rsbac_smalloc(rcu_free_item_slab); + if (likely(rcu_item)) { + rcu_item->mem = mem; + rcu_item->next = list->rcu_free->subhead; + list->rcu_free->subhead = rcu_item; + } else { + rsbac_printk(KERN_WARNING "rcu_free_lol_sub(): cannot allocate rcu_free for list of lists %s, loosing subitem %p!\n", + list->name, mem); + rcu_callback_count = rsbac_list_rcu_rate; + } +} + +/* Call spinlocked */ +static void rcu_free_item_chain(struct rsbac_list_reg_item_t * list, + struct rsbac_list_item_t * item_chain) +{ + if (!item_chain) + return; + if (unlikely(!create_rcu_free(list))) { + rsbac_printk(KERN_WARNING "rcu_free_item_chain(): cannot allocate rcu_free_head for list %s, loosing chain %p!\n", + list->name, item_chain); + return; + } +#ifdef CONFIG_RSBAC_LIST_STATS + rcu_free_item_chain_calls++; +#endif + if (!list->rcu_free->item_chain) { + list->rcu_free->item_chain = item_chain; + } else { + while (item_chain) { + rcu_free(list, item_chain); + item_chain = item_chain->next; + } + } +} + +/* Call spinlocked */ +static void rcu_free_lol_subitem_chain(struct rsbac_list_lol_reg_item_t * list, + struct rsbac_list_item_t * subitem_chain) +{ + if (!subitem_chain) + return; + if (unlikely(!create_rcu_free_lol(list))) { + rsbac_printk(KERN_WARNING "rcu_free_lol_subitem_chain(): cannot allocate rcu_free_head for list of lists %s, loosing subchain %p!\n", + list->name, subitem_chain); + return; + } +#ifdef CONFIG_RSBAC_LIST_STATS + rcu_free_lol_subitem_chain_calls++; +#endif + if (!list->rcu_free->lol_item_subchain) { + list->rcu_free->lol_item_subchain = subitem_chain; + } else { + while (subitem_chain) { + rcu_free_lol_sub(list, subitem_chain); + subitem_chain = subitem_chain->next; + } + } +} + +/* Call spinlocked */ +static void rcu_free_lol_item_chain(struct rsbac_list_lol_reg_item_t * list, + struct rsbac_list_lol_item_t * lol_item_chain) +{ + if (!lol_item_chain) + return; + if (unlikely(!create_rcu_free_lol(list))) { + rsbac_printk(KERN_WARNING "rcu_free_lol_item_chain(): cannot allocate rcu_free_head for list of lists %s, loosing chain %p!\n", + list->name, lol_item_chain); + return; + } +#ifdef CONFIG_RSBAC_LIST_STATS + rcu_free_lol_item_chain_calls++; +#endif + if (!list->rcu_free->lol_item_chain) { + list->rcu_free->lol_item_chain = lol_item_chain; + } else { + struct rsbac_list_item_t * sub_item; + + while (lol_item_chain) { + sub_item = lol_item_chain->head; + while (sub_item) { + rcu_free_lol_sub(list, sub_item); + sub_item = sub_item->next; + } + rcu_free_lol(list, lol_item_chain); + lol_item_chain = lol_item_chain->next; + } + } +} + +/* Call unlocked */ +static void rcu_free_do_cleanup(struct rsbac_list_rcu_free_head_t * rcu_head) +{ + struct rsbac_list_rcu_free_item_t * rcu_item; + struct rsbac_list_rcu_free_item_t * rcu_next_item; + struct rsbac_list_item_t * item_chain; + struct rsbac_list_item_t * item_chain_next; + + if (!rcu_head) + return; +#ifdef CONFIG_RSBAC_LIST_STATS + rcu_free_do_cleanup_calls++; +#endif + rcu_item = rcu_head->head; + if (rcu_head->slab) { + while (rcu_item) { + rsbac_sfree(rcu_head->slab, rcu_item->mem); + rcu_next_item = rcu_item->next; + rsbac_sfree(rcu_free_item_slab, rcu_item); + rcu_item = rcu_next_item; + } + item_chain = rcu_head->item_chain; + while (item_chain) { + item_chain_next = item_chain->next; + rsbac_sfree(rcu_head->slab, item_chain); + item_chain = item_chain_next; + } + } else { + while (rcu_item) { + rsbac_kfree(rcu_item->mem); + rcu_next_item = rcu_item->next; + rsbac_sfree(rcu_free_item_slab, rcu_item); + rcu_item = rcu_next_item; + } + item_chain = rcu_head->item_chain; + while (item_chain) { + item_chain_next = item_chain->next; + rsbac_kfree(item_chain); + item_chain = item_chain_next; + } + } + rsbac_sfree(rcu_free_head_slab, rcu_head); +} + +/* Call unlocked */ +static void rcu_free_do_cleanup_lol(struct rsbac_list_rcu_free_head_lol_t * rcu_head) +{ + struct rsbac_list_rcu_free_item_t * rcu_item; + struct rsbac_list_rcu_free_item_t * rcu_next_item; + struct rsbac_list_lol_item_t * lol_item_chain; + struct rsbac_list_lol_item_t * lol_item_chain_next; + struct rsbac_list_item_t * lol_item_subchain; + struct rsbac_list_item_t * lol_item_subchain_next; + + if (!rcu_head) + return; +#ifdef CONFIG_RSBAC_LIST_STATS + rcu_free_do_cleanup_lol_calls++; +#endif + rcu_item = rcu_head->head; + if (rcu_head->slab) { + while (rcu_item) { + rsbac_sfree(rcu_head->slab, rcu_item->mem); + rcu_next_item = rcu_item->next; + rsbac_sfree(rcu_free_item_slab, rcu_item); + rcu_item = rcu_next_item; + } + rcu_item = rcu_head->subhead; + while (rcu_item) { + rsbac_sfree(rcu_head->subslab, rcu_item->mem); + rcu_next_item = rcu_item->next; + rsbac_sfree(rcu_free_item_slab, rcu_item); + rcu_item = rcu_next_item; + } + lol_item_chain = rcu_head->lol_item_chain; + while (lol_item_chain) { + lol_item_subchain = lol_item_chain->head; + while (lol_item_subchain) { + lol_item_subchain_next = lol_item_subchain->next; + rsbac_sfree(rcu_head->subslab, lol_item_subchain); + lol_item_subchain = lol_item_subchain_next; + } + lol_item_chain_next = lol_item_chain->next; + rsbac_sfree(rcu_head->slab, lol_item_chain); + lol_item_chain = lol_item_chain_next; + } + lol_item_subchain = rcu_head->lol_item_subchain; + while (lol_item_subchain) { + lol_item_subchain_next = lol_item_subchain->next; + rsbac_sfree(rcu_head->subslab, lol_item_subchain); + lol_item_subchain = lol_item_subchain_next; + } + } else { + while (rcu_item) { + rsbac_kfree(rcu_item->mem); + rcu_next_item = rcu_item->next; + rsbac_sfree(rcu_free_item_slab, rcu_item); + rcu_item = rcu_next_item; + } + lol_item_chain = rcu_head->lol_item_chain; + while (lol_item_chain) { + lol_item_subchain = lol_item_chain->head; + while (lol_item_subchain) { + lol_item_subchain_next = lol_item_subchain->next; + rsbac_kfree(lol_item_subchain); + lol_item_subchain = lol_item_subchain_next; + } + lol_item_chain_next = lol_item_chain->next; + rsbac_kfree(lol_item_chain); + lol_item_chain = lol_item_chain_next; + } + lol_item_subchain = rcu_head->lol_item_subchain; + while (lol_item_subchain) { + lol_item_subchain_next = lol_item_subchain->next; + rsbac_kfree(lol_item_subchain); + lol_item_subchain = lol_item_subchain_next; + } + } + rsbac_sfree(rcu_free_head_lol_slab, rcu_head); +} + +/* RCU callback, do not call directly. Called unlocked by RCU. */ +static void rcu_free_callback(struct rcu_head *rp) +{ + if (unlikely(!rp)) + return; +#ifdef CONFIG_RSBAC_LIST_STATS + rcu_free_callback_calls++; +#endif + rcu_free_do_cleanup((struct rsbac_list_rcu_free_head_t *) rp); +} + +/* RCU callback, do not call directly. Called unlocked by RCU. */ +static void rcu_free_callback_lol(struct rcu_head *rp) +{ + if (unlikely(!rp)) + return; +#ifdef CONFIG_RSBAC_LIST_STATS + rcu_free_callback_lol_calls++; +#endif + rcu_free_do_cleanup_lol((struct rsbac_list_rcu_free_head_lol_t *) rp); +} + +#ifdef CONFIG_RSBAC_LIST_TRANS +/* Call unlocked */ +static void do_call_rcu(struct rsbac_list_rcu_free_head_t * rcu_head) +{ + if (rcu_head) { + rcu_callback_count++; + call_rcu(&rcu_head->rcu, rcu_free_callback); + } +} +/* Call unlocked */ +static void do_call_rcu_lol(struct rsbac_list_rcu_free_head_lol_t * rcu_head) +{ + if (rcu_head) { + rcu_callback_count++; + call_rcu(&rcu_head->rcu, rcu_free_callback_lol); + } +} +#endif + +/* Call unlocked */ +static void do_sync_rcu(struct rsbac_list_rcu_free_head_t * rcu_head) +{ + if (rcu_head) { + rcu_callback_count++; + if (rcu_callback_count < rsbac_list_rcu_rate) + call_rcu(&rcu_head->rcu, rcu_free_callback); + else { + synchronize_rcu(); + rcu_free_do_cleanup(rcu_head); + } + } +} + +/* Call unlocked */ +static void do_sync_rcu_lol(struct rsbac_list_rcu_free_head_lol_t * rcu_head) +{ + if (rcu_head) { + rcu_callback_count++; + if (rcu_callback_count < rsbac_list_rcu_rate) + call_rcu(&rcu_head->rcu, rcu_free_callback_lol); + else { + synchronize_rcu(); + rcu_free_do_cleanup_lol(rcu_head); + } + } +} + +/* List handling */ +/* Call RCU locked */ +static inline struct rsbac_list_item_t *lookup_item_compare( + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + u_int hash, + void *desc) +{ + struct rsbac_list_item_t *curr; + int compres; + + curr = rcu_dereference(hashed[hash].curr); + if (!curr) { + curr = rcu_dereference(hashed[hash].head); + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = list->compare(desc, &curr[1]); + if (compres) { + if (compres > 0) { + curr = rcu_dereference(curr->next); + while (curr && (list->compare(desc, &curr[1]) > 0) + ) + curr = rcu_dereference(curr->next); + } else { + curr = rcu_dereference(curr->prev); + while (curr && (list->compare(desc, &curr[1]) < 0) + ) + curr = rcu_dereference(curr->prev); + } + if (curr) { + if (!list->compare(desc, &curr[1])) + return curr; + } + /* NULL or not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +/* Call RCU locked */ +static inline struct rsbac_list_item_t *lookup_item_memcmp( + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + u_int hash, + void *desc) +{ + struct rsbac_list_item_t *curr; + int compres; + + curr = rcu_dereference(hashed[hash].curr); + if (!curr) { + curr = rcu_dereference(hashed[hash].head); + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = memcmp(desc, &curr[1], list->info.desc_size); + if (compres) { + if (compres > 0) { + curr = rcu_dereference(curr->next); + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) > 0) + ) + curr = rcu_dereference(curr->next); + } else { + curr = rcu_dereference(curr->prev); + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) < 0) + ) + curr = rcu_dereference(curr->prev); + } + if (curr) { + if (!memcmp(desc, &curr[1], list->info.desc_size)) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +/* Call RCU locked */ +static struct rsbac_list_item_t *lookup_item( + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + u_int hash, + void *desc) +{ + if (unlikely(!list || !desc || !hashed)) + return NULL; + + if (list->compare) + return lookup_item_compare(list, hashed, hash, desc); + else + return lookup_item_memcmp(list, hashed, hash, desc); +} + +/* Call spinlocked */ +static inline struct rsbac_list_item_t *lookup_item_compare_locked( + struct rsbac_list_reg_item_t *list, void *desc) +{ + struct rsbac_list_item_t *curr; + u_int hash = 0; + int compres; + + if (unlikely(!list || !desc || !list->compare)) + return NULL; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].curr; + if (!curr) { + curr = list->hashed[hash].head; + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = list->compare(desc, &curr[1]); + if (compres) { + if (compres > 0) { + curr = curr->next; + while (curr && (list->compare(desc, &curr[1]) > 0) + ) + curr = curr->next; + } else { + curr = curr->prev; + while (curr && (list->compare(desc, &curr[1]) < 0) + ) + curr = curr->prev; + } + if (curr) { + rcu_assign_pointer(list->hashed[hash].curr, curr); + if (!list->compare(desc, &curr[1])) + return curr; + } + /* NULL or not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +static inline struct rsbac_list_item_t *lookup_item_memcmp_locked(struct + rsbac_list_reg_item_t + *list, void *desc) +{ + struct rsbac_list_item_t *curr; + u_int hash = 0; + int compres; + + if (unlikely(!list || !desc)) + return NULL; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].curr; + if (!curr) { + curr = list->hashed[hash].head; + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = memcmp(desc, &curr[1], list->info.desc_size); + if (compres) { + if (compres > 0) { + curr = curr->next; + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) > 0) + ) + curr = curr->next; + } else { + curr = curr->prev; + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) < 0) + ) + curr = curr->prev; + } + if (curr) { + rcu_assign_pointer(list->hashed[hash].curr, curr); + if (!memcmp(desc, &curr[1], list->info.desc_size)) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +static struct rsbac_list_item_t *lookup_item_locked(struct rsbac_list_reg_item_t + *list, void *desc) +{ + if (unlikely(!list || !desc)) + return NULL; + + if (list->compare) + return lookup_item_compare_locked(list, desc); + else + return lookup_item_memcmp_locked(list, desc); +} + +#ifdef CONFIG_RSBAC_LIST_TRANS +/* Call RCU locked */ +static inline struct rsbac_list_item_t *ta_lookup_item_compare( + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + u_int hash, + void *desc) +{ + struct rsbac_list_item_t *curr; + int compres; + + curr = rcu_dereference(hashed[hash].ta_curr); + if (!curr) { + curr = rcu_dereference(hashed[hash].ta_head); + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = list->compare(desc, &curr[1]); + if (compres) { + if (compres > 0) { + curr = rcu_dereference(curr->next); + while (curr && (list->compare(desc, &curr[1]) > 0) + ) + curr = rcu_dereference(curr->next); + } else { + curr = rcu_dereference(curr->prev); + while (curr && (list->compare(desc, &curr[1]) < 0) + ) + curr = rcu_dereference(curr->prev); + } + if (curr) { + if (!list->compare(desc, &curr[1])) + return curr; + } + /* NULL or not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +/* Call RCU locked */ +static inline struct rsbac_list_item_t *ta_lookup_item_memcmp( + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + u_int hash, + void *desc) +{ + struct rsbac_list_item_t *curr; + int compres; + + curr = rcu_dereference(hashed[hash].ta_curr); + if (!curr) { + curr = rcu_dereference(hashed[hash].ta_head); + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = memcmp(desc, &curr[1], list->info.desc_size); + if (compres) { + if (compres > 0) { + curr = rcu_dereference(curr->next); + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) > 0) + ) + curr = rcu_dereference(curr->next); + } else { + curr = rcu_dereference(curr->prev); + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) < 0) + ) + curr = rcu_dereference(curr->prev); + } + if (curr) { + if (!memcmp(desc, &curr[1], list->info.desc_size)) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +/* Call RCU locked */ +static struct rsbac_list_item_t *ta_lookup_item( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + u_int hash, + void *desc) +{ + if (unlikely(!list || !desc)) + return NULL; + + if (!hashed[hash].ta_copied) + return lookup_item(list, hashed, hash, desc); + if (hashed[hash].ta_copied != ta_number) + return NULL; + + if (list->compare) + return ta_lookup_item_compare(list, hashed, hash, desc); + else + return ta_lookup_item_memcmp(list, hashed, hash, desc); +} + +static inline struct rsbac_list_item_t *ta_lookup_item_compare_locked( + struct rsbac_list_reg_item_t *list, void *desc) +{ + struct rsbac_list_item_t *curr; + u_int hash = 0; + int compres; + + if (unlikely(!list || !desc || !list->compare)) + return NULL; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].ta_curr; + if (!curr) { + curr = list->hashed[hash].ta_head; + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = list->compare(desc, &curr[1]); + if (compres) { + if (compres > 0) { + curr = curr->next; + while (curr && (list->compare(desc, &curr[1]) > 0) + ) + curr = curr->next; + } else { + curr = curr->prev; + while (curr && (list->compare(desc, &curr[1]) < 0) + ) + curr = curr->prev; + } + if (curr) { + rcu_assign_pointer(list->hashed[hash].ta_curr, curr); + if (!list->compare(desc, &curr[1])) + return curr; + } + /* NULL or not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +static inline struct rsbac_list_item_t *ta_lookup_item_memcmp_locked(struct + rsbac_list_reg_item_t + *list, void *desc) +{ + struct rsbac_list_item_t *curr; + u_int hash = 0; + int compres; + + if (unlikely(!list || !desc)) + return NULL; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].ta_curr; + if (!curr) { + curr = list->hashed[hash].ta_head; + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = memcmp(desc, &curr[1], list->info.desc_size); + if (compres) { + if (compres > 0) { + curr = curr->next; + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) > 0) + ) + curr = curr->next; + } else { + curr = curr->prev; + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) < 0) + ) + curr = curr->prev; + } + if (curr) { + rcu_assign_pointer(list->hashed[hash].ta_curr, curr); + if (!memcmp(desc, &curr[1], list->info.desc_size)) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +static struct rsbac_list_item_t *ta_lookup_item_locked(const rsbac_list_ta_number_t ta_number, + struct + rsbac_list_reg_item_t + *list, void *desc) +{ + u_int hash = 0; + + if (unlikely(!list || !desc)) + return NULL; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + if (!list->hashed[hash].ta_copied) + return lookup_item_locked(list, desc); + if (list->hashed[hash].ta_copied != ta_number) + return NULL; + + if (list->compare) + return ta_lookup_item_compare_locked(list, desc); + else + return ta_lookup_item_memcmp_locked(list, desc); +} +#endif + +/* Call RCU locked */ +static inline struct rsbac_list_item_t *lookup_item_data_compare( + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare) +{ + struct rsbac_list_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || compare((char *) curr + sizeof(*curr) + + list->info.desc_size, data) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static inline struct rsbac_list_item_t *lookup_item_data_memcmp( + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + const __u8 hash_bits, + void *data) +{ + struct rsbac_list_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || memcmp(data, + &curr[1] + list->info.desc_size, + list->info.data_size) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static struct rsbac_list_item_t *lookup_item_data( + struct rsbac_list_reg_item_t * list, + struct rsbac_list_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare) +{ + if (unlikely(!list || !data || !hashed)) + return NULL; + + if (compare) + return lookup_item_data_compare(list, hashed, hash_bits, data, compare); + else + return lookup_item_data_memcmp(list, hashed, hash_bits, data); +} + +#ifdef CONFIG_RSBAC_LIST_TRANS +/* Call RCU locked */ +static inline struct rsbac_list_item_t *ta_lookup_item_data_compare( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_reg_item_t * list, + struct rsbac_list_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare) +{ + struct rsbac_list_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || compare((char *) curr + sizeof(*curr) + + list->info.desc_size, data) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static inline struct rsbac_list_item_t *ta_lookup_item_data_memcmp( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + const __u8 hash_bits, + void *data) +{ + struct rsbac_list_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || memcmp(data, + &curr[1] + list->info.desc_size, + list->info.data_size) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static struct rsbac_list_item_t *ta_lookup_item_data( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare) +{ + if (unlikely(!list || !data || !hashed)) + return NULL; + + if(!ta_number) + return lookup_item_data(list, hashed, hash_bits, data, compare); + if (compare) + return ta_lookup_item_data_compare(ta_number, list, hashed, hash_bits, data, compare); + else + return ta_lookup_item_data_memcmp(ta_number, list, hashed, hash_bits, data); +} +#endif + +/* Call RCU locked */ +static inline struct rsbac_list_item_t *lookup_item_data_compare_selector( + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || compare((char *) curr + sizeof(*curr) + + list->info.desc_size, data) + || !selector((char *) curr + sizeof(*curr), param) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static inline struct rsbac_list_item_t *lookup_item_data_memcmp_selector( + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || memcmp(data, + &curr[1] + list->info.desc_size, + list->info.data_size) + || !selector((char *) curr + sizeof(*curr), param) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static struct rsbac_list_item_t *lookup_item_data_selector( + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + if (unlikely(!list || !data || !hashed)) + return NULL; + + if (compare) + return lookup_item_data_compare_selector(list, + hashed, hash_bits, + data, compare, + selector, + param); + else + return lookup_item_data_memcmp_selector(list, + hashed, hash_bits, + data, + selector, + param); +} + +#ifdef CONFIG_RSBAC_LIST_TRANS +/* Call RCU locked */ +static inline struct rsbac_list_item_t *ta_lookup_item_data_compare_selector( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || compare((char *) curr + sizeof(*curr) + + list->info.desc_size, data) + || !selector((char *) curr + sizeof(*curr), param) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static inline struct rsbac_list_item_t *ta_lookup_item_data_memcmp_selector( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || memcmp(data, + &curr[1] + list->info.desc_size, + list->info.data_size) + || !selector((char *) curr + sizeof(*curr), param) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static struct rsbac_list_item_t *ta_lookup_item_data_selector( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_reg_item_t *list, + struct rsbac_list_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + if (unlikely(!list || !data || !hashed)) + return NULL; + + if(!ta_number) + return lookup_item_data_selector( + list, hashed, hash_bits, + data, compare, + selector, param); + if (compare) + return ta_lookup_item_data_compare_selector( + ta_number, list, + hashed, hash_bits, + data, compare, + selector, param); + else + return ta_lookup_item_data_memcmp_selector( + ta_number, list, + hashed, hash_bits, + data, + selector, param); +} +#endif + +/* list of lists - subitems */ + +/* Call RCU locked */ +static inline struct rsbac_list_item_t *lookup_lol_subitem_compare( + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_item_t *sublist, + void *subdesc, + rsbac_list_compare_function_t compare) +{ + struct rsbac_list_item_t *curr; + int compres; + + if (unlikely(!list || !sublist || !subdesc || !compare)) + return NULL; + + curr = rcu_dereference(sublist->curr); + if (!curr) { + curr = rcu_dereference(sublist->head); + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = compare(&curr[1], subdesc); + if (compres) { + if (compres < 0) { + curr = rcu_dereference(curr->next); + while (curr && (compare(&curr[1], subdesc) < 0) + ) + curr = rcu_dereference(curr->next); + } else { + curr = rcu_dereference(curr->prev); + while (curr && (compare(&curr[1], subdesc) > 0) + ) + curr = rcu_dereference(curr->prev); + } + if (curr) { + if (!compare(&curr[1], subdesc)) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +/* Call RCU locked */ +static inline struct rsbac_list_item_t *lookup_lol_subitem_memcmp( + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_item_t *sublist, + void *subdesc) +{ + struct rsbac_list_item_t *curr; + int compres; + + if (unlikely(!list || !sublist || !subdesc)) + return NULL; + + curr = rcu_dereference(sublist->curr); + if (!curr) { + curr = rcu_dereference(sublist->head); + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = memcmp(subdesc, &curr[1], list->info.subdesc_size); + if (compres) { + if (compres > 0) { + curr = rcu_dereference(curr->next); + while (curr + && (memcmp(subdesc, + &curr[1], + list->info.subdesc_size) > 0) + ) + curr = rcu_dereference(curr->next); + } else { + curr = rcu_dereference(curr->prev); + while (curr + && (memcmp(subdesc, + &curr[1], + list->info.subdesc_size) < 0) + ) + curr = rcu_dereference(curr->prev); + } + if (curr) { + if (!memcmp(subdesc, + &curr[1], list->info.subdesc_size)) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +/* Call RCU locked */ +static struct rsbac_list_item_t *lookup_lol_subitem( + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_item_t *sublist, + void *subdesc) +{ + if (unlikely(!list || !sublist || !subdesc)) + return NULL; + + if (list->subcompare) + return lookup_lol_subitem_compare(list, sublist, subdesc, + list->subcompare); + else + return lookup_lol_subitem_memcmp(list, sublist, subdesc); +} + +static inline struct rsbac_list_item_t *lookup_lol_subitem_compare_locked(struct + rsbac_list_lol_reg_item_t + *list, + struct + rsbac_list_lol_item_t + *sublist, + void *subdesc, + rsbac_list_compare_function_t + compare) +{ + struct rsbac_list_item_t *curr; + int compres; + + if (unlikely(!list || !sublist || !subdesc || !compare)) + return NULL; + + curr = sublist->curr; + if (!curr) { + curr = sublist->head; + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = compare(&curr[1], subdesc); + if (compres) { + if (compres < 0) { + curr = curr->next; + while (curr && (compare(&curr[1], subdesc) < 0) + ) + curr = curr->next; + } else { + curr = curr->prev; + while (curr && (compare(&curr[1], subdesc) > 0) + ) + curr = curr->prev; + } + if (curr) { + rcu_assign_pointer(sublist->curr, curr); + if (!compare(&curr[1], subdesc)) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +static inline struct rsbac_list_item_t *lookup_lol_subitem_memcmp_locked(struct + rsbac_list_lol_reg_item_t + *list, + struct + rsbac_list_lol_item_t + *sublist, + void *subdesc) +{ + struct rsbac_list_item_t *curr; + int compres; + + if (unlikely(!list || !sublist || !subdesc)) + return NULL; + + curr = sublist->curr; + if (!curr) { + curr = sublist->head; + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = memcmp(subdesc, &curr[1], list->info.subdesc_size); + if (compres) { + if (compres > 0) { + curr = curr->next; + while (curr + && (memcmp(subdesc, + &curr[1], + list->info.subdesc_size) > 0) + ) + curr = curr->next; + } else { + curr = curr->prev; + while (curr + && (memcmp(subdesc, + &curr[1], + list->info.subdesc_size) < 0) + ) + curr = curr->prev; + } + if (curr) { + rcu_assign_pointer(sublist->curr, curr); + if (!memcmp(subdesc, + &curr[1], list->info.subdesc_size)) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +static struct rsbac_list_item_t *lookup_lol_subitem_locked(struct + rsbac_list_lol_reg_item_t + *list, + struct + rsbac_list_lol_item_t + *sublist, + void *subdesc) +{ + if (unlikely(!list || !sublist || !subdesc)) + return NULL; + + if (list->subcompare) + return lookup_lol_subitem_compare_locked(list, sublist, subdesc, + list->subcompare); + else + return lookup_lol_subitem_memcmp_locked(list, sublist, subdesc); +} + +/* Call RCU locked */ +static inline struct rsbac_list_item_t *lookup_lol_subitem_user_compare(struct + rsbac_list_lol_reg_item_t + *list, + struct + rsbac_list_lol_item_t + *sublist, + void + *subdesc, + rsbac_list_compare_function_t + compare) +{ + struct rsbac_list_item_t *curr; + + if (unlikely(!list || !sublist || !subdesc || !compare)) + return NULL; + + curr = rcu_dereference(sublist->head); + /* note: item desc is behind official struct */ + while (curr) { + if (!compare(&curr[1], subdesc)) + return curr; + curr = rcu_dereference(curr->next); + } + return curr; +} + +/* list of lists - items */ + +/* Call RCU locked */ +static inline struct rsbac_list_lol_item_t *lookup_lol_item_compare( + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + u_int hash, + void *desc) +{ + struct rsbac_list_lol_item_t *curr; + int compres; + + curr = rcu_dereference(hashed[hash].curr); + if (!curr) { + curr = rcu_dereference(hashed[hash].head); + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = list->compare(desc, &curr[1]); + if (compres) { + if (compres > 0) { + curr = rcu_dereference(curr->next); + while (curr && (list->compare(desc, &curr[1]) > 0) + ) + curr = rcu_dereference(curr->next); + } else { + curr = rcu_dereference(curr->prev); + while (curr && (list->compare(desc, &curr[1]) < 0) + ) + curr = rcu_dereference(curr->prev); + } + if (curr) { + if (!list->compare(desc, &curr[1])) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +/* Call RCU locked */ +static inline struct rsbac_list_lol_item_t *lookup_lol_item_memcmp( + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + u_int hash, + void *desc) +{ + struct rsbac_list_lol_item_t *curr; + int compres; + + curr = rcu_dereference(hashed[hash].curr); + if (!curr) { + curr = rcu_dereference(hashed[hash].head); + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = memcmp(desc, &curr[1], list->info.desc_size); + if (compres) { + if (compres > 0) { + curr = rcu_dereference(curr->next); + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) > 0) + ) + curr = rcu_dereference(curr->next); + } else { + curr = rcu_dereference(curr->prev); + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) < 0) + ) + curr = rcu_dereference(curr->prev); + } + if (curr) { + if (!memcmp(desc, &curr[1], list->info.desc_size)) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +/* Call RCU locked */ +static struct rsbac_list_lol_item_t *lookup_lol_item( + struct rsbac_list_lol_reg_item_t * list, + struct rsbac_list_lol_hashed_t * hashed, + u_int hash, + void *desc) +{ + if (unlikely(!list || !desc || !hashed)) + return NULL; + + if (list->compare) + return lookup_lol_item_compare(list, hashed, hash, desc); + else + return lookup_lol_item_memcmp(list, hashed, hash, desc); +} + +static inline struct rsbac_list_lol_item_t *lookup_lol_item_compare_locked(struct + rsbac_list_lol_reg_item_t + *list, + void *desc) +{ + struct rsbac_list_lol_item_t *curr; + u_int hash = 0; + int compres; + + if (unlikely(!list || !desc || !list->compare)) + return NULL; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].curr; + if (!curr) { + curr = list->hashed[hash].head; + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = list->compare(desc, &curr[1]); + if (compres) { + if (compres > 0) { + curr = curr->next; + while (curr && (list->compare(desc, &curr[1]) > 0) + ) + curr = curr->next; + } else { + curr = curr->prev; + while (curr && (list->compare(desc, &curr[1]) < 0) + ) + curr = curr->prev; + } + if (curr) { + rcu_assign_pointer(list->hashed[hash].curr, curr); + if (!list->compare(desc, &curr[1])) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +static inline struct rsbac_list_lol_item_t *lookup_lol_item_memcmp_locked(struct + rsbac_list_lol_reg_item_t + *list, + void *desc) +{ + struct rsbac_list_lol_item_t *curr; + u_int hash = 0; + int compres; + + if (unlikely(!list || !desc)) + return NULL; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].curr; + if (!curr) { + curr = list->hashed[hash].head; + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = memcmp(desc, &curr[1], list->info.desc_size); + if (compres) { + if (compres > 0) { + curr = curr->next; + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) > 0) + ) + curr = curr->next; + } else { + curr = curr->prev; + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) < 0) + ) + curr = curr->prev; + } + if (curr) { + rcu_assign_pointer(list->hashed[hash].curr, curr); + if (!memcmp(desc, &curr[1], list->info.desc_size)) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +static struct rsbac_list_lol_item_t *lookup_lol_item_locked(struct + rsbac_list_lol_reg_item_t + *list, void *desc) +{ + if (unlikely(!list || !desc)) + return NULL; + + if (list->compare) + return lookup_lol_item_compare_locked(list, desc); + else + return lookup_lol_item_memcmp_locked(list, desc); +} + +#ifdef CONFIG_RSBAC_LIST_TRANS +/* Call RCU locked */ +static inline struct rsbac_list_lol_item_t *ta_lookup_lol_item_compare( + struct rsbac_list_lol_reg_item_t * list, + struct rsbac_list_lol_hashed_t * hashed, + u_int hash, + void *desc) +{ + struct rsbac_list_lol_item_t *curr; + int compres; + + curr = rcu_dereference(hashed[hash].ta_curr); + if (!curr) { + curr = rcu_dereference(hashed[hash].ta_head); + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = list->compare(desc, &curr[1]); + if (compres) { + if (compres > 0) { + curr = rcu_dereference(curr->next); + while (curr && (list->compare(desc, &curr[1]) > 0) + ) + curr = rcu_dereference(curr->next); + } else { + curr = rcu_dereference(curr->prev); + while (curr && (list->compare(desc, &curr[1]) < 0) + ) + curr = rcu_dereference(curr->prev); + } + if (curr) { + if (!list->compare(desc, &curr[1])) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +/* Call RCU locked */ +static inline struct rsbac_list_lol_item_t *ta_lookup_lol_item_memcmp( + struct rsbac_list_lol_reg_item_t * list, + struct rsbac_list_lol_hashed_t * hashed, + u_int hash, + void *desc) +{ + struct rsbac_list_lol_item_t *curr; + int compres; + + curr = rcu_dereference(hashed[hash].ta_curr); + if (!curr) { + curr = rcu_dereference(hashed[hash].ta_head); + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = memcmp(desc, &curr[1], list->info.desc_size); + if (compres) { + if (compres > 0) { + curr = rcu_dereference(curr->next); + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) > 0) + ) + curr = rcu_dereference(curr->next); + } else { + curr = rcu_dereference(curr->prev); + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) < 0) + ) + curr = rcu_dereference(curr->prev); + } + if (curr) { + if (!memcmp(desc, &curr[1], list->info.desc_size)) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +/* Call RCU locked */ +static struct rsbac_list_lol_item_t *ta_lookup_lol_item( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + u_int hash, + void *desc) +{ + if (unlikely(!list || !desc || !hashed)) + return NULL; + + if (!hashed[hash].ta_copied) + return lookup_lol_item(list, hashed, hash, desc); + if (hashed[hash].ta_copied != ta_number) + return NULL; + + if (list->compare) + return ta_lookup_lol_item_compare(list, hashed, hash, desc); + else + return ta_lookup_lol_item_memcmp(list, hashed, hash, desc); +} + +static inline struct rsbac_list_lol_item_t *ta_lookup_lol_item_compare_locked(struct + rsbac_list_lol_reg_item_t + *list, + void *desc) +{ + struct rsbac_list_lol_item_t *curr; + u_int hash = 0; + int compres; + + if (unlikely(!list || !desc || !list->compare)) + return NULL; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].ta_curr; + if (!curr) { + curr = list->hashed[hash].ta_head; + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = list->compare(desc, &curr[1]); + if (compres) { + if (compres > 0) { + curr = curr->next; + while (curr && (list->compare(desc, &curr[1]) > 0) + ) + curr = curr->next; + } else { + curr = curr->prev; + while (curr && (list->compare(desc, &curr[1]) < 0) + ) + curr = curr->prev; + } + if (curr) { + rcu_assign_pointer(list->hashed[hash].ta_curr, curr); + if (!list->compare(desc, &curr[1])) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +static inline struct rsbac_list_lol_item_t *ta_lookup_lol_item_memcmp_locked(struct + rsbac_list_lol_reg_item_t + *list, + void *desc) +{ + struct rsbac_list_lol_item_t *curr; + u_int hash = 0; + int compres; + + if (unlikely(!list || !desc)) + return NULL; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].ta_curr; + if (!curr) { + curr = list->hashed[hash].ta_head; + if (!curr) + return NULL; + } + /* if current item is not the right one, search... */ + /* note: item desc is behind official struct */ + compres = memcmp(desc, &curr[1], list->info.desc_size); + if (compres) { + if (compres > 0) { + curr = curr->next; + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) > 0) + ) + curr = curr->next; + } else { + curr = curr->prev; + while (curr + && (memcmp(desc, + &curr[1], + list->info.desc_size) < 0) + ) + curr = curr->prev; + } + if (curr) { + rcu_assign_pointer(list->hashed[hash].ta_curr, curr); + if (!memcmp(desc, &curr[1], list->info.desc_size)) + return curr; + } + /* not found */ + return NULL; + } + /* it is the current item -> return it */ + return curr; +} + +static struct rsbac_list_lol_item_t + *ta_lookup_lol_item_locked(const rsbac_list_ta_number_t ta_number, + struct rsbac_list_lol_reg_item_t *list, void *desc) +{ + u_int hash = 0; + + if (unlikely(!list || !desc)) + return NULL; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + if (!list->hashed[hash].ta_copied) + return lookup_lol_item_locked(list, desc); + if (list->hashed[hash].ta_copied != ta_number) + return NULL; + + if (list->compare) + return ta_lookup_lol_item_compare_locked(list, desc); + else + return ta_lookup_lol_item_memcmp_locked(list, desc); +} +#endif + +/* Call RCU locked */ +static inline struct rsbac_list_lol_item_t *lookup_lol_item_data_compare( + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare) +{ + struct rsbac_list_lol_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || compare((char *) curr + sizeof(*curr) + + list->info.desc_size, data) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static inline struct rsbac_list_lol_item_t *lookup_lol_item_data_memcmp( + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + const __u8 hash_bits, + void *data) +{ + struct rsbac_list_lol_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || memcmp(data, + &curr[1] + list->info.desc_size, + list->info.data_size) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static struct rsbac_list_lol_item_t *lookup_lol_item_data( + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare) +{ + if (unlikely(!list || !data || !hashed)) + return NULL; + + if (compare) + return lookup_lol_item_data_compare(list, hashed, hash_bits, data, compare); + else + return lookup_lol_item_data_memcmp(list, hashed, hash_bits, data); +} + +#ifdef CONFIG_RSBAC_LIST_TRANS +/* Call RCU locked */ +static inline struct rsbac_list_lol_item_t *ta_lookup_lol_item_data_compare( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare) +{ + struct rsbac_list_lol_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || compare((char *) curr + sizeof(*curr) + + list->info.desc_size, data) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static inline struct rsbac_list_lol_item_t *ta_lookup_lol_item_data_memcmp( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + const __u8 hash_bits, + void *data) +{ + struct rsbac_list_lol_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || memcmp(data, + &curr[1] + list->info.desc_size, + list->info.data_size) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static struct rsbac_list_lol_item_t *ta_lookup_lol_item_data( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare) +{ + if (unlikely(!list || !data || !hashed)) + return NULL; + + if(!ta_number) + return lookup_lol_item_data(list, hashed, hash_bits, data, compare); + if (compare) + return ta_lookup_lol_item_data_compare(ta_number, list, + hashed, hash_bits, + data, + compare); + else + return ta_lookup_lol_item_data_memcmp(ta_number, list, + hashed, hash_bits, + data); +} +#endif + +/* Call RCU locked */ +static inline struct rsbac_list_lol_item_t *lookup_lol_item_data_compare_selector( + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_lol_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || compare((char *) curr + sizeof(*curr) + + list->info.desc_size, data) + || !selector((char *) curr + sizeof(*curr), param) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static inline struct rsbac_list_lol_item_t *lookup_lol_item_data_memcmp_selector( + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_lol_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + if (unlikely(!list || !data)) + return NULL; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || memcmp(data, + &curr[1] + list->info.desc_size, + list->info.data_size) + || !selector((char *) curr + sizeof(*curr), param) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static struct rsbac_list_lol_item_t *lookup_lol_item_data_selector( + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t + compare, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + if (unlikely(!list || !data || !hashed)) + return NULL; + + if (compare) + return lookup_lol_item_data_compare_selector(list, hashed, hash_bits, data, compare, selector, param); + else + return lookup_lol_item_data_memcmp_selector(list, hashed, hash_bits, data, selector, param); +} + +#ifdef CONFIG_RSBAC_LIST_TRANS +/* Call RCU locked */ +static inline struct rsbac_list_lol_item_t *ta_lookup_lol_item_data_compare_selector( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_lol_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || compare((char *) curr + sizeof(*curr) + + list->info.desc_size, data) + || !selector((char *) curr + sizeof(*curr), param) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static inline struct rsbac_list_lol_item_t *ta_lookup_lol_item_data_memcmp_selector( + const rsbac_list_ta_number_t ta_number, + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_lol_item_t *curr; + int i; + const u_int nr_hashes = 1 << hash_bits; + + for(i=0; imax_age && (curr->max_age <= RSBAC_CURRENT_TIME)) + || memcmp(data, + &curr[1] + list->info.desc_size, + list->info.data_size) + || !selector((char *) curr + sizeof(*curr), param) + ) + ) + curr = rcu_dereference(curr->next); + if(curr) + return curr; + } + return NULL; +} + +/* Call RCU locked */ +static struct rsbac_list_lol_item_t + *ta_lookup_lol_item_data_selector(const rsbac_list_ta_number_t ta_number, + struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_hashed_t * hashed, + const __u8 hash_bits, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + if (unlikely(!list || !data || !hashed)) + return NULL; + + if(likely(!ta_number)) + return lookup_lol_item_data_selector(list, hashed, hash_bits, data, compare, + selector, param); + if (compare) + return ta_lookup_lol_item_data_compare_selector(ta_number, list, + hashed, hash_bits, data, + compare, selector, param); + else + return ta_lookup_lol_item_data_memcmp_selector(ta_number, + list, hashed, hash_bits, + data, selector, param); +} +#endif + +/* Registration lookup */ + +static struct rsbac_list_reg_item_t *lookup_reg(struct rsbac_list_reg_item_t *handle) +{ + struct rsbac_list_reg_item_t *curr = srcu_dereference(reg_head.curr, ®_list_srcu); + + if (unlikely(!handle)) + return NULL; + /* if there is no current item or it is not the right one, search... */ + if (curr != handle) { + curr = srcu_dereference(reg_head.head, ®_list_srcu); + while (curr && curr != handle) + curr = srcu_dereference(curr->next, ®_list_srcu); + if (!curr) + rsbac_pr_debug(lists, + "Lookup of unknown list handle %p\n", + handle); + } + /* it is the current item -> return it */ + return curr; +} + +static struct rsbac_list_reg_item_t *lookup_reg_name(char *name, + kdev_t device) +{ + struct rsbac_list_reg_item_t *curr = srcu_dereference(reg_head.curr, ®_list_srcu); + + if (unlikely(!name)) + return NULL; + /* if there is no current item or it is not the right one, search... */ + if (!curr || (strncmp(curr->name, name, RSBAC_LIST_MAX_FILENAME) + || (RSBAC_MAJOR(curr->device) != RSBAC_MAJOR(device)) + || (RSBAC_MINOR(curr->device) != RSBAC_MINOR(device)) + ) + ) { + curr = srcu_dereference(reg_head.head, ®_list_srcu); + while (curr + && + (strncmp(curr->name, name, RSBAC_LIST_MAX_FILENAME) + || (RSBAC_MAJOR(curr->device) != + RSBAC_MAJOR(device)) + || (RSBAC_MINOR(curr->device) != + RSBAC_MINOR(device)) + ) + ) + curr = srcu_dereference(curr->next, ®_list_srcu); + if (!curr) + rsbac_pr_debug(lists, "Lookup of unknown list name %s " + "on device %02u:%02u\n", name, + RSBAC_MAJOR(device), + RSBAC_MINOR(device)); + } + /* it is the current item -> return it */ + return curr; +} + +/* List of lists registration lookup */ + +static struct rsbac_list_lol_reg_item_t *lookup_lol_reg(struct + rsbac_list_lol_reg_item_t + *handle) +{ + struct rsbac_list_lol_reg_item_t *curr = srcu_dereference(lol_reg_head.curr, &lol_reg_list_srcu); + + if (unlikely(!handle)) + return NULL; + /* if there is no current item or it is not the right one, search... */ + if (curr != handle) { + curr = srcu_dereference(lol_reg_head.head, &lol_reg_list_srcu); + while (curr && curr != handle) + curr = srcu_dereference(curr->next, &lol_reg_list_srcu); + if (!curr) + rsbac_pr_debug(lists, "Lookup of unknown list handle %p\n", + handle); + } + /* it is the current item -> return it */ + return curr; +} + +static struct rsbac_list_lol_reg_item_t *lookup_lol_reg_name(char *name, + kdev_t device) +{ + struct rsbac_list_lol_reg_item_t *curr = srcu_dereference(lol_reg_head.curr, &lol_reg_list_srcu); + + if (unlikely(!name)) + return NULL; + /* if there is no current item or it is not the right one, search... */ + if (!curr || (strncmp(curr->name, name, RSBAC_LIST_MAX_FILENAME) + || (RSBAC_MAJOR(curr->device) != RSBAC_MAJOR(device)) + || (RSBAC_MINOR(curr->device) != RSBAC_MINOR(device)) + ) + ) { + curr = srcu_dereference(lol_reg_head.head, &lol_reg_list_srcu); + while (curr + && + (strncmp(curr->name, name, RSBAC_LIST_MAX_FILENAME) + || (RSBAC_MAJOR(curr->device) != + RSBAC_MAJOR(device)) + || (RSBAC_MINOR(curr->device) != + RSBAC_MINOR(device)) + ) + ) + curr = srcu_dereference(curr->next, &lol_reg_list_srcu); + if (!curr) + rsbac_pr_debug(lists, "Lookup of unknown list name %s " + "on device %02u:%02u\n", name, + RSBAC_MAJOR(device), + RSBAC_MINOR(device)); + } + /* it is the current item -> return it */ + return curr; +} + +/*************/ +/* Add items */ + +/* Call spinlocked */ +static inline struct rsbac_list_item_t *insert_item_compare( + struct rsbac_list_reg_item_t * list, + void *desc, + struct rsbac_list_item_t * new_item_p) +{ + struct rsbac_list_item_t *curr; + u_int hash = 0; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].curr; + if (!curr) + curr = list->hashed[hash].head; + if ((list->compare(desc, &curr[1]) > 0)) { + curr = curr->next; + while (curr && (list->compare(desc, &curr[1]) > 0) + ) + curr = curr->next; + if (curr) { + /* insert before curr */ + new_item_p->prev = curr->prev; + new_item_p->next = curr; + rcu_assign_pointer(curr->prev->next, new_item_p); + rcu_assign_pointer(curr->prev, new_item_p); + } else { + /* insert as last item */ + new_item_p->prev = list->hashed[hash].tail; + new_item_p->next = NULL; + rcu_assign_pointer(list->hashed[hash].tail->next, new_item_p); + rcu_assign_pointer(list->hashed[hash].tail, new_item_p); + } + } else { + curr = curr->prev; + while (curr && (list->compare(desc, &curr[1]) < 0) + ) + curr = curr->prev; + if (curr) { + /* insert after curr */ + new_item_p->prev = curr; + new_item_p->next = curr->next; + rcu_assign_pointer(curr->next->prev, new_item_p); + rcu_assign_pointer(curr->next, new_item_p); + } else { + /* insert as first item */ + new_item_p->prev = NULL; + new_item_p->next = list->hashed[hash].head; + rcu_assign_pointer(list->hashed[hash].head->prev, new_item_p); + rcu_assign_pointer(list->hashed[hash].head, new_item_p); + } + } + list->hashed[hash].count++; + rcu_assign_pointer(list->hashed[hash].curr, new_item_p); + return new_item_p; +} + +/* Call spinlocked */ +static inline struct rsbac_list_item_t *insert_item_memcmp(struct + rsbac_list_reg_item_t + *list, void *desc, + struct + rsbac_list_item_t + *new_item_p) +{ + struct rsbac_list_item_t *curr; + u_int hash = 0; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].curr; + if (!curr) + curr = list->hashed[hash].head; + if (memcmp(desc, &curr[1], list->info.desc_size) > 0) { + curr = curr->next; + while (curr + && (memcmp(desc, + &curr[1], list->info.desc_size) > 0) + ) + curr = curr->next; + if (curr) { + /* insert before curr */ + new_item_p->prev = curr->prev; + new_item_p->next = curr; + rcu_assign_pointer(curr->prev->next, new_item_p); + rcu_assign_pointer(curr->prev, new_item_p); + } else { + /* insert as last item */ + new_item_p->prev = list->hashed[hash].tail; + new_item_p->next = NULL; + rcu_assign_pointer(list->hashed[hash].tail->next, new_item_p); + rcu_assign_pointer(list->hashed[hash].tail, new_item_p); + } + } else { + curr = curr->prev; + while (curr + && (memcmp(desc, + &curr[1], list->info.desc_size) < 0) + ) + curr = curr->prev; + if (curr) { + /* insert after curr */ + new_item_p->prev = curr; + new_item_p->next = curr->next; + rcu_assign_pointer(curr->next->prev, new_item_p); + rcu_assign_pointer(curr->next, new_item_p); + } else { + /* insert as first item */ + new_item_p->prev = NULL; + new_item_p->next = list->hashed[hash].head; + rcu_assign_pointer(list->hashed[hash].head->prev, new_item_p); + rcu_assign_pointer(list->hashed[hash].head, new_item_p); + } + } + list->hashed[hash].count++; + rcu_assign_pointer(list->hashed[hash].curr, new_item_p); + return new_item_p; +} + +/* Call spinlocked */ +static struct rsbac_list_item_t *add_item(struct rsbac_list_reg_item_t + *list, rsbac_time_t max_age, + void *desc, void *data) +{ + struct rsbac_list_item_t *new_item_p = NULL; + u_int hash = 0; + + if (unlikely(!list || !desc)) + return NULL; + if (unlikely(list->info.data_size && !data)) + return NULL; + + /* item desc and data are behind official struct */ + if (list->slab) + new_item_p = rsbac_smalloc(list->slab); + else + new_item_p = rsbac_kmalloc(sizeof(*new_item_p) + + list->info.desc_size + + list->info.data_size); + if (unlikely(!new_item_p)) + return NULL; + + new_item_p->max_age = max_age; + /* item desc is behind official struct */ + memcpy(&new_item_p[1], desc, list->info.desc_size); + /* item data is behind official struct and desc */ + /* data might be empty! */ + if (data && list->info.data_size) + memcpy(((__u8 *) new_item_p) + sizeof(*new_item_p) + + list->info.desc_size, data, list->info.data_size); + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + if (!list->hashed[hash].head) { + new_item_p->prev = NULL; + new_item_p->next = NULL; + rcu_assign_pointer(list->hashed[hash].head, new_item_p); + rcu_assign_pointer(list->hashed[hash].tail, new_item_p); + rcu_assign_pointer(list->hashed[hash].curr, new_item_p); + list->hashed[hash].count = 1; + return new_item_p; + } + if(list->hashed[hash].count >= list->max_items_per_hash) { + rsbac_sfree(list->slab, new_item_p); + if (!(list->flags & RSBAC_LIST_NO_MAX_WARN)) + rsbac_printk(KERN_WARNING "add_item(): cannot add item to list %s, hash %u on device %02u:%02u, would be more than %u items!\n", + list->name, + hash, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + list->max_items_per_hash); + return NULL; + } + if (list->compare) + return insert_item_compare(list, desc, new_item_p); + else + return insert_item_memcmp(list, desc, new_item_p); +} + +#ifdef CONFIG_RSBAC_LIST_TRANS +static void ta_remove_all_items(struct rsbac_list_reg_item_t *list, u_int hash); + +/* Call spinlocked */ +static int ta_copy(const rsbac_list_ta_number_t ta_number, + struct rsbac_list_reg_item_t *list, + u_int hash) +{ + struct rsbac_list_item_t *curr; + struct rsbac_list_item_t *new_item_p; + u_int item_size = sizeof(*new_item_p) + + list->info.desc_size + list->info.data_size; + + /* write access to ta_* is safe for readers as long as ta_copied is not set */ + curr = list->hashed[hash].head; + if (curr) { + if (list->slab) + new_item_p = rsbac_smalloc(list->slab); + else + new_item_p = rsbac_kmalloc(item_size); + if (!new_item_p) { + ta_remove_all_items(list, hash); + return -RSBAC_ENOMEM; + } + memcpy(new_item_p, curr, item_size); + new_item_p->prev = NULL; + new_item_p->next = NULL; + list->hashed[hash].ta_head = new_item_p; + list->hashed[hash].ta_tail = new_item_p; + list->hashed[hash].ta_curr = new_item_p; + list->hashed[hash].ta_count = 1; + curr = curr->next; + } else { + list->hashed[hash].ta_head = NULL; + list->hashed[hash].ta_tail = NULL; + list->hashed[hash].ta_curr = NULL; + list->hashed[hash].ta_count = 0; + list->hashed[hash].ta_copied = ta_number; + return 0; + } + while (curr) { + if (list->slab) + new_item_p = rsbac_smalloc(list->slab); + else + new_item_p = rsbac_kmalloc(item_size); + if (!new_item_p) { + ta_remove_all_items(list, hash); + return -RSBAC_ENOMEM; + } + memcpy(new_item_p, curr, item_size); + new_item_p->prev = list->hashed[hash].ta_tail; + new_item_p->next = NULL; + list->hashed[hash].ta_tail->next = new_item_p; + list->hashed[hash].ta_tail = new_item_p; + list->hashed[hash].ta_count++; + curr = curr->next; + } + list->hashed[hash].ta_copied = ta_number; + return 0; +} + +static void ta_remove_all_lol_items(struct rsbac_list_lol_reg_item_t *list, + u_int hash); + +/* Call spinlocked */ +static int ta_lol_copy(const rsbac_list_ta_number_t ta_number, + struct rsbac_list_lol_reg_item_t *list, + u_int hash) +{ + struct rsbac_list_lol_item_t *curr; + struct rsbac_list_lol_item_t *new_item_p; + struct rsbac_list_item_t *sub_curr; + struct rsbac_list_item_t *new_subitem_p; + u_int item_size = sizeof(*new_item_p) + + list->info.desc_size + list->info.data_size; + u_int subitem_size = sizeof(*new_subitem_p) + + list->info.subdesc_size + list->info.subdata_size; + + /* write access to ta_* is safe for readers as long as ta_copied is not set */ + list->hashed[hash].ta_head = NULL; + list->hashed[hash].ta_tail = NULL; + list->hashed[hash].ta_curr = NULL; + list->hashed[hash].ta_count = 0; + + curr = list->hashed[hash].head; + while (curr) { + if (list->slab) + new_item_p = rsbac_smalloc(list->slab); + else + new_item_p = rsbac_kmalloc(item_size); + if (!new_item_p) { + ta_remove_all_lol_items(list, hash); + return -RSBAC_ENOMEM; + } + memcpy(new_item_p, curr, item_size); + new_item_p->head = NULL; + new_item_p->tail = NULL; + new_item_p->curr = NULL; + new_item_p->count = 0; + new_item_p->prev = NULL; + new_item_p->next = NULL; + sub_curr = curr->head; + while (sub_curr) { + if (list->subslab) + new_subitem_p = rsbac_smalloc(list->subslab); + else + new_subitem_p = rsbac_kmalloc(subitem_size); + if (!new_subitem_p) { + ta_remove_all_lol_items(list, hash); + rsbac_sfree(list->slab, new_item_p); + return -RSBAC_ENOMEM; + } + memcpy(new_subitem_p, sub_curr, subitem_size); + new_subitem_p->prev = NULL; + new_subitem_p->next = NULL; + if (new_item_p->tail) { + new_subitem_p->prev = new_item_p->tail; + new_item_p->tail->next = new_subitem_p; + new_item_p->tail = new_subitem_p; + new_item_p->count++; + } else { + new_item_p->head = new_subitem_p; + new_item_p->tail = new_subitem_p; + new_item_p->count = 1; + } + sub_curr = sub_curr->next; + } + if (list->hashed[hash].ta_tail) { + new_item_p->prev = list->hashed[hash].ta_tail; + list->hashed[hash].ta_tail->next = new_item_p; + list->hashed[hash].ta_tail= new_item_p; + list->hashed[hash].ta_count++; + } else { + list->hashed[hash].ta_head = new_item_p; + list->hashed[hash].ta_tail = new_item_p; + list->hashed[hash].ta_curr = new_item_p; + list->hashed[hash].ta_count = 1; + } + curr = curr->next; + } + list->hashed[hash].ta_copied = ta_number; + return 0; +} + +/* Call spinlocked */ +static inline struct rsbac_list_item_t *ta_insert_item_compare(struct + rsbac_list_reg_item_t + *list, void *desc, + struct + rsbac_list_item_t + *new_item_p) +{ + struct rsbac_list_item_t *curr; + u_int hash = 0; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].ta_curr; + if (!curr) + curr = list->hashed[hash].ta_head; + if ((list->compare(desc, &curr[1]) > 0)) { + curr = curr->next; + while (curr && (list->compare(desc, &curr[1]) > 0) + ) + curr = curr->next; + if (curr) { + /* insert before curr */ + new_item_p->prev = curr->prev; + new_item_p->next = curr; + rcu_assign_pointer(curr->prev->next, new_item_p); + rcu_assign_pointer(curr->prev, new_item_p); + } else { + /* insert as last item */ + new_item_p->prev = list->hashed[hash].ta_tail; + new_item_p->next = NULL; + rcu_assign_pointer(list->hashed[hash].ta_tail->next, new_item_p); + rcu_assign_pointer(list->hashed[hash].ta_tail, new_item_p); + } + } else { + curr = curr->prev; + while (curr && (list->compare(desc, &curr[1]) < 0) + ) + curr = curr->prev; + if (curr) { + /* insert after curr */ + new_item_p->prev = curr; + new_item_p->next = curr->next; + rcu_assign_pointer(curr->next->prev, new_item_p); + rcu_assign_pointer(curr->next, new_item_p); + } else { + /* insert as first item */ + new_item_p->prev = NULL; + new_item_p->next = list->hashed[hash].ta_head; + rcu_assign_pointer(list->hashed[hash].ta_head->prev, new_item_p); + rcu_assign_pointer(list->hashed[hash].ta_head, new_item_p); + } + } + list->hashed[hash].ta_count++; + rcu_assign_pointer(list->hashed[hash].ta_curr, new_item_p); + return new_item_p; +} + +/* Call spinlocked */ +static inline struct rsbac_list_item_t *ta_insert_item_memcmp(struct + rsbac_list_reg_item_t + *list, void *desc, + struct + rsbac_list_item_t + *new_item_p) +{ + struct rsbac_list_item_t *curr; + u_int hash = 0; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].ta_curr; + if (!curr) + curr = list->hashed[hash].ta_head; + if (memcmp(desc, &curr[1], list->info.desc_size) > 0) { + curr = curr->next; + while (curr + && (memcmp(desc, + &curr[1], list->info.desc_size) > 0) + ) + curr = curr->next; + if (curr) { + /* insert before curr */ + new_item_p->prev = curr->prev; + new_item_p->next = curr; + rcu_assign_pointer(curr->prev->next, new_item_p); + rcu_assign_pointer(curr->prev, new_item_p); + } else { + /* insert as last item */ + new_item_p->prev = list->hashed[hash].ta_tail; + new_item_p->next = NULL; + rcu_assign_pointer(list->hashed[hash].ta_tail->next, new_item_p); + rcu_assign_pointer(list->hashed[hash].ta_tail, new_item_p); + } + } else { + curr = curr->prev; + while (curr + && (memcmp(desc, + &curr[1], list->info.desc_size) < 0) + ) + curr = curr->prev; + if (curr) { + /* insert after curr */ + new_item_p->prev = curr; + new_item_p->next = curr->next; + rcu_assign_pointer(curr->next->prev, new_item_p); + rcu_assign_pointer(curr->next, new_item_p); + } else { + /* insert as first item */ + new_item_p->prev = NULL; + new_item_p->next = list->hashed[hash].ta_head; + rcu_assign_pointer(list->hashed[hash].ta_head->prev, new_item_p); + rcu_assign_pointer(list->hashed[hash].ta_head, new_item_p); + } + } + list->hashed[hash].ta_count++; + rcu_assign_pointer(list->hashed[hash].ta_curr, new_item_p); + return new_item_p; +} + +/* Call spinlocked */ +static struct rsbac_list_item_t *ta_add_item(const rsbac_list_ta_number_t + ta_number, + struct rsbac_list_reg_item_t + *list, rsbac_time_t max_age, + void *desc, void *data) +{ + struct rsbac_list_item_t *new_item_p = NULL; + u_int hash = 0; + + if (unlikely(!list || !desc)) + return NULL; + if (unlikely(list->info.data_size && !data)) + return NULL; + if (!ta_number) + return add_item(list, max_age, desc, data); + /* item desc and data are behind official struct */ + if (list->slab) + new_item_p = rsbac_smalloc(list->slab); + else + new_item_p = rsbac_kmalloc(sizeof(*new_item_p) + + list->info.desc_size + + list->info.data_size); + if (unlikely(!new_item_p)) + return NULL; + new_item_p->max_age = max_age; + /* item desc is behind official struct */ + memcpy(&new_item_p[1], desc, list->info.desc_size); + /* item data is behind official struct and desc */ + /* data might be empty! */ + if (data && list->info.data_size) + memcpy(((__u8 *) new_item_p) + sizeof(*new_item_p) + + list->info.desc_size, data, list->info.data_size); + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + if (!list->hashed[hash].ta_copied) { /* copy list to ta_list */ + if (ta_copy(ta_number, list, hash)) { + rsbac_sfree(list->slab, new_item_p); + return NULL; + } + } else { + if (list->hashed[hash].ta_copied != ta_number) { + rsbac_sfree(list->slab, new_item_p); + return NULL; + } + } + + if (!list->hashed[hash].ta_head) { + new_item_p->prev = NULL; + new_item_p->next = NULL; + rcu_assign_pointer(list->hashed[hash].ta_head, new_item_p); + rcu_assign_pointer(list->hashed[hash].ta_tail, new_item_p); + rcu_assign_pointer(list->hashed[hash].ta_curr, new_item_p); + list->hashed[hash].ta_count = 1; + return new_item_p; + } + if (list->hashed[hash].ta_count >= list->max_items_per_hash) { + rsbac_sfree(list->slab, new_item_p); + if (!(list->flags & RSBAC_LIST_NO_MAX_WARN)) + rsbac_printk(KERN_WARNING "ta_add_item(): cannot add item to list %s, hash %u on device %02u:%02u, would be more than %u items!\n", + list->name, + hash, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + list->max_items_per_hash); + return NULL; + } + if (list->compare) + return ta_insert_item_compare(list, desc, new_item_p); + else + return ta_insert_item_memcmp(list, desc, new_item_p); +} +#endif + + +/* Call spinlocked */ +static inline struct rsbac_list_item_t *insert_lol_subitem_compare(struct + rsbac_list_lol_reg_item_t + *list, + struct + rsbac_list_lol_item_t + *sublist, + void *subdesc, + struct + rsbac_list_item_t + *new_item_p) +{ + struct rsbac_list_item_t *curr; + + curr = sublist->curr; + if (!curr) + curr = sublist->head; + if ((list->subcompare(subdesc, &curr[1]) > 0)) { + curr = curr->next; + while (curr && (list->subcompare(subdesc, &curr[1]) > 0) + ) + curr = curr->next; + if (curr) { + /* insert before curr */ + new_item_p->prev = curr->prev; + new_item_p->next = curr; + rcu_assign_pointer(curr->prev->next, new_item_p); + rcu_assign_pointer(curr->prev, new_item_p); + } else { + /* insert as last item */ + new_item_p->prev = sublist->tail; + new_item_p->next = NULL; + rcu_assign_pointer(sublist->tail->next, new_item_p); + rcu_assign_pointer(sublist->tail, new_item_p); + } + } else { + curr = curr->prev; + while (curr && (list->subcompare(subdesc, &curr[1]) < 0) + ) + curr = curr->prev; + if (curr) { + /* insert after curr */ + new_item_p->prev = curr; + new_item_p->next = curr->next; + rcu_assign_pointer(curr->next->prev, new_item_p); + rcu_assign_pointer(curr->next, new_item_p); + } else { + /* insert as first item */ + new_item_p->prev = NULL; + new_item_p->next = sublist->head; + rcu_assign_pointer(sublist->head->prev, new_item_p); + rcu_assign_pointer(sublist->head, new_item_p); + } + } + sublist->count++; + rcu_assign_pointer(sublist->curr, new_item_p); + return new_item_p; +} + +/* Call spinlocked */ +static inline struct rsbac_list_item_t *insert_lol_subitem_memcmp(struct + rsbac_list_lol_reg_item_t + *list, + struct + rsbac_list_lol_item_t + *sublist, + void *subdesc, + struct + rsbac_list_item_t + *new_item_p) +{ + struct rsbac_list_item_t *curr; + + curr = sublist->curr; + if (!curr) + curr = sublist->head; + if (memcmp(subdesc, &curr[1], list->info.subdesc_size) > 0) { + curr = curr->next; + while (curr + && (memcmp(subdesc, + &curr[1], list->info.subdesc_size) > 0) + ) + curr = curr->next; + if (curr) { + /* insert before curr */ + new_item_p->prev = curr->prev; + new_item_p->next = curr; + rcu_assign_pointer(curr->prev->next, new_item_p); + rcu_assign_pointer(curr->prev, new_item_p); + } else { + /* insert as last item */ + new_item_p->prev = sublist->tail; + new_item_p->next = NULL; + rcu_assign_pointer(sublist->tail->next, new_item_p); + rcu_assign_pointer(sublist->tail, new_item_p); + } + } else { + curr = curr->prev; + while (curr + && (memcmp(subdesc, + &curr[1], list->info.subdesc_size) < 0) + ) + curr = curr->prev; + if (curr) { + /* insert after curr */ + new_item_p->prev = curr; + new_item_p->next = curr->next; + rcu_assign_pointer(curr->next->prev, new_item_p); + rcu_assign_pointer(curr->next, new_item_p); + } else { + /* insert as first item */ + new_item_p->prev = NULL; + new_item_p->next = sublist->head; + rcu_assign_pointer(sublist->head->prev, new_item_p); + rcu_assign_pointer(sublist->head, new_item_p); + } + } + sublist->count++; + rcu_assign_pointer(sublist->curr, new_item_p); + return new_item_p; +} + +/* Call spinlocked */ +static struct rsbac_list_item_t *add_lol_subitem(struct + rsbac_list_lol_reg_item_t + *list, + struct + rsbac_list_lol_item_t + *sublist, + rsbac_time_t max_age, + void *subdesc, + void *subdata) +{ + struct rsbac_list_item_t *new_item_p = NULL; + + if (unlikely(!list || !sublist || !subdesc)) + return NULL; + if (unlikely(list->info.subdata_size && !subdata)) + return NULL; + /* item desc and data are behind official struct */ + if (list->subslab) + new_item_p = rsbac_smalloc(list->subslab); + else + new_item_p = rsbac_kmalloc(sizeof(*new_item_p) + + list->info.subdesc_size + + list->info.subdata_size); + if (unlikely(!new_item_p)) + return NULL; + + new_item_p->max_age = max_age; + /* item desc is behind official struct */ + memcpy(&new_item_p[1], subdesc, list->info.subdesc_size); + /* item data is behind official struct and desc */ + /* subdata might be empty! */ + if (subdata && list->info.subdata_size) + memcpy(((__u8 *) new_item_p) + sizeof(*new_item_p) + + list->info.subdesc_size, subdata, + list->info.subdata_size); + + /* Sublist was empty */ + if (!sublist->head) { + new_item_p->prev = NULL; + new_item_p->next = NULL; + rcu_assign_pointer(sublist->head, new_item_p); + rcu_assign_pointer(sublist->tail, new_item_p); + rcu_assign_pointer(sublist->curr, new_item_p); + sublist->count = 1; + return new_item_p; + } + if (sublist->count >= list->max_subitems) { + rsbac_sfree(list->slab, new_item_p); + if (!(list->flags & RSBAC_LIST_NO_MAX_WARN)) + rsbac_printk(KERN_WARNING "add_lol_subitem(): cannot add subitem to sublist of %s on device %02u:%02u, would be more than %u subitems!\n", + list->name, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + list->max_subitems); + return NULL; + } + if (list->subcompare) + return insert_lol_subitem_compare(list, sublist, subdesc, + new_item_p); + else + return insert_lol_subitem_memcmp(list, sublist, subdesc, + new_item_p); +} + +/* Call spinlocked */ +static inline struct rsbac_list_lol_item_t *insert_lol_item_compare(struct + rsbac_list_lol_reg_item_t + *list, + void *desc, + struct + rsbac_list_lol_item_t + *new_item_p) +{ + struct rsbac_list_lol_item_t *curr; + u_int hash = 0; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].curr; + if (!curr) + curr = list->hashed[hash].head; + if ((list->compare(desc, &curr[1]) > 0)) { + curr = curr->next; + while (curr && (list->compare(desc, &curr[1]) > 0) + ) + curr = curr->next; + if (curr) { + /* insert before curr */ + new_item_p->prev = curr->prev; + new_item_p->next = curr; + rcu_assign_pointer(curr->prev->next, new_item_p); + rcu_assign_pointer(curr->prev, new_item_p); + } else { + /* insert as last item */ + new_item_p->prev = list->hashed[hash].tail; + new_item_p->next = NULL; + rcu_assign_pointer(list->hashed[hash].tail->next, new_item_p); + rcu_assign_pointer(list->hashed[hash].tail, new_item_p); + } + } else { + curr = curr->prev; + while (curr && (list->compare(desc, &curr[1]) < 0) + ) + curr = curr->prev; + if (curr) { + /* insert after curr */ + new_item_p->prev = curr; + new_item_p->next = curr->next; + rcu_assign_pointer(curr->next->prev, new_item_p); + rcu_assign_pointer(curr->next, new_item_p); + } else { + /* insert as first item */ + new_item_p->prev = NULL; + new_item_p->next = list->hashed[hash].head; + rcu_assign_pointer(list->hashed[hash].head->prev, new_item_p); + rcu_assign_pointer(list->hashed[hash].head, new_item_p); + } + } + list->hashed[hash].count++; + rcu_assign_pointer(list->hashed[hash].curr, new_item_p); + return new_item_p; +} + +/* Call spinlocked */ +static inline struct rsbac_list_lol_item_t *insert_lol_item_memcmp(struct + rsbac_list_lol_reg_item_t + *list, + void *desc, + struct + rsbac_list_lol_item_t + *new_item_p) +{ + struct rsbac_list_lol_item_t *curr; + u_int hash = 0; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].curr; + if (!curr) + curr = list->hashed[hash].head; + if (memcmp(desc, &curr[1], list->info.desc_size) > 0) { + curr = curr->next; + while (curr + && (memcmp(desc, + &curr[1], list->info.desc_size) > 0) + ) + curr = curr->next; + if (curr) { + /* insert before curr */ + new_item_p->prev = curr->prev; + new_item_p->next = curr; + rcu_assign_pointer(curr->prev->next, new_item_p); + rcu_assign_pointer(curr->prev, new_item_p); + } else { + /* insert as last item */ + new_item_p->prev = list->hashed[hash].tail; + new_item_p->next = NULL; + rcu_assign_pointer(list->hashed[hash].tail->next, new_item_p); + rcu_assign_pointer(list->hashed[hash].tail, new_item_p); + } + } else { + curr = curr->prev; + while (curr + && (memcmp(desc, + &curr[1], list->info.desc_size) < 0) + ) + curr = curr->prev; + if (curr) { + /* insert after curr */ + new_item_p->prev = curr; + new_item_p->next = curr->next; + rcu_assign_pointer(curr->next->prev, new_item_p); + rcu_assign_pointer(curr->next, new_item_p); + } else { + /* insert as first item */ + new_item_p->prev = NULL; + new_item_p->next = list->hashed[hash].head; + rcu_assign_pointer(list->hashed[hash].head->prev, new_item_p); + rcu_assign_pointer(list->hashed[hash].head, new_item_p); + } + } + list->hashed[hash].count++; + rcu_assign_pointer(list->hashed[hash].curr, new_item_p); + return new_item_p; +} + +/* Call spinlocked */ +static struct rsbac_list_lol_item_t *add_lol_item(struct + rsbac_list_lol_reg_item_t + *list, + rsbac_time_t max_age, + void *desc, void *data) +{ + struct rsbac_list_lol_item_t *new_item_p = NULL; + u_int hash = 0; + + if (unlikely(!list || !desc)) + return NULL; + if (unlikely(list->info.data_size && !data)) + return NULL; + /* item desc and data are behind official struct */ + if (list->slab) + new_item_p = rsbac_smalloc(list->slab); + else + new_item_p = rsbac_kmalloc(sizeof(*new_item_p) + + list->info.desc_size + + list->info.data_size); + if (unlikely(!new_item_p)) + return NULL; + + /* Init sublist */ + new_item_p->head = NULL; + new_item_p->tail = NULL; + new_item_p->curr = NULL; + new_item_p->count = 0; + new_item_p->max_age = max_age; + /* item desc is behind official struct */ + memcpy(&new_item_p[1], desc, list->info.desc_size); + /* item data is behind official struct and desc */ + /* data might be empty! */ + if (data && list->info.data_size) + memcpy(((__u8 *) new_item_p) + sizeof(*new_item_p) + + list->info.desc_size, data, list->info.data_size); + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + if (!list->hashed[hash].head) { + new_item_p->prev = NULL; + new_item_p->next = NULL; + rcu_assign_pointer(list->hashed[hash].head, new_item_p); + rcu_assign_pointer(list->hashed[hash].tail, new_item_p); + rcu_assign_pointer(list->hashed[hash].curr, new_item_p); + list->hashed[hash].count = 1; + return new_item_p; + } + if (list->hashed[hash].count >= list->max_items_per_hash) { + rsbac_sfree(list->slab, new_item_p); + if (!(list->flags & RSBAC_LIST_NO_MAX_WARN)) + rsbac_printk(KERN_WARNING "add_lol_item(): cannot add item to list %s, hash %u on device %02u:%02u, would be more than %u items!\n", + list->name, + hash, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + list->max_items_per_hash); + return NULL; + } + if (list->compare) + return insert_lol_item_compare(list, desc, new_item_p); + else + return insert_lol_item_memcmp(list, desc, new_item_p); +} + +#ifdef CONFIG_RSBAC_LIST_TRANS +/* Call spinlocked */ +static inline struct rsbac_list_lol_item_t *ta_insert_lol_item_compare(struct + rsbac_list_lol_reg_item_t + *list, + void *desc, + struct + rsbac_list_lol_item_t + *new_item_p) +{ + struct rsbac_list_lol_item_t *curr; + u_int hash = 0; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].ta_curr; + if (!curr) + curr = list->hashed[hash].ta_head; + if ((list->compare(desc, &curr[1]) > 0)) { + curr = curr->next; + while (curr && (list->compare(desc, &curr[1]) > 0) + ) + curr = curr->next; + if (curr) { + /* insert before curr */ + new_item_p->prev = curr->prev; + new_item_p->next = curr; + rcu_assign_pointer(curr->prev->next, new_item_p); + rcu_assign_pointer(curr->prev, new_item_p); + } else { + /* insert as last item */ + new_item_p->prev = list->hashed[hash].ta_tail; + new_item_p->next = NULL; + rcu_assign_pointer(list->hashed[hash].ta_tail->next, new_item_p); + rcu_assign_pointer(list->hashed[hash].ta_tail, new_item_p); + } + } else { + curr = curr->prev; + while (curr && (list->compare(desc, &curr[1]) < 0) + ) + curr = curr->prev; + if (curr) { + /* insert after curr */ + new_item_p->prev = curr; + new_item_p->next = curr->next; + rcu_assign_pointer(curr->next->prev, new_item_p); + rcu_assign_pointer(curr->next, new_item_p); + } else { + /* insert as first item */ + new_item_p->prev = NULL; + new_item_p->next = list->hashed[hash].ta_head; + rcu_assign_pointer(list->hashed[hash].ta_head->prev, new_item_p); + rcu_assign_pointer(list->hashed[hash].ta_head, new_item_p); + } + } + list->hashed[hash].ta_count++; + rcu_assign_pointer(list->hashed[hash].ta_curr, new_item_p); + return new_item_p; +} + +/* Call spinlocked */ +static inline struct rsbac_list_lol_item_t *ta_insert_lol_item_memcmp(struct + rsbac_list_lol_reg_item_t + *list, + void *desc, + struct + rsbac_list_lol_item_t + *new_item_p) +{ + struct rsbac_list_lol_item_t *curr; + u_int hash = 0; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + curr = list->hashed[hash].ta_curr; + if (!curr) + curr = list->hashed[hash].ta_head; + if (memcmp(desc, &curr[1], list->info.desc_size) > 0) { + curr = curr->next; + while (curr + && (memcmp(desc, + &curr[1], list->info.desc_size) > 0) + ) + curr = curr->next; + if (curr) { + /* insert before curr */ + new_item_p->prev = curr->prev; + new_item_p->next = curr; + rcu_assign_pointer(curr->prev->next, new_item_p); + rcu_assign_pointer(curr->prev, new_item_p); + } else { + /* insert as last item */ + new_item_p->prev = list->hashed[hash].ta_tail; + new_item_p->next = NULL; + rcu_assign_pointer(list->hashed[hash].ta_tail->next, new_item_p); + rcu_assign_pointer(list->hashed[hash].ta_tail, new_item_p); + } + } else { + curr = curr->prev; + while (curr + && (memcmp(desc, + &curr[1], list->info.desc_size) < 0) + ) + curr = curr->prev; + if (curr) { + /* insert after curr */ + new_item_p->prev = curr; + new_item_p->next = curr->next; + rcu_assign_pointer(curr->next->prev, new_item_p); + rcu_assign_pointer(curr->next, new_item_p); + } else { + /* insert as first item */ + new_item_p->prev = NULL; + new_item_p->next = list->hashed[hash].ta_head; + rcu_assign_pointer(list->hashed[hash].ta_head->prev, new_item_p); + rcu_assign_pointer(list->hashed[hash].ta_head, new_item_p); + } + } + list->hashed[hash].ta_count++; + rcu_assign_pointer(list->hashed[hash].ta_curr, new_item_p); + return new_item_p; +} + +/* Call spinlocked */ +static struct rsbac_list_lol_item_t *ta_add_lol_item(const rsbac_list_ta_number_t + ta_number, + struct + rsbac_list_lol_reg_item_t + *list, + rsbac_time_t max_age, + void *desc, + void *data) +{ + struct rsbac_list_lol_item_t *new_item_p = NULL; + u_int hash = 0; + + if (unlikely(!list || !desc)) + return NULL; + if (unlikely(list->info.data_size && !data)) + return NULL; + if (!ta_number) + return add_lol_item(list, max_age, desc, data); + /* item desc and data are behind official struct */ + if (list->slab) + new_item_p = rsbac_smalloc(list->slab); + else + new_item_p = rsbac_kmalloc(sizeof(*new_item_p) + + list->info.desc_size + + list->info.data_size); + if (unlikely(!new_item_p)) + return NULL; + + /* Init sublist */ + new_item_p->head = NULL; + new_item_p->tail = NULL; + new_item_p->curr = NULL; + new_item_p->count = 0; + new_item_p->max_age = max_age; + new_item_p->prev = NULL; + new_item_p->next = NULL; + /* item desc is behind official struct */ + memcpy(&new_item_p[1], desc, list->info.desc_size); + /* item data is behind official struct and desc */ + /* data might be empty! */ + if (data && list->info.data_size) + memcpy(((__u8 *) new_item_p) + sizeof(*new_item_p) + + list->info.desc_size, data, list->info.data_size); + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + if (!list->hashed[hash].ta_copied) { /* copy list to ta_list */ + if (ta_lol_copy(ta_number, list, hash)) { + rsbac_sfree(list->slab, new_item_p); + return NULL; + } + } else { + if (list->hashed[hash].ta_copied != ta_number) { + rsbac_sfree(list->slab, new_item_p); + return NULL; + } + } + + if (!list->hashed[hash].ta_head) { + rcu_assign_pointer(list->hashed[hash].ta_head, new_item_p); + rcu_assign_pointer(list->hashed[hash].ta_tail, new_item_p); + rcu_assign_pointer(list->hashed[hash].ta_curr, new_item_p); + list->hashed[hash].ta_count = 1; + return (new_item_p); + } + if (list->hashed[hash].ta_count >= list->max_items_per_hash) { + rsbac_sfree(list->slab, new_item_p); + if (!(list->flags & RSBAC_LIST_NO_MAX_WARN)) + rsbac_printk(KERN_WARNING "ta_add_lol_item(): cannot add item to list %s, hash %u on device %02u:%02u, would be more than %u items!\n", + list->name, + hash, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + list->max_items_per_hash); + return NULL; + } + if (list->compare) + return ta_insert_lol_item_compare(list, desc, new_item_p); + else + return ta_insert_lol_item_memcmp(list, desc, new_item_p); +} +#endif + +/* Add registration items */ + +/* no locking needed */ +static inline struct rsbac_list_reg_item_t *create_reg( + struct rsbac_list_info_t *info_p, + u_int flags, + rsbac_list_compare_function_t * compare, + rsbac_list_get_conv_t * get_conv, + void *def_data, + char *name, + kdev_t device, + const __u8 hash_bits, + rsbac_list_hash_function_t hash_function, + char * old_name_base) +{ + struct rsbac_list_reg_item_t *new_item_p = NULL; + const u_int nr_hashes = 1 << hash_bits; + + if (!(new_item_p = rsbac_smalloc_clear_unlocked(reg_item_slab))) + return NULL; + if (!(new_item_p->hashed = rsbac_kmalloc_clear_unlocked(nr_hashes*sizeof(struct rsbac_list_hashed_t)))) { + rsbac_sfree(reg_item_slab, new_item_p); + return NULL; + } + new_item_p->info = *info_p; + if (!def_data) + flags &= ~RSBAC_LIST_DEF_DATA; + new_item_p->flags = flags; + new_item_p->compare = compare; + new_item_p->get_conv = get_conv; + new_item_p->rcu_free = NULL; + if (flags & RSBAC_LIST_DEF_DATA) { + new_item_p->def_data = rsbac_kmalloc_unlocked(info_p->data_size); + if (new_item_p->def_data) + memcpy(new_item_p->def_data, def_data, + info_p->data_size); + else { + rsbac_kfree(new_item_p->hashed); + rsbac_sfree(reg_item_slab, new_item_p); + return NULL; + } + } else + new_item_p->def_data = NULL; + if (name) { + strncpy(new_item_p->name, name, RSBAC_LIST_MAX_FILENAME); + new_item_p->name[RSBAC_LIST_MAX_FILENAME] = 0; + } else { + strcpy(new_item_p->name, RSBAC_LIST_NONAME); + } + new_item_p->hash_bits = hash_bits; + if (flags & RSBAC_LIST_NO_MAX) + new_item_p->max_items_per_hash = RSBAC_LIST_MAX_NR_ITEMS_LIMIT; + else + new_item_p->max_items_per_hash = RSBAC_LIST_MAX_NR_ITEMS; + new_item_p->hash_function = hash_function; + if (old_name_base) { + strncpy(new_item_p->old_name_base, old_name_base, RSBAC_LIST_MAX_FILENAME); + new_item_p->old_name_base[RSBAC_LIST_MAX_FILENAME] = 0; + } else { + new_item_p->old_name_base[0] = 0; + } + new_item_p->device = device; + spin_lock_init(&new_item_p->lock); + if (flags & RSBAC_LIST_OWN_SLAB) { + new_item_p->slabname = rsbac_kmalloc(RSBAC_MAX_SLABNAME); + if (!new_item_p->slabname) { + rsbac_kfree(new_item_p->hashed); + rsbac_sfree(reg_item_slab, new_item_p); + if (new_item_p->def_data) + rsbac_kfree(new_item_p->def_data); + return NULL; + } + if (device != RSBAC_AUTO_DEV) { + snprintf(new_item_p->slabname, + RSBAC_MAX_SLABNAME, + "%s-%02u:%02u", + name, + RSBAC_MAJOR(device), RSBAC_MINOR(device)); + } else { + strncpy(new_item_p->slabname, name, RSBAC_MAX_SLABNAME); + } + new_item_p->slabname[RSBAC_MAX_SLABNAME - 1] = 0; + new_item_p->slab = rsbac_slab_create_rcu(new_item_p->slabname, + sizeof(struct rsbac_list_item_t) + info_p->desc_size + info_p->data_size); + } else { + new_item_p->slabname = NULL; + new_item_p->slab = NULL; + } + lockdep_set_class(&new_item_p->lock, &list_lock_class); + new_item_p->dirty = FALSE; + if (flags & RSBAC_LIST_NO_WRITE) + new_item_p->no_write = TRUE; + else + new_item_p->no_write = FALSE; + new_item_p->self = new_item_p; + return new_item_p; +} + +/* locking needed */ +static struct rsbac_list_reg_item_t *add_reg(struct rsbac_list_reg_item_t + *new_item_p) +{ + if (!reg_head.head) { + new_item_p->prev = NULL; + new_item_p->next = NULL; + rcu_assign_pointer(reg_head.head, new_item_p); + rcu_assign_pointer(reg_head.tail, new_item_p); + rcu_assign_pointer(reg_head.curr, new_item_p); + reg_head.count = 1; + } else { + new_item_p->prev = reg_head.tail; + new_item_p->next = NULL; + rcu_assign_pointer(reg_head.tail->next, new_item_p); + rcu_assign_pointer(reg_head.tail, new_item_p); + rcu_assign_pointer(reg_head.curr, new_item_p); + reg_head.count++; + } + return new_item_p; +} + +/* no locking needed */ +static inline struct rsbac_list_lol_reg_item_t *create_lol_reg( + struct rsbac_list_lol_info_t *info_p, + u_int flags, + rsbac_list_compare_function_t *compare, + rsbac_list_compare_function_t *subcompare, + rsbac_list_get_conv_t *get_conv, + rsbac_list_get_conv_t *get_subconv, + void *def_data, + void *def_subdata, + char *name, + kdev_t device, + const __u8 hash_bits, + rsbac_list_hash_function_t hash_function, + char * old_name_base) +{ + struct rsbac_list_lol_reg_item_t *new_item_p = NULL; + const u_int nr_hashes = 1 << hash_bits; + + if (!(new_item_p = rsbac_smalloc_clear_unlocked(lol_reg_item_slab))) + return NULL; + if (!(new_item_p->hashed = rsbac_kmalloc_clear_unlocked(nr_hashes*sizeof(struct rsbac_list_lol_hashed_t)))) { + rsbac_sfree(lol_reg_item_slab, new_item_p); + return NULL; + } + new_item_p->info = *info_p; + if (info_p->data_size && !def_data) + flags &= ~RSBAC_LIST_DEF_DATA; + if (!def_subdata) + flags &= ~RSBAC_LIST_DEF_SUBDATA; + new_item_p->flags = flags; + new_item_p->compare = compare; + new_item_p->subcompare = subcompare; + new_item_p->get_conv = get_conv; + new_item_p->get_subconv = get_subconv; + new_item_p->rcu_free = NULL; + if ((flags & RSBAC_LIST_DEF_DATA) + && (info_p->data_size) + ) { + new_item_p->def_data = rsbac_kmalloc_unlocked(info_p->data_size); + if (new_item_p->def_data) + memcpy(new_item_p->def_data, def_data, + info_p->data_size); + else { + rsbac_kfree(new_item_p->hashed); + rsbac_sfree(lol_reg_item_slab, new_item_p); + return NULL; + } + } else + new_item_p->def_data = NULL; + if ((flags & RSBAC_LIST_DEF_SUBDATA) + && (info_p->subdata_size) + ) { + new_item_p->def_subdata = + rsbac_kmalloc_unlocked(info_p->subdata_size); + if (new_item_p->def_subdata) + memcpy(new_item_p->def_subdata, def_subdata, + info_p->subdata_size); + else { + if (new_item_p->def_data) + rsbac_kfree(new_item_p->def_data); + rsbac_kfree(new_item_p->hashed); + rsbac_sfree(lol_reg_item_slab, new_item_p); + return NULL; + } + } else + new_item_p->def_subdata = NULL; + if (name) { + strncpy(new_item_p->name, name, RSBAC_LIST_MAX_FILENAME); + new_item_p->name[RSBAC_LIST_MAX_FILENAME] = 0; + } else { + strcpy(new_item_p->name, RSBAC_LIST_NONAME); + } + new_item_p->hash_bits = hash_bits; + if (flags & RSBAC_LIST_NO_MAX) { + new_item_p->max_items_per_hash = RSBAC_LIST_MAX_NR_ITEMS_LIMIT; + new_item_p->max_subitems = RSBAC_LIST_MAX_NR_ITEMS_LIMIT; + } else { + new_item_p->max_items_per_hash = RSBAC_LIST_MAX_NR_ITEMS; + new_item_p->max_subitems = RSBAC_LIST_MAX_NR_SUBITEMS; + } + new_item_p->hash_function = hash_function; + if (old_name_base) { + strncpy(new_item_p->old_name_base, old_name_base, RSBAC_LIST_MAX_FILENAME); + new_item_p->old_name_base[RSBAC_LIST_MAX_FILENAME] = 0; + } else + new_item_p->old_name_base[0] = 0; + new_item_p->device = device; + spin_lock_init(&new_item_p->lock); + if (flags & RSBAC_LIST_OWN_SLAB) { + new_item_p->slabname = rsbac_kmalloc(RSBAC_MAX_SLABNAME); + if (!new_item_p->slabname) { + rsbac_kfree(new_item_p->hashed); + rsbac_sfree(lol_reg_item_slab, new_item_p); + if (new_item_p->def_data) + rsbac_kfree(new_item_p->def_data); + if (new_item_p->def_subdata) + rsbac_kfree(new_item_p->def_subdata); + return NULL; + } + new_item_p->subslabname = rsbac_kmalloc(RSBAC_MAX_SLABNAME); + if (!new_item_p->subslabname) { + rsbac_kfree(new_item_p->hashed); + rsbac_sfree(lol_reg_item_slab, new_item_p); + if (new_item_p->def_data) + rsbac_kfree(new_item_p->def_data); + if (new_item_p->def_subdata) + rsbac_kfree(new_item_p->def_subdata); + if (new_item_p->slabname) + rsbac_kfree(new_item_p->slabname); + return NULL; + } + if (device != RSBAC_AUTO_DEV) { + snprintf(new_item_p->slabname, + RSBAC_MAX_SLABNAME, + "%s-%02u:%02u", + name, + RSBAC_MAJOR(device), RSBAC_MINOR(device)); + snprintf(new_item_p->subslabname, + RSBAC_MAX_SLABNAME, + "%s-s-%02u:%02u", + name, + RSBAC_MAJOR(device), RSBAC_MINOR(device)); + } else { + strncpy(new_item_p->slabname, name, RSBAC_MAX_SLABNAME); + snprintf(new_item_p->subslabname, + RSBAC_MAX_SLABNAME, + "%s-s", + name); + } + new_item_p->slabname[RSBAC_MAX_SLABNAME - 1] = 0; + new_item_p->subslabname[RSBAC_MAX_SLABNAME - 1] = 0; + new_item_p->slab = rsbac_slab_create_rcu(new_item_p->slabname, + sizeof(struct rsbac_list_lol_item_t) + info_p->desc_size + info_p->data_size); + new_item_p->subslab = rsbac_slab_create_rcu(new_item_p->subslabname, + sizeof(struct rsbac_list_item_t) + info_p->subdesc_size + info_p->subdata_size); + } else { + new_item_p->slabname = NULL; + new_item_p->subslabname = NULL; + new_item_p->slab = NULL; + new_item_p->subslab = NULL; + } + lockdep_set_class(&new_item_p->lock, &list_lock_class); + new_item_p->dirty = FALSE; + if (flags & RSBAC_LIST_NO_WRITE) + new_item_p->no_write = TRUE; + else + new_item_p->no_write = FALSE; + new_item_p->self = new_item_p; + return new_item_p; +} + +/* locking needed */ +static struct rsbac_list_lol_reg_item_t *add_lol_reg(struct + rsbac_list_lol_reg_item_t + *new_item_p) +{ + if (!lol_reg_head.head) { + new_item_p->prev = NULL; + new_item_p->next = NULL; + rcu_assign_pointer(lol_reg_head.head, new_item_p); + rcu_assign_pointer(lol_reg_head.tail, new_item_p); + rcu_assign_pointer(lol_reg_head.curr, new_item_p); + lol_reg_head.count = 1; + } else { + new_item_p->prev = lol_reg_head.tail; + new_item_p->next = NULL; + rcu_assign_pointer(lol_reg_head.tail->next, new_item_p); + rcu_assign_pointer(lol_reg_head.tail, new_item_p); + rcu_assign_pointer(lol_reg_head.curr, new_item_p); + lol_reg_head.count++; + } + return new_item_p; +} + +/* Removing items */ + +/* Call spinlocked */ +static inline void do_remove_item(struct rsbac_list_reg_item_t *list, + struct rsbac_list_item_t *item_p, + u_int hash) +{ + if (unlikely(!list || !item_p)) + return; + + /* curr is no longer valid -> reset */ + if (list->hashed[hash].curr == item_p) + rcu_assign_pointer(list->hashed[hash].curr, NULL); + if ((list->hashed[hash].head == item_p)) { /* item is head */ + if ((list->hashed[hash].tail == item_p)) { /* item is head and tail = only item -> list will be empty */ + rcu_assign_pointer(list->hashed[hash].head, NULL); + rcu_assign_pointer(list->hashed[hash].tail, NULL); + } else { /* item is head, but not tail -> next item becomes head */ + rcu_assign_pointer(item_p->next->prev, NULL); + rcu_assign_pointer(list->hashed[hash].head, item_p->next); + } + } else { /* item is not head */ + if ((list->hashed[hash].tail == item_p)) { /*item is not head, but tail -> previous item becomes tail */ + rcu_assign_pointer(item_p->prev->next, NULL); + rcu_assign_pointer(list->hashed[hash].tail, item_p->prev); + } else { /* item is neither head nor tail -> item is cut out */ + rcu_assign_pointer(item_p->prev->next, item_p->next); + rcu_assign_pointer(item_p->next->prev, item_p->prev); + } + } + /* adjust counter */ + list->hashed[hash].count--; + /* now we can remove the item from memory */ + rcu_free(list, item_p); +} + +/* Call spinlocked */ +static void remove_item(struct rsbac_list_reg_item_t *list, void *desc) +{ + struct rsbac_list_item_t *item_p; + u_int hash = 0; + + if (unlikely(!list || !desc)) + return; + /* first we must locate the item. */ + if ((item_p = lookup_item_locked(list, desc))) { + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + do_remove_item(list, item_p, hash); + } +} + +/* Call spinlocked */ +static void remove_all_items(struct rsbac_list_reg_item_t *list, u_int hash) +{ + struct rsbac_list_item_t *item_p; + + if (unlikely(!list || !list->hashed)) + return; + /* cleanup all items */ + item_p = list->hashed[hash].head; + rcu_assign_pointer(list->hashed[hash].curr, NULL); + rcu_assign_pointer(list->hashed[hash].head, NULL); + rcu_assign_pointer(list->hashed[hash].tail, NULL); + list->hashed[hash].count = 0; + rcu_free_item_chain(list, item_p); +} + +#ifdef CONFIG_RSBAC_LIST_TRANS +/* Call spinlocked */ +static void ta_do_remove_item(struct rsbac_list_reg_item_t *list, + struct rsbac_list_item_t *item_p, + u_int hash) +{ + if (unlikely(!list || !item_p)) + return; + + /* curr is no longer valid -> reset */ + if (list->hashed[hash].ta_curr == item_p) + rcu_assign_pointer(list->hashed[hash].ta_curr, NULL); + if ((list->hashed[hash].ta_head == item_p)) { /* item is head */ + if ((list->hashed[hash].ta_tail == item_p)) { /* item is head and tail = only item -> list will be empty */ + rcu_assign_pointer(list->hashed[hash].ta_head, NULL); + rcu_assign_pointer(list->hashed[hash].ta_tail, NULL); + } else { /* item is head, but not tail -> next item becomes head */ + rcu_assign_pointer(item_p->next->prev, NULL); + rcu_assign_pointer(list->hashed[hash].ta_head, item_p->next); + } + } else { /* item is not head */ + if ((list->hashed[hash].ta_tail == item_p)) { /*item is not head, but tail -> previous item becomes tail */ + rcu_assign_pointer(item_p->prev->next, NULL); + rcu_assign_pointer(list->hashed[hash].ta_tail, item_p->prev); + } else { /* item is neither head nor tail -> item is cut out */ + rcu_assign_pointer(item_p->prev->next, item_p->next); + rcu_assign_pointer(item_p->next->prev, item_p->prev); + } + } + /* adjust counter */ + list->hashed[hash].ta_count--; + /* now we can remove the item from memory */ + rcu_free(list, item_p); +} + +/* Call spinlocked */ +static void ta_remove_item(const rsbac_list_ta_number_t ta_number, + struct rsbac_list_reg_item_t *list, void *desc) +{ + struct rsbac_list_item_t *item_p; + u_int hash = 0; + + if (unlikely(!list || !desc)) + return; + if (!ta_number) + return remove_item(list, desc); + /* first we must locate the item. */ + if ((item_p = ta_lookup_item_locked(ta_number, list, desc))) { + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + ta_do_remove_item(list, item_p, hash); + } +} + +/* Call spinlocked */ +static void ta_remove_all_items(struct rsbac_list_reg_item_t *list, u_int hash) +{ + struct rsbac_list_item_t *item_p; + + /* cleanup all items */ + item_p = list->hashed[hash].ta_head; + rcu_assign_pointer(list->hashed[hash].ta_curr, NULL); + rcu_assign_pointer(list->hashed[hash].ta_head, NULL); + rcu_assign_pointer(list->hashed[hash].ta_tail, NULL); + list->hashed[hash].ta_count = 0; + rcu_free_item_chain(list, item_p); +} +#endif + +/* Call spinlocked */ +static void do_remove_lol_subitem(struct rsbac_list_lol_item_t *sublist, + struct rsbac_list_item_t *item_p) +{ + if (unlikely(!sublist || !item_p)) + return; + + /* curr is no longer valid -> reset */ + if (sublist->curr == item_p) + rcu_assign_pointer(sublist->curr, NULL); + if ((sublist->head == item_p)) { /* item is head */ + if ((sublist->tail == item_p)) { /* item is head and tail = only item -> list will be empty */ + rcu_assign_pointer(sublist->head, NULL); + rcu_assign_pointer(sublist->tail, NULL); + } else { /* item is head, but not tail -> next item becomes head */ + rcu_assign_pointer(item_p->next->prev, NULL); + rcu_assign_pointer(sublist->head, item_p->next); + } + } else { /* item is not head */ + if ((sublist->tail == item_p)) { /*item is not head, but tail -> previous item becomes tail */ + rcu_assign_pointer(item_p->prev->next, NULL); + rcu_assign_pointer(sublist->tail, item_p->prev); + } else { /* item is neither head nor tail -> item is cut out */ + rcu_assign_pointer(item_p->prev->next, item_p->next); + rcu_assign_pointer(item_p->next->prev, item_p->prev); + } + } + /* adjust counter */ + sublist->count--; + /* free call is in calling function */ +} + +/* Call spinlocked */ +static void remove_lol_subitem(struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_item_t *sublist, + void *subdesc) +{ + struct rsbac_list_item_t *subitem_p; + + if (unlikely(!list || !sublist || !subdesc)) + return; + + /* first we must locate the item. */ + if ((subitem_p = lookup_lol_subitem_locked(list, sublist, subdesc))) { + do_remove_lol_subitem(sublist, subitem_p); + rcu_free_lol_sub(list, subitem_p); + } +} + + +/* Call spinlocked */ +static void do_remove_lol_item(struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_item_t *item_p, + u_int hash) +{ + if (unlikely(!list || !item_p)) + return; + + /* curr is no longer valid -> reset */ + if (list->hashed[hash].curr == item_p) + rcu_assign_pointer(list->hashed[hash].curr, NULL); + if ((list->hashed[hash].head == item_p)) { /* item is head */ + if ((list->hashed[hash].tail == item_p)) { /* item is head and tail = only item -> list will be empty */ + rcu_assign_pointer(list->hashed[hash].head, NULL); + rcu_assign_pointer(list->hashed[hash].tail, NULL); + } else { /* item is head, but not tail -> next item becomes head */ +#ifdef CONFIG_RSBAC_DEBUG + if (!item_p->next) { /* list corrupted! */ + rsbac_printk(KERN_WARNING "do_remove_lol_item(): list %s corrupted: invalid next!\n", + list->name); + } else +#endif + { + rcu_assign_pointer(item_p->next->prev, NULL); + rcu_assign_pointer(list->hashed[hash].head, item_p->next); + } + } + } else { /* item is not head */ + if ((list->hashed[hash].tail == item_p)) { /*item is not head, but tail -> previous item becomes tail */ +#ifdef CONFIG_RSBAC_DEBUG + if (!item_p->prev) { /* list corrupted! */ + rsbac_printk(KERN_WARNING "do_remove_lol_item(): list %s corrupted: invalid prev!\n", + list->name); + } else +#endif + { + rcu_assign_pointer(item_p->prev->next, NULL); + rcu_assign_pointer(list->hashed[hash].tail, item_p->prev); + } + } else { /* item is neither head nor tail -> item is cut out */ +#ifdef CONFIG_RSBAC_DEBUG + if (!item_p->prev) { /* list corrupted! */ + rsbac_printk(KERN_WARNING "do_remove_lol_item(): list %s corrupted: invalid prev!\n", + list->name); + } else if (!item_p->next) { /* list corrupted! */ + rsbac_printk(KERN_WARNING "do_remove_lol_item(): list %s corrupted: invalid next!\n", + list->name); + } else +#endif + { + rcu_assign_pointer(item_p->prev->next, item_p->next); + rcu_assign_pointer(item_p->next->prev, item_p->prev); + } + } + } + /* adjust counter */ + list->hashed[hash].count--; + + rcu_free_lol_subitem_chain(list, item_p->head); + rcu_free_lol(list, item_p); +} + +/* Call spinlocked */ +static void remove_lol_item(struct rsbac_list_lol_reg_item_t *list, + void *desc) +{ + struct rsbac_list_lol_item_t *item_p; + u_int hash = 0; + + if (unlikely(!list || !desc)) + return; + + /* first we must locate the item. */ + if ((item_p = lookup_lol_item_locked(list, desc))) { + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + do_remove_lol_item(list, item_p, hash); + } +} + +#ifdef CONFIG_RSBAC_LIST_TRANS +/* Call spinlocked */ +static void ta_do_remove_lol_item(struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_item_t *item_p, + u_int hash) +{ + if (unlikely(!list || !item_p)) + return; + + /* curr is no longer valid -> reset */ + if (list->hashed[hash].ta_curr == item_p) + rcu_assign_pointer(list->hashed[hash].ta_curr, NULL); + if ((list->hashed[hash].ta_head == item_p)) { /* item is head */ + if ((list->hashed[hash].ta_tail == item_p)) { /* item is head and tail = only item -> list will be empty */ + rcu_assign_pointer(list->hashed[hash].ta_head, NULL); + rcu_assign_pointer(list->hashed[hash].ta_tail, NULL); + } else { /* item is head, but not tail -> next item becomes head */ +#ifdef CONFIG_RSBAC_DEBUG + if (!item_p->next) { /* list corrupted! */ + rsbac_printk(KERN_WARNING "do_remove_lol_item(): list %s corrupted: invalid next!\n", + list->name); + } else +#endif + { + rcu_assign_pointer(item_p->next->prev, NULL); + rcu_assign_pointer(list->hashed[hash].ta_head, item_p->next); + } + } + } else { /* item is not head */ + if ((list->hashed[hash].ta_tail == item_p)) { /*item is not head, but tail -> previous item becomes tail */ +#ifdef CONFIG_RSBAC_DEBUG + if (!item_p->prev) { /* list corrupted! */ + rsbac_printk(KERN_WARNING "do_remove_lol_item(): list %s corrupted: invalid prev!\n", + list->name); + } else +#endif + { + rcu_assign_pointer(item_p->prev->next, NULL); + rcu_assign_pointer(list->hashed[hash].ta_tail, item_p->prev); + } + } else { /* item is neither head nor tail -> item is cut out */ +#ifdef CONFIG_RSBAC_DEBUG + if (!item_p->prev) { /* list corrupted! */ + rsbac_printk(KERN_WARNING "do_remove_lol_item(): list %s corrupted: invalid prev!\n", + list->name); + } else if (!item_p->next) { /* list corrupted! */ + rsbac_printk(KERN_WARNING "do_remove_lol_item(): list %s corrupted: invalid next!\n", + list->name); + } else +#endif + { + rcu_assign_pointer(item_p->prev->next, item_p->next); + rcu_assign_pointer(item_p->next->prev, item_p->prev); + } + } + } + /* adjust counter */ + list->hashed[hash].ta_count--; + + rcu_free_lol_subitem_chain(list, item_p->head); + rcu_free_lol(list, item_p); +} + +/* Call spinlocked */ +static void ta_remove_lol_item(const rsbac_list_ta_number_t ta_number, + struct rsbac_list_lol_reg_item_t *list, + void *desc) +{ + struct rsbac_list_lol_item_t *item_p; + u_int hash = 0; + + if (unlikely(!list || !desc)) + return; + + /* first we must locate the item. */ + if ((item_p = ta_lookup_lol_item_locked(ta_number, list, desc))) { + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + ta_do_remove_lol_item(list, item_p, hash); + } +} +#endif + +/* Call spinlocked */ +static void remove_all_lol_subitems(struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_item_t *sublist) +{ + struct rsbac_list_item_t *subitem_p; + + subitem_p = sublist->head; + rcu_assign_pointer(sublist->curr, NULL); + rcu_assign_pointer(sublist->head, NULL); + rcu_assign_pointer(sublist->tail, NULL); + sublist->count = 0; + rcu_free_lol_subitem_chain(list, subitem_p); +} + +/* Call spinlocked */ +static void remove_all_lol_items(struct rsbac_list_lol_reg_item_t *list, u_int hash) +{ + struct rsbac_list_lol_item_t *item_p; + + if (unlikely(!list || !list->hashed)) + return; + item_p = list->hashed[hash].head; + rcu_assign_pointer(list->hashed[hash].curr, NULL); + rcu_assign_pointer(list->hashed[hash].head, NULL); + rcu_assign_pointer(list->hashed[hash].tail, NULL); + list->hashed[hash].count = 0; + rcu_free_lol_item_chain(list, item_p); +} + +#ifdef CONFIG_RSBAC_LIST_TRANS +/* Call spinlocked */ +static void ta_remove_all_lol_items(struct rsbac_list_lol_reg_item_t *list, + u_int hash) +{ + struct rsbac_list_lol_item_t *item_p; + + /* cleanup all items */ + item_p = list->hashed[hash].ta_head; + rcu_assign_pointer(list->hashed[hash].ta_curr, NULL); + rcu_assign_pointer(list->hashed[hash].ta_head, NULL); + rcu_assign_pointer(list->hashed[hash].ta_tail, NULL); + list->hashed[hash].ta_count = 0; + rcu_free_lol_item_chain(list, item_p); +} +#endif + +/* Remove registration items */ + +/* no locking needed */ +static void clear_reg(struct rsbac_list_reg_item_t *reg_item_p) +{ + if (likely(reg_item_p)) { + int i; + struct rsbac_list_item_t *item_p; + struct rsbac_list_item_t *new_item_p; + const u_int nr_hashes = 1 << reg_item_p->hash_bits; + + /* now we can remove the item from memory */ + synchronize_rcu(); + for (i=0; ihashed[i].head; + while(item_p) { + new_item_p = item_p->next; + rsbac_sfree(reg_item_p->slab, item_p); + item_p = new_item_p; + } +#ifdef CONFIG_RSBAC_LIST_TRANS + if(reg_item_p->hashed[i].ta_copied) { + item_p = reg_item_p->hashed[i].ta_head; + while(item_p) { + new_item_p = item_p->next; + rsbac_sfree(reg_item_p->slab, item_p); + item_p = new_item_p; + } + } +#endif + } + if (reg_item_p->def_data) + rsbac_kfree(reg_item_p->def_data); + if (reg_item_p->slab) + rsbac_slab_destroy(reg_item_p->slab); + if (reg_item_p->slabname) + rsbac_kfree(reg_item_p->slabname); + if (reg_item_p->hashed) + rsbac_kfree(reg_item_p->hashed); + rsbac_sfree(reg_item_slab, reg_item_p); + } +} + +/* locking needed */ +static void remove_reg(struct rsbac_list_reg_item_t *reg_item_p) +{ + /* first we must locate the item. */ + if (reg_item_p && (reg_item_p->self == reg_item_p)) {/* item found and valid */ + /* protect against reuse */ + reg_item_p->self = NULL; + if ((reg_head.head == reg_item_p)) { /* item is head */ + if ((reg_head.tail == reg_item_p)) { /* item is head and tail = only item -> list will be empty */ + rcu_assign_pointer(reg_head.head, NULL); + rcu_assign_pointer(reg_head.tail, NULL); + } else { /* item is head, but not tail -> next item becomes head */ + reg_item_p->next->prev = NULL; + rcu_assign_pointer(reg_head.head, reg_item_p->next); + } + } else { /* item is not head */ + if ((reg_head.tail == reg_item_p)) { /*item is not head, but tail -> previous item becomes tail */ + reg_item_p->prev->next = NULL; + rcu_assign_pointer(reg_head.tail, reg_item_p->prev); + } else { /* item is neither head nor tail -> item is cut out */ + reg_item_p->prev->next = reg_item_p->next; + reg_item_p->next->prev = reg_item_p->prev; + } + } + + /* curr is no longer valid -> reset */ + reg_head.curr = NULL; + /* adjust counter */ + reg_head.count--; + } /* end of if: item was found */ +} + +/* no locking needed */ +static void clear_lol_reg(struct rsbac_list_lol_reg_item_t *reg_item_p) +{ + int i; + + if (likely(reg_item_p)) { + struct rsbac_list_lol_item_t *lol_item_p; + struct rsbac_list_lol_item_t *new_lol_item_p; + struct rsbac_list_item_t * lol_subitem_p; + struct rsbac_list_item_t * new_lol_subitem_p; + const u_int nr_hashes = 1 << reg_item_p->hash_bits; + + /* now we can remove the item from memory */ + synchronize_rcu(); + for (i=0; ihashed[i].head; + while(lol_item_p) { + lol_subitem_p = lol_item_p->head; + while (lol_subitem_p) { + new_lol_subitem_p = lol_subitem_p->next; + rsbac_sfree(reg_item_p->subslab, lol_subitem_p); + lol_subitem_p = new_lol_subitem_p; + } + new_lol_item_p = lol_item_p->next; + rsbac_sfree(reg_item_p->slab, lol_item_p); + lol_item_p = new_lol_item_p; + } +#ifdef CONFIG_RSBAC_LIST_TRANS + if(reg_item_p->hashed[i].ta_copied) { + lol_item_p = reg_item_p->hashed[i].ta_head; + while(lol_item_p) { + lol_subitem_p = lol_item_p->head; + while (lol_subitem_p) { + new_lol_subitem_p = lol_subitem_p->next; + rsbac_sfree(reg_item_p->subslab, lol_subitem_p); + lol_subitem_p = new_lol_subitem_p; + } + new_lol_item_p = lol_item_p->next; + rsbac_sfree(reg_item_p->slab, lol_item_p); + lol_item_p = new_lol_item_p; + } + } +#endif + } + if (reg_item_p->def_data) + rsbac_kfree(reg_item_p->def_data); + if (reg_item_p->def_subdata) + rsbac_kfree(reg_item_p->def_subdata); + if (reg_item_p->slab) + rsbac_slab_destroy(reg_item_p->slab); + if (reg_item_p->subslab) + rsbac_slab_destroy(reg_item_p->subslab); + if (reg_item_p->slabname) + rsbac_kfree(reg_item_p->slabname); + if (reg_item_p->subslabname) + rsbac_kfree(reg_item_p->subslabname); + if (reg_item_p->hashed) + rsbac_kfree(reg_item_p->hashed); + rsbac_sfree(lol_reg_item_slab, reg_item_p); + } +} + +/* locking needed */ +static void remove_lol_reg(struct rsbac_list_lol_reg_item_t *reg_item_p) +{ + /* first we must locate the item. */ + if (reg_item_p && (reg_item_p->self == reg_item_p)) {/* found */ + /* protect against reuse */ + reg_item_p->self = NULL; + if ((lol_reg_head.head == reg_item_p)) { /* item is head */ + if ((lol_reg_head.tail == reg_item_p)) { /* item is head and tail = only item -> list will be empty */ + rcu_assign_pointer(lol_reg_head.head, NULL); + rcu_assign_pointer(lol_reg_head.tail, NULL); + } else { /* item is head, but not tail -> next item becomes head */ + reg_item_p->next->prev = NULL; + rcu_assign_pointer(lol_reg_head.head, reg_item_p->next); + } + } else { /* item is not head */ + if ((lol_reg_head.tail == reg_item_p)) { /*item is not head, but tail -> previous item becomes tail */ + reg_item_p->prev->next = NULL; + rcu_assign_pointer(lol_reg_head.tail, reg_item_p->prev); + } else { /* item is neither head nor tail -> item is cut out */ + reg_item_p->prev->next = reg_item_p->next; + reg_item_p->next->prev = reg_item_p->prev; + } + } + + /* curr is no longer valid -> reset */ + rcu_assign_pointer(lol_reg_head.curr, NULL); + /* adjust counter */ + lol_reg_head.count--; + } /* end of if: item was found */ +} + +#define touch(x) + +#define lol_touch(x) + +/********************/ +/* Read/Write */ +/********************/ + +/* call unlocked */ +static int do_read_list(struct rsbac_list_reg_item_t *list, + char * name, + rsbac_boolean_t backup) +{ + struct file *file_p; + int err = 0; + int tmperr; + int converr; + rsbac_version_t list_version; + u_long read_count = 0; + char *old_buf = NULL; + char *new_buf = NULL; + char *old_data; + char *new_data; + struct rsbac_list_info_t *list_info_p; + rsbac_list_count_t list_count; + rsbac_time_t timestamp; + struct rsbac_nanotime_t lastchange; + rsbac_time_t max_age = 0; + rsbac_list_conv_function_t *conv = NULL; + rsbac_boolean_t timeout = FALSE; + mm_segment_t oldfs; + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (unlikely(!list_info_p)) + return -RSBAC_ENOMEM; + /* open file */ + if ((err = rsbac_read_open(name, &file_p, list->device))) { + goto double_free; + } + + /* OK, now we can start reading */ + /* There is a read function for this file, so check info and read as + * many items as possible. A positive return value means a read success, + * 0 end of file and a negative value an error. */ + + /* Set current user space to kernel space, because read() writes */ + /* to user space */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + + /* check gen-list on-disk version */ + tmperr = __vfs_read(file_p, + (__u8 *) & list_version, + sizeof(list_version), &file_p->f_pos); + set_fs(oldfs); + /* error? */ + if (tmperr < sizeof(list_version)) { + rsbac_printk(KERN_WARNING "do_read_list(): read error %i from file when reading list version!\n", tmperr); + err = -RSBAC_EREADFAILED; + goto end_read; + } + /* if wrong list on-disk version, fail */ + switch (list_version) { + case RSBAC_LIST_DISK_VERSION: + case RSBAC_LIST_DISK_OLD_VERSION: + break; + default: + rsbac_printk(KERN_WARNING "do_read_list(): wrong on-disk list version %u in file %s, expected %u - error!\n", + list_version, + name, RSBAC_LIST_DISK_VERSION); + err = -RSBAC_EREADFAILED; + goto end_read; + } + + /* get timestamp */ + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + (__u8 *) & timestamp, + sizeof(timestamp), &file_p->f_pos); + set_fs(oldfs); + /* error? */ + if (tmperr < sizeof(timestamp)) { + rsbac_printk(KERN_WARNING "do_read_list(): timestamp read error %i from file %s!\n", + tmperr, + name); + err = -RSBAC_EREADFAILED; + goto end_read; + } + + /* get list info */ + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + (__u8 *) list_info_p, + sizeof(*list_info_p), &file_p->f_pos); + set_fs(oldfs); + /* error? */ + if (tmperr < sizeof(*list_info_p)) { + rsbac_printk(KERN_WARNING "do_read_list(): list info read error %i from file %s!\n", + tmperr, + name); + err = -RSBAC_EREADFAILED; + goto end_read; + } + + /* list timed out? System time is measured in seconds. */ + if (list_info_p->max_age + && (timestamp + list_info_p->max_age) <= RSBAC_CURRENT_TIME) + timeout = TRUE; + + /* Valid key? */ + if (list_info_p->key != list->info.key) { + if (timeout) { + rsbac_printk(KERN_WARNING "do_read_list(): accessing timed out list %s with wrong key, ignoring old contents!\n", + name); + goto end_read; + } else { + rsbac_printk(KERN_WARNING "do_read_list(): try to access list %s with wrong key!\n", + name); + err = -EPERM; + goto end_read; + } + } + + /* skip the rest, if ignore is requested */ + if (list->flags & RSBAC_LIST_IGNORE_OLD) + goto end_read; + + switch (list_version) { + case RSBAC_LIST_DISK_VERSION: + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + (char *) &lastchange, + sizeof(lastchange), + &file_p->f_pos); + set_fs(oldfs); + /* error? */ + if (tmperr < sizeof(lastchange)) { + rsbac_printk(KERN_WARNING "do_read_list(): lastchange read error %i from file %s!\n", + tmperr, + name); + err = -RSBAC_EREADFAILED; + goto end_read; + } + break; + case RSBAC_LIST_DISK_OLD_VERSION: + break; + default: + break; + } + /* if wrong list version, try to get_conv */ + if (list_info_p->version != list->info.version) { + if (list->get_conv) + conv = list->get_conv(list_info_p->version); + if (!conv) { + if (timeout) { + rsbac_printk(KERN_WARNING "do_read_list(): accessing timed out list %s without conversion function, ignoring old contents!\n", + name); + goto end_read; + } else { + /* complain and set error, if ignore is not requested */ + if (! + (list-> + flags & + RSBAC_LIST_IGNORE_UNSUPP_VERSION)) { + rsbac_printk(KERN_WARNING "do_read_list(): cannot convert list version %u of file %s to version %u!\n", + list_info_p->version, + name, + list->info.version); + err = -RSBAC_EINVALIDVERSION; + } + goto end_read; + } + } else { + rsbac_printk(KERN_WARNING "do_read_list(): converting list version %u of file %s on device %02u:%02u to version %u!\n", + list_info_p->version, + name, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + list->info.version); + } + } else { /* same version needs same sizes */ + + if ((list_info_p->desc_size != list->info.desc_size) + || (list_info_p->data_size != list->info.data_size) + ) { + if (timeout) { + rsbac_printk(KERN_WARNING "do_read_list(): accessing timed out list %s with wrong desc or data size, ignoring old contents!\n", + name); + goto end_read; + } else { + rsbac_printk(KERN_WARNING "do_read_list(): desc or data size mismatch on list %s!\n", + name); + err = -RSBAC_EINVALIDLIST; + goto end_read; + } + } + } + + /* get list count */ + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + (__u8 *) & list_count, + sizeof(list_count), &file_p->f_pos); + set_fs(oldfs); + /* error? */ + if (tmperr < sizeof(list_count)) { + rsbac_printk(KERN_WARNING "do_read_list(): list count read error %i from file %s!\n", + tmperr, + name); + err = -RSBAC_EREADFAILED; + goto end_read; + } + + /* alloc mem for old and converted item */ + old_buf = + rsbac_kmalloc_unlocked(list_info_p->desc_size + list_info_p->data_size); + if (!old_buf) { + rsbac_printk(KERN_WARNING "do_read_list(): cannot allocate memory!\n"); + err = -RSBAC_ENOMEM; + goto end_read; + } + new_buf = + rsbac_kmalloc_unlocked(list->info.desc_size + list->info.data_size); + if (unlikely(!new_buf)) { + rsbac_printk(KERN_WARNING "do_read_list(): cannot allocate memory!\n"); + err = -RSBAC_ENOMEM; + goto end_read; + } + /* calculate data pointers */ + if (list_info_p->data_size) + old_data = old_buf + list_info_p->desc_size; + else + old_data = NULL; + if (list->info.data_size) + new_data = new_buf + list->info.desc_size; + else + new_data = NULL; + + /* actual reading */ + do { + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + (char *) &max_age, + sizeof(max_age), + &file_p->f_pos); + set_fs(oldfs); + if (conv) { + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + old_buf, + list_info_p-> + desc_size + + list_info_p->data_size, + &file_p->f_pos); + set_fs(oldfs); + if (tmperr > 0) { /* convert */ + converr = conv(old_buf, old_data, + new_buf, new_data); + if (converr) + tmperr = converr; + } + } else { + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + new_buf, + list->info.desc_size + + list->info.data_size, + &file_p->f_pos); + set_fs(oldfs); + } + /* if successful, add item */ + if (tmperr > 0) { + /* no need to lock, list is not yet published */ + if (!backup || !lookup_item_locked(list, new_buf)) + add_item(list, max_age, new_buf, new_data); + /* allow access */ + read_count++; +/* + rsbac_pr_debug(lists, "read item %i\n", user_aci.id); +*/ + } + } + while (tmperr > 0); /* end of do */ + + if (tmperr < 0) { + rsbac_printk(KERN_WARNING "do_read_list(): read error %i from file %s!\n", + tmperr, + name); + err = -RSBAC_EREADFAILED; + } + + if (read_count != list_count) { + rsbac_printk(KERN_WARNING "do_read_list(): read %lu, expected %u items from file %s!\n", + read_count, list_count, name); + err = -RSBAC_EREADFAILED; + } + +end_read: + if (old_buf) + rsbac_kfree(old_buf); + if (new_buf) + rsbac_kfree(new_buf); + + rsbac_pr_debug(lists, "%lu entries read.\n", read_count); + /* We do not need this file any more */ + rsbac_read_close(file_p); + +double_free: + rsbac_kfree(list_info_p); + + if ( err + && (err != -RSBAC_ENOTFOUND) + && !backup + && rsbac_list_recover + ) { + char * bname; + + rsbac_list_read_errors++; + bname = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if (!bname) + return -RSBAC_ENOMEM; + rsbac_printk(KERN_WARNING "restoring list %s from device %02u:%02u failed with error %s, rsbac_list_recover is set, so retrying with backup list.\n", + name, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + get_error_name(bname, err)); + sprintf(bname, "%sb", name); + err = do_read_list(list, bname, TRUE); + if ( err + && (err != -RSBAC_ENOTFOUND) + && rsbac_list_recover + ) { + rsbac_printk(KERN_WARNING "restoring list %s backup from device %02u:%02u failed with error %s, rsbac_list_recover is set, so returning that list is fine.\n", + name, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + get_error_name(bname, err)); + err = 0; + } + list->dirty = TRUE; + rsbac_kfree(bname); + } + + return err; +} + +/* call unlocked */ +static int read_list(struct rsbac_list_reg_item_t *list) +{ + int res; + u_int flags; + + flags = list->flags; + list->flags |= RSBAC_LIST_NO_MAX; + res = do_read_list(list, list->name, FALSE); + if((res == -RSBAC_ENOTFOUND) && list->old_name_base[0]) { + char name[RSBAC_MAXNAMELEN]; + int i; + + rsbac_printk(KERN_INFO "read_list(): list %s on device %02u:%02u not found, trying numbered lists 0 to %u with old name base '%s'\n", + list->name, MAJOR(list->device), MINOR(list->device), RSBAC_LIST_MAX_OLD_HASH-1, list->old_name_base); + for (i=0; iold_name_base, i); + res = do_read_list(list, name, FALSE); + if(res && (res != -RSBAC_ENOTFOUND)) + return res; + } + list->dirty = TRUE; + } + list->flags = flags; + return res; +} + +/* call unlocked */ +static int do_read_lol_list(struct rsbac_list_lol_reg_item_t *list, + char * name, + rsbac_boolean_t backup) +{ + struct file *file_p; + int err = 0; + int tmperr; + int converr; + rsbac_version_t list_version; + u_long read_count = 0; + u_long sublen; + u_long i; + char *old_buf = NULL; + char *new_buf = NULL; + char *old_data; + char *new_data; + char *old_subbuf = NULL; + char *new_subbuf = NULL; + char *old_subdata; + char *new_subdata; + struct rsbac_list_lol_info_t *list_info_p; + rsbac_list_count_t list_count; + rsbac_time_t timestamp; + struct rsbac_nanotime_t lastchange; + rsbac_time_t max_age = 0; + rsbac_list_conv_function_t *conv = NULL; + rsbac_list_conv_function_t *subconv = NULL; + rsbac_boolean_t timeout = FALSE; + struct rsbac_list_lol_item_t *item_p; + mm_segment_t oldfs; + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (unlikely(!list_info_p)) + return -RSBAC_ENOMEM; + /* open file */ + if ((err = rsbac_read_open(name, &file_p, list->device))) { + goto double_free; + } + + /* OK, now we can start reading */ + /* There is a read function for this file, so check info and read as + * many items as possible. A positive return value means a read success, + * 0 end of file and a negative value an error. */ + + /* Set current user space to kernel space, because read() writes */ + /* to user space */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + + /* check gen-list on-disk version */ + tmperr = __vfs_read(file_p, + (__u8 *) & list_version, + sizeof(list_version), &file_p->f_pos); + set_fs(oldfs); + /* error? */ + if (tmperr < sizeof(list_version)) { + printk(KERN_WARNING + "do_read_lol_list(): read error %i from file!\n", + tmperr); + err = -RSBAC_EREADFAILED; + goto end_read; + } + /* if wrong list on-disk version, fail */ + switch (list_version) { + case RSBAC_LIST_DISK_VERSION: + case RSBAC_LIST_DISK_OLD_VERSION: + break; + default: + rsbac_printk(KERN_WARNING "do_read_lol_list(): wrong on-disk list version %u in file %s, expected %u - error!\n", + list_version, + name, RSBAC_LIST_DISK_VERSION); + err = -RSBAC_EREADFAILED; + goto end_read; + } + + /* get timestamp */ + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + (__u8 *) & timestamp, + sizeof(timestamp), &file_p->f_pos); + set_fs(oldfs); + /* error? */ + if (tmperr < sizeof(timestamp)) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): timestamp read error %i from file %s!\n", + tmperr, + name); + err = -RSBAC_EREADFAILED; + goto end_read; + } + + /* get list info */ + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + (__u8 *) list_info_p, + sizeof(*list_info_p), &file_p->f_pos); + set_fs(oldfs); + /* error? */ + if (tmperr < sizeof(*list_info_p)) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): list info read error %i from file %s!\n", + tmperr, + name); + err = -RSBAC_EREADFAILED; + goto end_read; + } + + /* list timed out? System time is measured in seconds. */ + if (list_info_p->max_age + && (timestamp + list_info_p->max_age) <= RSBAC_CURRENT_TIME) + timeout = TRUE; + + /* Valid key? */ + if (list_info_p->key != list->info.key) { + if (timeout) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): accessing timed out list %s with wrong key, ignoring old contents!\n", + name); + goto end_read; + } else { + rsbac_printk(KERN_WARNING "do_read_lol_list(): try to access list %s with wrong key!\n", + name); + err = -EPERM; + goto end_read; + } + } + + /* skip the rest, if ignore is requested */ + if (list->flags & RSBAC_LIST_IGNORE_OLD) + goto end_read; + + switch (list_version) { + case RSBAC_LIST_DISK_VERSION: + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + (char *) &lastchange, + sizeof(lastchange), + &file_p->f_pos); + set_fs(oldfs); + /* error? */ + if (tmperr < sizeof(lastchange)) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): lastchange read error %i from file %s!\n", + tmperr, + name); + err = -RSBAC_EREADFAILED; + goto end_read; + } + break; + case RSBAC_LIST_DISK_OLD_VERSION: + break; + default: + break; + } + /* if wrong list version, try to get_conv */ + if (list_info_p->version != list->info.version) { + if (list->get_conv) + conv = list->get_conv(list_info_p->version); + if (list->get_subconv) + subconv = list->get_subconv(list_info_p->version); + if (!conv || !subconv) { + if (timeout) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): accessing timed out list %s without both conversion functions, ignoring old contents!\n", + name); + goto end_read; + } else { + /* complain and set error, if ignore is not requested */ + if (! + (list-> + flags & + RSBAC_LIST_IGNORE_UNSUPP_VERSION)) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): cannot convert list version %u of file %s to version %u!\n", + list_info_p->version, + name, + list->info.version); + err = -RSBAC_EINVALIDVERSION; + } + goto end_read; + } + } else { + rsbac_printk(KERN_WARNING "do_read_lol_list(): converting list version %u of file %s on device %02u:%02u to version %u!\n", + list_info_p->version, + name, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + list->info.version); + } + } else { /* same version needs same sizes */ + + if ((list_info_p->desc_size != list->info.desc_size) + || (list_info_p->data_size != list->info.data_size) + || (list_info_p->subdesc_size != + list->info.subdesc_size) + || (list_info_p->subdata_size != + list->info.subdata_size) + ) { + if (timeout) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): accessing timed out list %s with wrong desc or data size(s), ignoring old contents!\n", + name); + goto end_read; + } else { + rsbac_printk(KERN_WARNING "do_read_lol_list(): desc or data size mismatch on list %s!\n", + name); + err = -RSBAC_EINVALIDLIST; + goto end_read; + } + } + } + + /* get list count */ + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + (__u8 *) & list_count, + sizeof(list_count), &file_p->f_pos); + set_fs(oldfs); + /* error? */ + if (tmperr < sizeof(list_count)) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): list count read error %i from file %s!\n", + tmperr, + name); + err = -RSBAC_EREADFAILED; + goto end_read; + } + + /* alloc mem for old and converted items */ + old_buf = + rsbac_kmalloc_unlocked(list_info_p->desc_size + list_info_p->data_size); + if (!old_buf) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): cannot allocate memory!\n"); + err = -RSBAC_ENOMEM; + goto end_read; + } + new_buf = + rsbac_kmalloc_unlocked(list->info.desc_size + list->info.data_size); + if (!new_buf) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): cannot allocate memory!\n"); + err = -RSBAC_ENOMEM; + goto end_read; + } + old_subbuf = + rsbac_kmalloc_unlocked(list_info_p->subdesc_size + + list_info_p->subdata_size); + if (!old_subbuf) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): cannot allocate memory!\n"); + err = -RSBAC_ENOMEM; + goto end_read; + } + new_subbuf = + rsbac_kmalloc_unlocked(list->info.subdesc_size + + list->info.subdata_size); + if (!new_subbuf) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): cannot allocate memory!\n"); + err = -RSBAC_ENOMEM; + goto end_read; + } + /* calculate data pointers */ + if (list_info_p->data_size) + old_data = old_buf + list_info_p->desc_size; + else + old_data = NULL; + if (list->info.data_size) + new_data = new_buf + list->info.desc_size; + else + new_data = NULL; + if (list_info_p->subdata_size) + old_subdata = old_subbuf + list_info_p->subdesc_size; + else + old_subdata = NULL; + if (list->info.subdata_size) + new_subdata = new_subbuf + list->info.subdesc_size; + else + new_subdata = NULL; + + /* actual reading */ + do { + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + (char *) &max_age, + sizeof(max_age), + &file_p->f_pos); + set_fs(oldfs); + if (conv) { + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + old_buf, + list_info_p-> + desc_size + + list_info_p->data_size, + &file_p->f_pos); + set_fs(oldfs); + if (tmperr > 0) { /* convert */ + converr = conv(old_buf, old_data, + new_buf, new_data); + if (converr) + tmperr = converr; + } + } else { + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + new_buf, + list->info.desc_size + + list->info.data_size, + &file_p->f_pos); + set_fs(oldfs); + } + /* if successful, add item */ + if (tmperr > 0) { + /* no need to lock, list is not yet published */ + if (!backup || !(item_p = lookup_lol_item_locked(list, new_buf))) + item_p = add_lol_item(list, max_age, new_buf, new_data); + /* allow access */ + if (!item_p) { + err = -RSBAC_ENOMEM; + goto end_read; + } + read_count++; +/* + rsbac_pr_debug(lists, "read item %i\n", user_aci.id); +*/ + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + (__u8 *) & sublen, + sizeof(sublen), + &file_p->f_pos); + set_fs(oldfs); + /* if successful, read and add sublen subitems */ + if (tmperr > 0) { + for (i = 0; i < sublen; i++) { + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + (char + *) + &max_age, + sizeof + (max_age), + &file_p-> + f_pos); + set_fs(oldfs); + if (subconv) { + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + old_subbuf, + list_info_p-> + subdesc_size + + list_info_p-> + subdata_size, + &file_p->f_pos); + set_fs(oldfs); + if (tmperr > 0) { /* convert */ + converr = + subconv + (old_subbuf, + old_subdata, + new_subbuf, + new_subdata); + if (converr) + tmperr = + converr; + } + } else { + set_fs(KERNEL_DS); + tmperr = __vfs_read(file_p, + new_subbuf, + list->info. + subdesc_size + + list->info. + subdata_size, + &file_p->f_pos); + set_fs(oldfs); + } + if (tmperr > 0) { + /* no need to lock, list is not yet published */ + if (!backup || !lookup_lol_subitem_locked(list, item_p, new_subbuf)) + if (!add_lol_subitem + (list, item_p, max_age, + new_subbuf, + new_subdata)) { + rsbac_printk + (KERN_WARNING + "do_read_lol_list(): could not add subitem!\n"); + i = sublen; + tmperr = -1; + } + } else { + i = sublen; + tmperr = -1; + } + } + } + } + } + while (tmperr > 0); /* end of do */ + + if (tmperr < 0) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): read error %i from file %s!\n", + tmperr, + name); + err = -RSBAC_EREADFAILED; + } + + if (read_count != list_count) { + rsbac_printk(KERN_WARNING "do_read_lol_list(): read %lu, expected %u items from file %s!\n", + read_count, list_count, name); + err = -RSBAC_EREADFAILED; + } + +end_read: + if (old_buf) + rsbac_kfree(old_buf); + if (new_buf) + rsbac_kfree(new_buf); + if (old_subbuf) + rsbac_kfree(old_subbuf); + if (new_subbuf) + rsbac_kfree(new_subbuf); + + rsbac_pr_debug(lists, "%lu entries read.\n", read_count); + /* We do not need this file any more */ + rsbac_read_close(file_p); + +double_free: + rsbac_kfree(list_info_p); + + if ( err + && (err != -RSBAC_ENOTFOUND) + && !backup + && rsbac_list_recover + ) { + char * bname; + + rsbac_list_read_errors++; + bname = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if (!bname) + return -RSBAC_ENOMEM; + rsbac_printk(KERN_WARNING "restoring list of lists %s from device %02u:%02u failed with error %s, rsbac_list_recover is set, so retrying with backup list.\n", + name, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + get_error_name(bname, err)); + sprintf(bname, "%sb", name); + err = do_read_lol_list(list, bname, TRUE); + if ( err + && (err != -RSBAC_ENOTFOUND) + && rsbac_list_recover + ) { + rsbac_printk(KERN_WARNING "restoring list of lists %s backup from device %02u:%02u failed with error %s, rsbac_list_recover is set, so returning that list is fine.\n", + name, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + get_error_name(bname, err)); + err = 0; + } + list->dirty = TRUE; + rsbac_kfree(bname); + } + + return err; +} /* end of do_read_lol_list() */ + +/* call unlocked */ +static int read_lol_list(struct rsbac_list_lol_reg_item_t *list) +{ + int res; + u_int flags; + + flags = list->flags; + list->flags |= RSBAC_LIST_NO_MAX; + res = do_read_lol_list(list, list->name, FALSE); + if((res == -RSBAC_ENOTFOUND) && list->old_name_base[0]) { + char name[RSBAC_MAXNAMELEN]; + int i; + + rsbac_printk(KERN_INFO "read_lol_list(): list %s on device %02u:%02u not found, trying numbered lists 0 to %u with old name base '%s'\n", + list->name, MAJOR(list->device), MINOR(list->device), RSBAC_LIST_LOL_MAX_OLD_HASH-1, list->old_name_base); + for (i=0; iold_name_base, i); + res = do_read_lol_list(list, name, FALSE); + if(res && (res != -RSBAC_ENOTFOUND)) + return res; + } + list->dirty = TRUE; + } + list->flags = flags; + return res; +} + + +#ifndef CONFIG_RSBAC_NO_WRITE +int check_buffer(struct rsbac_list_buffer_t ** buffer_pp, u_int size) +{ + if((*buffer_pp)->len + size <= RSBAC_LIST_BUFFER_DATA_SIZE) + return 0; + else { + struct rsbac_list_buffer_t * new_buffer; + + new_buffer = rsbac_kmalloc(RSBAC_LIST_BUFFER_SIZE); + if(!new_buffer) + return -RSBAC_ENOMEM; + rsbac_pr_debug(write, "Added a buffer\n"); + new_buffer->next = NULL; + new_buffer->len = 0; + (*buffer_pp)->next = new_buffer; + *buffer_pp = new_buffer; + return 0; + } +} + +void free_buffers(struct rsbac_list_buffer_t * buffer) +{ + struct rsbac_list_buffer_t * next; + + while(buffer) { + rsbac_pr_debug(write, "Freeing buffer of size %u\n", + buffer->len); + next = buffer->next; + rsbac_kfree(buffer); + buffer = next; + } +} + +/* call unlocked */ +static int fill_buffer(struct rsbac_list_reg_item_t *list, + struct rsbac_list_write_item_t **write_item_pp) +{ + struct rsbac_list_write_item_t *write_item_p; + struct rsbac_list_item_t *current_p; + struct rsbac_list_buffer_t *buffer = NULL; + rsbac_list_count_t allcount = 0; + rsbac_version_t list_version = RSBAC_LIST_DISK_VERSION; + rsbac_time_t timestamp = RSBAC_CURRENT_TIME; + int i; + const u_int nr_hashes = 1 << list->hash_bits; + + write_item_p = rsbac_kmalloc(sizeof(*write_item_p)); + if (unlikely(!write_item_p)) { + *write_item_pp = NULL; + return -RSBAC_ENOMEM; + } + + /* fill write_item */ + write_item_p->prev = NULL; + write_item_p->next = NULL; + write_item_p->list = list; + write_item_p->buffer = NULL; + strncpy(write_item_p->name, list->name, RSBAC_LIST_MAX_FILENAME); + write_item_p->name[RSBAC_LIST_MAX_FILENAME] = 0; + write_item_p->device = list->device; + + buffer = rsbac_kmalloc(RSBAC_LIST_BUFFER_SIZE); + if (unlikely(!buffer)) { + rsbac_kfree(write_item_p); + *write_item_pp = NULL; + return -RSBAC_ENOMEM; + } + write_item_p->buffer = buffer; + buffer->len = 0; + buffer->next = NULL; + /* copy version */ + memcpy(buffer->data, &list_version, sizeof(list_version)); + buffer->len = sizeof(list_version); + /* copy timestamp */ + memcpy(buffer->data + buffer->len, + ×tamp, sizeof(timestamp)); + buffer->len += sizeof(timestamp); + /* copy info */ + memcpy(buffer->data + buffer->len, + &list->info, sizeof(list->info)); + buffer->len += sizeof(list->info); + + /* Protect list */ + spin_lock(&list->lock); + for (i=0; ihashed[i].count; + /* copy lastchange */ + memcpy(buffer->data + buffer->len, + &list->lastchange, sizeof(list->lastchange)); + buffer->len += sizeof(list->lastchange); + /* copy count */ + memcpy(buffer->data + buffer->len, + &allcount, sizeof(allcount)); + buffer->len += sizeof(allcount); + /* copy list */ + for (i=0; ihashed[i].head; + while (current_p) { + if (unlikely(check_buffer(&buffer, sizeof(current_p->max_age) + list->info.desc_size + list->info.data_size))) { + /* unprotect this list */ + spin_unlock(&list->lock); + free_buffers(write_item_p->buffer); + rsbac_kfree(write_item_p); + *write_item_pp = NULL; + return -RSBAC_ENOMEM; + } + memcpy(buffer->data + buffer->len, + ¤t_p->max_age, sizeof(current_p->max_age)); + buffer->len += sizeof(current_p->max_age); + memcpy(buffer->data + buffer->len, + ((char *) current_p) + sizeof(*current_p), + list->info.desc_size + list->info.data_size); + buffer->len += list->info.desc_size + list->info.data_size; + current_p = current_p->next; + } + } + spin_unlock(&list->lock); + + *write_item_pp = write_item_p; + + return 0; +} + +/* call unlocked */ +static int rsbac_list_write_buffers(struct rsbac_list_write_head_t write_head) +{ + struct file *file_p; + int count = 0; + mm_segment_t oldfs; + u_int written; + u_long all_written; + u_long bytes; + u_int bufcount; + int tmperr = 0; + struct rsbac_list_buffer_t * buffer; + struct rsbac_list_write_item_t *write_item_p; + struct rsbac_list_write_item_t *next_item_p; + + write_item_p = write_head.head; + while (write_item_p) { + rsbac_pr_debug(write, "write list %s on device %02u:%02u.\n", + write_item_p->name, + RSBAC_MAJOR(write_item_p->device), + RSBAC_MINOR(write_item_p->device)); + /* open file */ + if ((tmperr = rsbac_write_open(write_item_p->name, + &file_p, + write_item_p->device))) { + if (tmperr != -RSBAC_ENOTWRITABLE) { + rsbac_printk(KERN_WARNING "rsbac_list_write_buffers(): opening file %s on device %02u:%02u failed with error %i!\n", + write_item_p->name, + RSBAC_MAJOR(write_item_p-> + device), + RSBAC_MINOR(write_item_p-> + device), tmperr); + } + count = tmperr; + goto out_free_all; + } + + /* OK, now we can start writing the buffer. */ + /* Set current user space to kernel space, because write() reads */ + /* from user space */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + + buffer = write_item_p->buffer; + all_written = 0; + bufcount = 0; + while (buffer && (tmperr >= 0)) { + rsbac_pr_debug(write, "Writing list %s, buffer %u with size %u\n", + write_item_p->name, bufcount, buffer->len); + bufcount++; + written = 0; + while ((written < buffer->len) && (tmperr >= 0)) { + bytes = buffer->len - written; + tmperr = __vfs_write(file_p, + buffer->data + written, + bytes, + &file_p->f_pos); + if (tmperr > 0) { + written += tmperr; + } + } + all_written += written; + buffer = buffer->next; + } + /* Set current user space back to user space, because write() reads */ + /* from user space */ + set_fs(oldfs); + /* End of write access */ + rsbac_write_close(file_p); + if (tmperr < 0) { + rsbac_printk(KERN_WARNING "rsbac_list_write_buffers(): write error %i on device %02u:%02u file %s!\n", + tmperr, + RSBAC_MAJOR(write_item_p->device), + RSBAC_MINOR(write_item_p->device), + write_item_p->name); + count = tmperr; + goto out_free_all; + } else + count++; + + rsbac_pr_debug(write, "%lu bytes from %u buffers written.\n", + all_written, bufcount); + + free_buffers(write_item_p->buffer); + next_item_p = write_item_p->next; + rsbac_kfree(write_item_p); + write_item_p = next_item_p; + } + return count; + +out_free_all: + /* Mark unwritten lists dirty and free everything */ + while(write_item_p) + { + if(write_item_p->list->self == write_item_p->list) + write_item_p->list->dirty = TRUE; + free_buffers(write_item_p->buffer); + next_item_p = write_item_p->next; + rsbac_kfree(write_item_p); + write_item_p = next_item_p; + } + return count; +} + +/* call unlocked */ +static int fill_lol_buffer(struct rsbac_list_lol_reg_item_t *list, + struct rsbac_list_lol_write_item_t + **write_item_pp) +{ + struct rsbac_list_lol_write_item_t *write_item_p; + struct rsbac_list_lol_item_t *current_p; + struct rsbac_list_item_t *sub_p; + struct rsbac_list_buffer_t *buffer = NULL; + rsbac_list_count_t allcount = 0; + rsbac_version_t list_version = RSBAC_LIST_DISK_VERSION; + rsbac_time_t timestamp = RSBAC_CURRENT_TIME; + int i; + const u_int nr_hashes = 1 << list->hash_bits; + + write_item_p = rsbac_kmalloc_unlocked(sizeof(*write_item_p)); + if (unlikely(!write_item_p)) { + *write_item_pp = NULL; + return (-RSBAC_ENOMEM); + } + + rsbac_pr_debug(write, "Filling buffers for list of lists %s\n", + list->name); + /* fill write_item */ + write_item_p->prev = NULL; + write_item_p->next = NULL; + write_item_p->list = list; + write_item_p->buffer = NULL; + strncpy(write_item_p->name, list->name, RSBAC_LIST_MAX_FILENAME); + write_item_p->name[RSBAC_LIST_MAX_FILENAME] = 0; + write_item_p->device = list->device; + + buffer = rsbac_kmalloc(RSBAC_LIST_BUFFER_SIZE); + if (unlikely(!buffer)) { + rsbac_kfree(write_item_p); + *write_item_pp = NULL; + return -RSBAC_ENOMEM; + } + write_item_p->buffer = buffer; + buffer->len = 0; + buffer->next = NULL; + /* copy version */ + memcpy(buffer->data, (char *) &list_version, sizeof(list_version)); + buffer->len = sizeof(list_version); + /* copy timestamp */ + memcpy(buffer->data + buffer->len, + (char *) ×tamp, sizeof(timestamp)); + buffer->len += sizeof(timestamp); + /* copy info */ + memcpy(buffer->data + buffer->len, + (char *) &list->info, sizeof(list->info)); + buffer->len += sizeof(list->info); + /* protect list */ + spin_lock(&list->lock); + for (i=0; ihashed[i].count; + /* copy lastchange */ + memcpy(buffer->data + buffer->len, + (char *) &list->lastchange, sizeof(list->lastchange)); + buffer->len += sizeof(list->lastchange); + /* copy count */ + memcpy(buffer->data + buffer->len, + (char *) &allcount, sizeof(allcount)); + buffer->len += sizeof(allcount); + /* copy list */ + for (i=0; ihashed[i].head; + while (current_p) { + if (unlikely(check_buffer(&buffer, sizeof(current_p->max_age) + + list->info.desc_size + + list->info.data_size + + sizeof(current_p->count)))) { + /* unprotect this list */ + spin_unlock(&list->lock); + free_buffers(write_item_p->buffer); + rsbac_kfree(write_item_p); + *write_item_pp = NULL; + return -RSBAC_ENOMEM; + } + memcpy(buffer->data + buffer->len, + ¤t_p->max_age, sizeof(current_p->max_age)); + buffer->len += sizeof(current_p->max_age); + memcpy(buffer->data + buffer->len, + ((char *) current_p) + sizeof(*current_p), + list->info.desc_size + list->info.data_size); + buffer->len += list->info.desc_size + list->info.data_size; + memcpy(buffer->data + buffer->len, + ¤t_p->count, sizeof(current_p->count)); + buffer->len += sizeof(current_p->count); + /* copy subitems */ + sub_p = current_p->head; + while (sub_p) { + if (unlikely(check_buffer(&buffer, sizeof(sub_p->max_age) + + list->info.subdesc_size + + list->info.subdata_size))) { + /* unprotect this list */ + spin_unlock(&list->lock); + free_buffers(write_item_p->buffer); + rsbac_kfree(write_item_p); + *write_item_pp = NULL; + return -RSBAC_ENOMEM; + } + memcpy(buffer->data + buffer->len, + &sub_p->max_age, sizeof(sub_p->max_age)); + buffer->len += sizeof(sub_p->max_age); + memcpy(buffer->data + buffer->len, + ((char *) sub_p) + sizeof(*sub_p), + list->info.subdesc_size + + list->info.subdata_size); + buffer->len += + list->info.subdesc_size + + list->info.subdata_size; + sub_p = sub_p->next; + } + current_p = current_p->next; + } + } + /* unprotect this list */ + spin_unlock(&list->lock); + *write_item_pp = write_item_p; + + return 0; +} + +/* call unlocked */ +static int rsbac_list_write_lol_buffers(struct rsbac_list_lol_write_head_t + write_head) +{ + struct file *file_p; + int count = 0; + mm_segment_t oldfs; + u_long written; + u_long all_written; + u_long bytes; + u_int bufcount; + int tmperr = 0; + struct rsbac_list_buffer_t * buffer; + struct rsbac_list_lol_write_item_t *write_item_p; + struct rsbac_list_lol_write_item_t *next_item_p; + + write_item_p = write_head.head; + while (write_item_p) { + rsbac_pr_debug(write, "write list of lists %s on device %02u:%02u.\n", + write_item_p->name, + RSBAC_MAJOR(write_item_p->device), + RSBAC_MINOR(write_item_p->device)); + /* open file */ + if ((tmperr = rsbac_write_open(write_item_p->name, + &file_p, + write_item_p->device))) { + if (tmperr != -RSBAC_ENOTWRITABLE) { + rsbac_printk(KERN_WARNING "rsbac_list_write_lol_buffers(): opening file %s on device %02u:%02u failed with error %i!\n", + write_item_p->name, + RSBAC_MAJOR(write_item_p-> + device), + RSBAC_MINOR(write_item_p-> + device), tmperr); + } + goto out_free_all; + } + + /* OK, now we can start writing the buffer. */ + /* Set current user space to kernel space, because write() reads */ + /* from user space */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + + buffer = write_item_p->buffer; + all_written = 0; + bufcount = 0; + while (buffer && (tmperr >= 0)) { + rsbac_pr_debug(write, "Writing list of lists %s, buffer %u with size %u\n", + write_item_p->name, bufcount, buffer->len); + bufcount++; + written = 0; + while ((written < buffer->len) && (tmperr >= 0)) { + bytes = buffer->len - written; + tmperr = __vfs_write(file_p, + buffer->data + written, + bytes, + &file_p->f_pos); + if (tmperr > 0) { + written += tmperr; + } + } + all_written += written; + buffer = buffer->next; + } + /* Set current user space back to user space, because write() reads */ + /* from user space */ + set_fs(oldfs); + /* End of write access */ + rsbac_write_close(file_p); + + if (tmperr < 0) { + rsbac_printk(KERN_WARNING "rsbac_list_write_lol_buffers(): write error %i on device %02u:%02u file %s!\n", + tmperr, + RSBAC_MAJOR(write_item_p->device), + RSBAC_MINOR(write_item_p->device), + write_item_p->name); + count = tmperr; + goto out_free_all; + } else + count++; + + rsbac_pr_debug(write, "%lu bytes from %u buffers written.\n", + all_written, bufcount); + free_buffers(write_item_p->buffer); + next_item_p = write_item_p->next; + rsbac_kfree(write_item_p); + write_item_p = next_item_p; + } + return count; + +out_free_all: + /* Mark unwritten lists dirty and free everything */ + while(write_item_p) + { + if(write_item_p->list->self == write_item_p->list) + write_item_p->list->dirty = TRUE; + free_buffers(write_item_p->buffer); + next_item_p = write_item_p->next; + rsbac_kfree(write_item_p); + write_item_p = next_item_p; + } + return count; +} +#endif /* ifndef CONFIG_RSBAC_NO_WRITE */ + +/************************************************* */ +/* PROC support */ +/************************************************* */ + +#if defined(CONFIG_RSBAC_PROC) +static int +lists_proc_show(struct seq_file *m, void *v) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + struct rsbac_list_reg_item_t *item_p; + struct rsbac_list_lol_reg_item_t *lol_item_p; + int i; + u_long tmp_count; + int srcu_idx; + struct rsbac_list_hashed_t * hashed; + struct rsbac_list_lol_hashed_t * lol_hashed; + u_int nr_hashes; + + if (unlikely(!rsbac_is_initialized())) + return -ENOSYS; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, + "Generic Lists Status\n--------------------\nMaximum number of hash bits per list/list of lists is %u\nrsbac_list_auto_rehash_trigger is %u\n%u list read failures\n", + rsbac_list_max_hash_bits, rsbac_list_auto_rehash_trigger, rsbac_list_read_errors); +#ifdef CONFIG_RSBAC_RC_LEARN_TA + seq_printf(m, "RC Learning Mode transaction Number: %u\n", + CONFIG_RSBAC_RC_LEARN_TA); +#endif +#ifdef CONFIG_RSBAC_AUTH_LEARN_TA + seq_printf(m, "AUTH Learning Mode transaction Number: %u\n", + CONFIG_RSBAC_AUTH_LEARN_TA); +#endif +#ifdef CONFIG_RSBAC_ACL_LEARN_TA + seq_printf(m, "ACL Learning Mode transaction Number: %u\n", + CONFIG_RSBAC_ACL_LEARN_TA); +#endif +#ifdef CONFIG_RSBAC_CAP_LEARN_TA + seq_printf(m, "CAP Learning Mode transaction Number: %u\n", + CONFIG_RSBAC_CAP_LEARN_TA); +#endif +#ifdef CONFIG_RSBAC_LIST_TRANS + if (rsbac_list_count(ta_handle) > 0) { + int list_count; + rsbac_list_ta_number_t *desc_array; + struct rsbac_list_ta_data_t data; + + seq_printf(m, "\nTransactions active:\n\n"); + list_count = + rsbac_list_get_all_desc(ta_handle, + (void **) &desc_array); + if (list_count > 0) { + int i; + rsbac_time_t now = RSBAC_CURRENT_TIME; + + for (i = 0; i < list_count; i++) { + if (!rsbac_list_get_data + (ta_handle, &desc_array[i], &data)) { + seq_printf(m, + "%u %s (ttl %is)\n", + desc_array[i], + data.name, + data.timeout - now); + } + } + rsbac_kfree(desc_array); + } + + seq_printf(m, + "\nLists in Transaction\n--------------------\nName\t\tdevice\thash\tta\t count\n"); + + list_count = 0; + srcu_idx = srcu_read_lock(®_list_srcu); + item_p = srcu_dereference(reg_head.head, ®_list_srcu); + while (item_p) { + rcu_read_lock(); + nr_hashes = 1 << item_p->hash_bits; + hashed = rcu_dereference(item_p->hashed); + for (i=0; iname, + RSBAC_MAJOR(item_p->device), + RSBAC_MINOR(item_p->device), + i, + hashed[i].ta_copied, + hashed[i].ta_count); + list_count++; + } + } + rcu_read_unlock(); + item_p = srcu_dereference(item_p->next, ®_list_srcu); + } + srcu_read_unlock(®_list_srcu, srcu_idx); + + seq_printf(m, + "\n %u lists in transaction.\n\n", list_count); + seq_printf(m, + "Lists of Lists in Transaction\n-----------------------------\nName\t\tdevice\thash\tta\t count\n"); + list_count = 0; + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + lol_item_p = srcu_dereference(lol_reg_head.head, &lol_reg_list_srcu); + while (lol_item_p) { + rcu_read_lock(); + nr_hashes = 1 << lol_item_p->hash_bits; + lol_hashed = rcu_dereference(lol_item_p->hashed); + for (i=0; iname, + RSBAC_MAJOR(lol_item_p-> + device), + RSBAC_MINOR(lol_item_p-> + device), + i, + lol_hashed[i].ta_copied, + lol_hashed[i].ta_count); + list_count++; + } + } + rcu_read_unlock(); + lol_item_p = srcu_dereference(lol_item_p->next, &lol_reg_list_srcu); + } + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + + seq_printf(m, + "\n %u lists of lists in transaction.\n\n", + list_count); + } else + seq_printf(m, "No active transaction\n"); +#endif + seq_printf(m, + "\nRegistered Generic Lists (item size %u + per hash %u)\n------------------------\n", + (int) sizeof(struct rsbac_list_reg_item_t), (int) sizeof(struct rsbac_list_hashed_t)); + seq_printf(m, + "Name\t\tdevice\tcount\tdesc\tdata\tpersist\tnow/dir\tflags\thashbits\n"); + + srcu_idx = srcu_read_lock(®_list_srcu); + item_p = srcu_dereference(reg_head.head, ®_list_srcu); + while (item_p) { + rcu_read_lock(); + nr_hashes = 1 << item_p->hash_bits; + hashed = rcu_dereference(item_p->hashed); + tmp_count = 0; + for (i=0; iname, RSBAC_MAJOR(item_p->device), + RSBAC_MINOR(item_p->device), tmp_count, + item_p->info.desc_size, item_p->info.data_size, + item_p->flags & RSBAC_LIST_PERSIST, + item_p->no_write, + item_p->dirty & (item_p-> + flags & RSBAC_LIST_PERSIST), + item_p->flags, + item_p->hash_bits); + item_p = srcu_dereference(item_p->next, ®_list_srcu); + } + srcu_read_unlock(®_list_srcu, srcu_idx); + + seq_printf(m, "\n %u lists registered.\n\n", + reg_head.count); + seq_printf(m, + "Registered Generic Lists of Lists (item size %u + per hash %u)\n---------------------------------\n", + (int) sizeof(struct rsbac_list_lol_reg_item_t), (int) sizeof(struct rsbac_list_lol_hashed_t)); + seq_printf(m, + "Name\t\tdevice\tcount\tdesc\tdata\tpersist\tnow/dir\tflags\thashbits\n"); + + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + lol_item_p = srcu_dereference(lol_reg_head.head, &lol_reg_list_srcu); + while (lol_item_p) { + rcu_read_lock(); + nr_hashes = 1 << lol_item_p->hash_bits; + lol_hashed = rcu_dereference(lol_item_p->hashed); + tmp_count = 0; + for (i=0; iname, + RSBAC_MAJOR(lol_item_p->device), + RSBAC_MINOR(lol_item_p->device), + tmp_count, lol_item_p->info.desc_size, + lol_item_p->info.subdesc_size, + lol_item_p->info.data_size, + lol_item_p->info.subdata_size, + lol_item_p->flags & RSBAC_LIST_PERSIST, + lol_item_p->no_write, + lol_item_p->dirty & (lol_item_p-> + flags & + RSBAC_LIST_PERSIST), + lol_item_p->flags, + lol_item_p->hash_bits); + lol_item_p = srcu_dereference(lol_item_p->next, &lol_reg_list_srcu); + } + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + + seq_printf(m, "\n %u lists of lists registered.\n", + lol_reg_head.count); + return 0; +} + +static int lists_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, lists_proc_show, NULL); +} + +static const struct file_operations lists_proc_fops = { + .owner = THIS_MODULE, + .open = lists_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *lists_proc; + +static int +lists_counts_proc_show(struct seq_file *m, void *v) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + struct rsbac_list_reg_item_t *item_p; + struct rsbac_list_lol_reg_item_t *lol_item_p; + int i; +#ifdef CONFIG_RSBAC_LIST_STATS + __u64 all_read = 0; + __u64 all_write = 0; +#endif + int srcu_idx; + struct rsbac_list_hashed_t * hashed; + struct rsbac_list_lol_hashed_t * lol_hashed; + u_int nr_hashes; + u_long subcount; + struct rsbac_list_lol_item_t *sublist; + + if (unlikely(!rsbac_is_initialized())) + return -ENOSYS; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, + "Generic Lists Status\n--------------------\nMaximum number of hash bits per list/list of lists is %u\n\n", + rsbac_list_max_hash_bits); + seq_printf(m, + "Registered Generic Lists (item size %u + per hash %u)\n------------------------\n", + (int) sizeof(struct rsbac_list_reg_item_t), (int) sizeof(struct rsbac_list_hashed_t)); +#ifdef CONFIG_RSBAC_LIST_STATS + seq_printf(m, + "Name\t\tdevice\tmaxitem\treads\twrites\thashbit\tcounts\n"); +#else + seq_printf(m, + "Name\t\tdevice\tmaxitem\thashbit\tcounts\n"); +#endif + srcu_idx = srcu_read_lock(®_list_srcu); + item_p = srcu_dereference(reg_head.head, ®_list_srcu); + while (item_p) { +#ifdef CONFIG_RSBAC_LIST_STATS + seq_printf(m, + "%-16s%02u:%02u\t%u\t%llu\t%llu\t%u\t", + item_p->name, RSBAC_MAJOR(item_p->device), + RSBAC_MINOR(item_p->device), + item_p->max_items_per_hash, + item_p->read_count, + item_p->write_count, + item_p->hash_bits); + all_read += item_p->read_count; + all_write += item_p->write_count; +#else + seq_printf(m, + "%-16s%02u:%02u\t%u\t%u\t", + item_p->name, RSBAC_MAJOR(item_p->device), + RSBAC_MINOR(item_p->device), + item_p->max_items_per_hash, + item_p->hash_bits); +#endif + rcu_read_lock(); + nr_hashes = 1 << item_p->hash_bits; + hashed = rcu_dereference(item_p->hashed); + for (i=0; inext, ®_list_srcu); + } + srcu_read_unlock(®_list_srcu, srcu_idx); + +#ifdef CONFIG_RSBAC_LIST_STATS + seq_printf(m, "\n %u lists registered, %llu reads, %llu writes\n\n", + reg_head.count, all_read, all_write); + all_read = 0; + all_write = 0; +#else + seq_printf(m, "\n %u lists registered.\n\n", + reg_head.count); +#endif + seq_printf(m, + "Registered Generic Lists of Lists (item size %u + per hash %u)\n---------------------------------\n", + (int) sizeof(struct rsbac_list_lol_reg_item_t), (int) sizeof(struct rsbac_list_lol_hashed_t)); +#ifdef CONFIG_RSBAC_LIST_STATS + seq_printf(m, + "Name\t\tdevice\tmaxitem\tmaxsubi\treads\twrites\thashbit\tcounts(sub)\n"); +#else + seq_printf(m, + "Name\t\tdevice\tmaxitem\tmaxsubi\thashbit\tcounts(sub)\n"); +#endif + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + lol_item_p = srcu_dereference(lol_reg_head.head, &lol_reg_list_srcu); + while (lol_item_p) { +#ifdef CONFIG_RSBAC_LIST_STATS + seq_printf(m, + "%-16s%02u:%02u\t%u\t%u\t%llu\t%llu\t%u\t", + lol_item_p->name, RSBAC_MAJOR(lol_item_p->device), + RSBAC_MINOR(lol_item_p->device), + lol_item_p->max_items_per_hash, + lol_item_p->max_subitems, + lol_item_p->read_count, + lol_item_p->write_count, + lol_item_p->hash_bits); + all_read += lol_item_p->read_count; + all_write += lol_item_p->write_count; +#else + seq_printf(m, + "%-16s%02u:%02u\t%u\t%u\t%u\t", + lol_item_p->name, RSBAC_MAJOR(lol_item_p->device), + RSBAC_MINOR(lol_item_p->device), + lol_item_p->max_items_per_hash, + lol_item_p->max_subitems, + lol_item_p->hash_bits); +#endif + rcu_read_lock(); + nr_hashes = 1 << lol_item_p->hash_bits; + lol_hashed = rcu_dereference(lol_item_p->hashed); + for (i=0; icount; + sublist = rcu_dereference(sublist->next); + } + seq_printf(m, + "%u(%lu) ", + lol_hashed[i].count, + subcount); + } + rcu_read_unlock(); + seq_printf(m, + "\n"); + lol_item_p = srcu_dereference(lol_item_p->next, &lol_reg_list_srcu); + } + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + +#ifdef CONFIG_RSBAC_LIST_STATS + seq_printf(m, "\n %u lists of lists registered, %llu reads, %llu writes\n\nRCU Garbage Collector call statistics\n-------------------------------------\n", + lol_reg_head.count, all_read, all_write); + seq_printf(m, "rcu_free: %llu\n", rcu_free_calls); + seq_printf(m, "rcu_free_item_chain: %llu\n", rcu_free_item_chain_calls); + seq_printf(m, "rcu_free_lol: %llu\n", rcu_free_lol_calls); + seq_printf(m, "rcu_free_lol_sub: %llu\n", rcu_free_lol_sub_calls); + seq_printf(m, "rcu_free_lol_item_chain: %llu\n", rcu_free_lol_item_chain_calls); + seq_printf(m, "rcu_free_lol_subitem_chain: %llu\n", rcu_free_lol_subitem_chain_calls); + seq_printf(m, "rcu_free_do_cleanup: %llu\n", rcu_free_do_cleanup_calls); + seq_printf(m, "rcu_free_do_cleanup_lol: %llu\n", rcu_free_do_cleanup_lol_calls); + seq_printf(m, "rcu_free_callback: %llu\n", rcu_free_callback_calls); + seq_printf(m, "rcu_free_callback_lol: %llu\n", rcu_free_callback_lol_calls); + seq_printf(m, "rcu_callback_count: %u\n", rcu_callback_count); + seq_printf(m, "max_rcu_callback_count: %u\n", max_rcu_callback_count); + seq_printf(m, "rcu_rate: %u/s\n", rsbac_list_rcu_rate); + /*seq_printf(m, "system RCU total completed: %lu\n", rcu_batches_completed());*/ +#else + seq_printf(m, "\n %u lists of lists registered.\n", + lol_reg_head.count); +#endif + return 0; +} + +static int lists_counts_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, lists_counts_proc_show, NULL); +} + +static const struct file_operations lists_counts_proc_fops = { + .owner = THIS_MODULE, + .open = lists_counts_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *lists_counts_proc; + +/* Generic backup generation function */ +static int backup_proc_show(struct seq_file *m, void *data) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *current_p; + rsbac_version_t list_version = RSBAC_LIST_DISK_VERSION; + rsbac_time_t timestamp = RSBAC_CURRENT_TIME; + int srcu_idx; + struct rsbac_list_hashed_t * hashed; + u_int nr_hashes; + int i; + + if (unlikely(!rsbac_is_initialized())) + return -ENOSYS; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + srcu_idx = srcu_read_lock(®_list_srcu); + list = lookup_reg(data); + if (unlikely(!list)) { + srcu_read_unlock(®_list_srcu, srcu_idx); + return -ENOSYS; + } + /* copy version */ + seq_write(m, &list_version, sizeof(list_version)); + /* copy version */ + seq_write(m, ×tamp, sizeof(timestamp)); + /* copy info */ + seq_write(m, &list->info, sizeof(list->info)); + + rcu_read_lock(); + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + /* copy list */ + for (i=0; iinfo.desc_size + list->info.data_size); + current_p = rcu_dereference(current_p->next); + } + } + + rcu_read_unlock(); + srcu_read_unlock(®_list_srcu, srcu_idx); + return 0; +} + +/* Generic lists of lists backup generation function */ +static int lol_backup_proc_show(struct seq_file *m, void *data) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *current_p; + struct rsbac_list_item_t *sub_p; + rsbac_version_t list_version = RSBAC_LIST_DISK_VERSION; + rsbac_time_t timestamp = RSBAC_CURRENT_TIME; + int srcu_idx; + struct rsbac_list_lol_hashed_t * hashed; + u_int nr_hashes; + int i; + + if (unlikely(!rsbac_is_initialized())) + return -ENOSYS; + + rsbac_pr_debug(aef, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + list = lookup_lol_reg(data); + if (unlikely(!list)) { + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + return -ENOSYS; + } + /* copy version */ + seq_write(m, &list_version, sizeof(list_version)); + /* copy version */ + seq_write(m, ×tamp, sizeof(timestamp)); + /* copy info */ + seq_write(m, &list->info, sizeof(list->info)); + + rcu_read_lock(); + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + /* copy list */ + for (i=0; iinfo.desc_size + list->info.data_size); + seq_write(m, + ¤t_p->count, sizeof(current_p->count)); + /* copy sublist */ + sub_p = rcu_dereference(current_p->head); + while (sub_p) { + seq_write(m, + ((char *) sub_p) + sizeof(*sub_p), + list->info.subdesc_size + + list->info.subdata_size); + sub_p = rcu_dereference(sub_p->next); + } + current_p = rcu_dereference(current_p->next); + } + } + rcu_read_unlock(); + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + return 0; +} +#endif /* PROC */ + + +/********************/ +/* Init and general */ +/********************/ +int rsbac_list_compare_u32(void * desc1, void * desc2) + { + if( *((__u32*) desc1) < *((__u32*) desc2)) + return -1; + return( *((__u32*) desc1) != *((__u32*) desc2)); + } + +static void rcu_rate_reset(u_long dummy) +{ +#ifdef CONFIG_RSBAC_DEBUG + if (rcu_callback_count > rsbac_list_rcu_rate) { + rsbac_pr_debug(lists, + "rcu_callback_count %u over rcu_rate %u, list write accesses have been throttled\n", + rcu_callback_count, rsbac_list_rcu_rate); + } +#endif +#ifdef CONFIG_RSBAC_LIST_STATS + if (rcu_callback_count > max_rcu_callback_count) + max_rcu_callback_count = rcu_callback_count; +#endif + rcu_callback_count = 0; + + mod_timer(&rcu_rate_timer, jiffies + HZ); +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_list_init(void) +#else +int __init rsbac_list_init(void) +#endif +{ +#if defined(CONFIG_RSBAC_LIST_TRANS) || defined(CONFIG_RSBAC_LIST_REPL) + int err; + struct rsbac_list_info_t *list_info_p; +#endif + reg_item_slab = rsbac_slab_create_rcu("rsbac_reg_item", + sizeof(struct rsbac_list_reg_item_t)); + lol_reg_item_slab = rsbac_slab_create_rcu("rsbac_lol_reg_item", + sizeof(struct rsbac_list_lol_reg_item_t)); + rcu_free_item_slab = rsbac_slab_create("rsbac_rcu_free_item", + sizeof(struct rsbac_list_rcu_free_item_t)); + rcu_free_head_slab = rsbac_slab_create("rsbac_rcu_free_head", + sizeof(struct rsbac_list_rcu_free_head_t)); + rcu_free_head_lol_slab = rsbac_slab_create("rsbac_rcu_free_head_lol", + sizeof(struct rsbac_list_rcu_free_head_lol_t)); + + reg_head.head = NULL; + reg_head.tail = NULL; + reg_head.curr = NULL; + spin_lock_init(®_head.lock); + init_srcu_struct(®_list_srcu); + init_srcu_struct(&lol_reg_list_srcu); + reg_head.count = 0; + + lol_reg_head.head = NULL; + lol_reg_head.tail = NULL; + lol_reg_head.curr = NULL; + spin_lock_init(&lol_reg_head.lock); + lol_reg_head.count = 0; + + if(CONFIG_RSBAC_LIST_MAX_HASH_BITS < RSBAC_LIST_MIN_MAX_HASH_BITS) + rsbac_list_max_hash_bits = RSBAC_LIST_MIN_MAX_HASH_BITS; + else if (CONFIG_RSBAC_LIST_MAX_HASH_BITS > RSBAC_LIST_MAX_MAX_HASH_BITS) + rsbac_list_max_hash_bits = RSBAC_LIST_MAX_MAX_HASH_BITS; + else + rsbac_list_max_hash_bits = CONFIG_RSBAC_LIST_MAX_HASH_BITS; + + list_initialized = TRUE; + +#if defined(CONFIG_RSBAC_LIST_TRANS) || defined(CONFIG_RSBAC_LIST_REPL) + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (unlikely(!list_info_p)) { + return -ENOMEM; + } +#endif + + /* init proc entry */ +#if defined(CONFIG_RSBAC_PROC) + { + lists_proc = proc_create(RSBAC_LIST_PROC_NAME, S_IFREG | S_IRUGO, + proc_rsbac_root_p, &lists_proc_fops); + lists_counts_proc = proc_create(RSBAC_LIST_COUNTS_PROC_NAME, + S_IFREG | S_IRUGO, + proc_rsbac_root_p, + &lists_counts_proc_fops); + } +#endif + +#ifdef CONFIG_RSBAC_LIST_TRANS + rsbac_printk(KERN_INFO "rsbac_list_init(): Registering transaction list.\n"); + list_info_p->version = 1; + list_info_p->key = RSBAC_LIST_TA_KEY; + list_info_p->desc_size = sizeof(rsbac_list_ta_number_t); + list_info_p->data_size = sizeof(struct rsbac_list_ta_data_t); + list_info_p->max_age = 0; + err = rsbac_list_register(RSBAC_LIST_VERSION, + (void **) &ta_handle, + list_info_p, + 0, + NULL, + NULL, + NULL, "transactions", RSBAC_AUTO_DEV); + if (err) { + char *tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_list_init(): Registering transaction list failed with error %s\n", + get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } +#endif + +#if defined(CONFIG_RSBAC_LIST_TRANS) || defined(CONFIG_RSBAC_LIST_REPL) + rsbac_kfree(list_info_p); +#endif + + init_timer(&rcu_rate_timer); + rcu_rate_timer.function = rcu_rate_reset; + rcu_rate_timer.data = 0; + rcu_rate_timer.expires = jiffies + HZ; + add_timer(&rcu_rate_timer); + return 0; +} + +#ifdef CONFIG_RSBAC_AUTO_WRITE +int rsbac_list_auto_rehash(void); + +int rsbac_write_lists(void) +{ + int count = 0; + int subcount = 0; + int error = 0; + struct rsbac_list_reg_item_t *item_p; + struct rsbac_list_lol_reg_item_t *lol_item_p; + struct rsbac_list_write_head_t write_head; + struct rsbac_list_write_item_t *write_item_p; + struct rsbac_list_lol_write_head_t write_lol_head; + struct rsbac_list_lol_write_item_t *write_lol_item_p; + int srcu_idx; + +/* + rsbac_pr_debug(lists, "called.\n"); +*/ + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + +#ifdef CONFIG_RSBAC_LIST_TRANS + if (rsbac_list_count(ta_handle) > 0) { + int list_count; + rsbac_list_ta_number_t *desc_array; + struct rsbac_list_ta_data_t data; + + list_count = + rsbac_list_get_all_desc(ta_handle, + (void **) &desc_array); + if (list_count > 0) { + int i; + rsbac_time_t now = RSBAC_CURRENT_TIME; + + for (i = 0; i < list_count; i++) { + if (!rsbac_list_get_data + (ta_handle, &desc_array[i], &data)) { + if (data.timeout < now) { + rsbac_printk(KERN_WARNING "rsbac_write_lists(): transaction %u timed out, forcing forget\n", + desc_array + [i]); + do_forget(desc_array[i]); + } + } + } + rsbac_kfree(desc_array); + } + } +#endif + + /* Init buffer list */ + write_head.head = NULL; + write_head.tail = NULL; + write_head.count = 0; + + srcu_idx = srcu_read_lock(®_list_srcu); + item_p = srcu_dereference(reg_head.head, ®_list_srcu); + while (item_p) { + if ((item_p->flags & RSBAC_LIST_PERSIST) + && item_p->dirty && !item_p->no_write + && !rsbac_debug_no_write) { + struct vfsmount *mnt_p; + + mnt_p = rsbac_get_vfsmount(item_p->device); + if (mnt_p && rsbac_writable(mnt_p->mnt_sb)) { + item_p->dirty = FALSE; + error = fill_buffer(item_p, &write_item_p); + if (!error) { + if (!write_head.head) { + write_head.head = write_item_p; + write_head.tail = write_item_p; + write_head.count = 1; + } else { + write_head.tail->next = + write_item_p; + write_item_p->prev = + write_head.tail; + write_head.tail = write_item_p; + write_head.count++; + } + } else { + if ((error != -RSBAC_ENOTWRITABLE) + && (error != -RSBAC_ENOMEM) + ) { + rsbac_printk(KERN_WARNING "rsbac_write_lists(): fill_buffer() for list %s returned error %i\n", + item_p->name, error); + item_p->dirty = TRUE; + } + } + } + } + item_p = srcu_dereference(item_p->next, ®_list_srcu); + } + srcu_read_unlock(®_list_srcu, srcu_idx); + + if (write_head.count > 0) + rsbac_pr_debug(write, "%u lists copied to buffers\n", + write_head.count); + + /* write all buffers */ + if (write_head.count) { + count = rsbac_list_write_buffers(write_head); + rsbac_pr_debug(write, "%u lists written to disk\n", count); + } + + /* LOL */ + /* Init buffer list */ + write_lol_head.head = NULL; + write_lol_head.tail = NULL; + write_lol_head.count = 0; + + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + lol_item_p = srcu_dereference(lol_reg_head.head, &lol_reg_list_srcu); + while (lol_item_p) { + if ((lol_item_p->flags & RSBAC_LIST_PERSIST) + && lol_item_p->dirty && !lol_item_p->no_write + && !rsbac_debug_no_write) { + struct vfsmount *mnt_p; + + mnt_p = rsbac_get_vfsmount(lol_item_p->device); + if (mnt_p && rsbac_writable(mnt_p->mnt_sb)) { + lol_item_p->dirty = FALSE; + error = fill_lol_buffer(lol_item_p, &write_lol_item_p); + if (!error) { + if (!write_lol_head.head) { + write_lol_head.head = + write_lol_item_p; + write_lol_head.tail = + write_lol_item_p; + write_lol_head.count = 1; + } else { + write_lol_head.tail->next = + write_lol_item_p; + write_lol_item_p->prev = + write_lol_head.tail; + write_lol_head.tail = + write_lol_item_p; + write_lol_head.count++; + } + } else { + if ((error != -RSBAC_ENOTWRITABLE) + && (error != -RSBAC_ENOMEM)) + { + rsbac_printk(KERN_WARNING "rsbac_write_lists(): fill_lol_buffer() for list %s returned error %i\n", + lol_item_p->name, + error); + } + lol_item_p->dirty = TRUE; + } + } + } + lol_item_p = srcu_dereference(lol_item_p->next, &lol_reg_list_srcu); + } + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + + if (write_lol_head.count > 0) + rsbac_pr_debug(write, "%u lists of lists copied to buffers\n", + write_lol_head.count); + /* write all buffers */ + if (write_lol_head.count) { + subcount = + rsbac_list_write_lol_buffers(write_lol_head); + count += subcount; + rsbac_pr_debug(write, "%u lists of lists written to disk\n", + subcount); + } + rsbac_pr_debug(write, "%u lists written.\n", + count); + + if(jiffies > next_rehash) { + rsbac_list_auto_rehash(); + next_rehash = jiffies + (RSBAC_LIST_REHASH_INTERVAL * HZ); + } + return count; +} +#endif /* CONFIG_RSBAC_AUTO_WRITE */ + +/* Status checking */ +int rsbac_check_lists(const int correct) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_lol_reg_item_t *lol_list; + struct rsbac_list_item_t *item_p; + struct rsbac_list_item_t *next_item_p; + struct rsbac_list_lol_item_t *lol_item_p; + struct rsbac_list_lol_item_t *next_lol_item_p; + struct rsbac_list_item_t *lol_subitem_p; + struct rsbac_list_item_t *next_lol_subitem_p; + u_long tmp_count; + u_long tmp_subcount; + u_long subitem_count; + u_long dirty = 0; + u_int remove_count; + int i; + u_long all_count; + struct rsbac_list_rcu_free_head_t * rcu_head_p; + struct rsbac_list_rcu_free_head_lol_t * rcu_head_lol_p; + int srcu_idx; + u_int nr_hashes; + + rsbac_pr_debug(lists, "called.\n"); + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + srcu_idx = srcu_read_lock(®_list_srcu); + list = srcu_dereference(reg_head.head, ®_list_srcu); + while (list) { +restart: + nr_hashes = 1 << list->hash_bits; + remove_count = 0; + /* check list */ + spin_lock(&list->lock); + all_count = 0; + for (i=0; ihashed[i].head; + while (item_p) { + if ((item_p->max_age + && (item_p->max_age <= RSBAC_CURRENT_TIME) + ) + || (list->def_data + && !memcmp(((char *) item_p) + + sizeof(*item_p) + + list->info.desc_size, + list->def_data, + list->info.data_size) + ) + ) { + next_item_p = item_p->next; + do_remove_item(list, item_p, i); + remove_count++; + if (remove_count > rsbac_list_rcu_rate) { + rcu_head_p = get_rcu_free(list); + spin_unlock(&list->lock); + synchronize_rcu(); + rcu_free_do_cleanup(rcu_head_p); + goto restart; + } + item_p = next_item_p; + } else { + tmp_count++; + if (tmp_count > (2 * list->max_items_per_hash)) { + tmp_count = 0; + rsbac_printk(KERN_WARNING "rsbac_check_lists(): list %s hash %u on device %02u:%02u counts an invalid number %lu of items, should be %u, skipping further checks!\n", + list->name, i, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + tmp_count, list->hashed[i].count); + } + item_p = item_p->next; + } + } + if ((tmp_count > 0) && (tmp_count != list->hashed[i].count)) { + if (correct) { + rsbac_printk(KERN_WARNING "rsbac_check_lists(): correcting count mismatch for list %s hash %u on device %02u:%02u - was %u, counted %lu!\n", + list->name, i, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + list->hashed[i].count, tmp_count); + list->hashed[i].count = tmp_count; + } else { + rsbac_printk(KERN_WARNING "rsbac_check_lists(): count mismatch for list %s hash %u on device %02u:%02u - is %u, counted %lu!\n", + list->name, i, + RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + list->hashed[i].count, tmp_count); + } + } + all_count += list->hashed[i].count; + } + rcu_head_p = get_rcu_free(list); + spin_unlock(&list->lock); + do_sync_rcu(rcu_head_p); + if (list->dirty && (list->flags & RSBAC_LIST_PERSIST)) { + dirty++; + rsbac_pr_debug(lists, "%s on %02u:%02u has %u items (list is dirty)\n", + list->name, RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), all_count); + } else + rsbac_pr_debug(lists, "%s on %02u:%02u has %u items\n", + list->name, RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), all_count); + list = srcu_dereference(list->next, ®_list_srcu); + } + srcu_read_unlock(®_list_srcu, srcu_idx); + + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + lol_list = srcu_dereference(lol_reg_head.head, &lol_reg_list_srcu); + while (lol_list) { +lol_restart: + nr_hashes = 1 << lol_list->hash_bits; + remove_count = 0; + /* check list */ + spin_lock(&lol_list->lock); + all_count = 0; + subitem_count = 0; + for (i=0; ihashed[i].head; + while (lol_item_p) { + tmp_subcount = 0; + lol_subitem_p = lol_item_p->head; + while (lol_subitem_p) { + if ((lol_subitem_p->max_age + && (lol_subitem_p->max_age <= + RSBAC_CURRENT_TIME) + ) + || (lol_list->def_subdata + && + !memcmp(((char *) + lol_subitem_p) + + sizeof + (*lol_subitem_p) + + lol_list->info. + subdesc_size, + lol_list-> + def_subdata, + lol_list->info. + subdata_size) + ) + ) { + next_lol_subitem_p = + lol_subitem_p->next; + do_remove_lol_subitem + (lol_item_p, + lol_subitem_p); + rcu_free_lol_sub(lol_list, lol_subitem_p); + lol_subitem_p = + next_lol_subitem_p; + } else { + tmp_subcount++; + lol_subitem_p = + lol_subitem_p->next; + } + } + if (tmp_subcount != lol_item_p->count) { + if (correct) { + rsbac_printk(KERN_WARNING "rsbac_check_lists(): correcting count mismatch for list of lists %s hash %u sublist on %02u:%02u - was %lu, counted %lu!\n", + lol_list->name, i, + RSBAC_MAJOR + (lol_list-> + device), + RSBAC_MINOR + (lol_list-> + device), + lol_item_p-> + count, + tmp_subcount); + lol_item_p->count = + tmp_subcount; + } else { + rsbac_printk(KERN_WARNING "rsbac_check_lists(): count mismatch for list of lists %s hash %u sublist on %02u:%02u - is %lu, counted %lu!\n", + lol_list->name, i, + RSBAC_MAJOR + (lol_list-> + device), + RSBAC_MINOR + (lol_list-> + device), + lol_item_p-> + count, + tmp_subcount); + } + } + if ((lol_item_p->max_age + && (lol_item_p->max_age <= RSBAC_CURRENT_TIME) + ) + || (lol_list->def_data + && !lol_item_p->count + && !memcmp(((char *) lol_item_p) + + sizeof(*lol_item_p) + + lol_list->info.desc_size, + lol_list->def_data, + lol_list->info.data_size) + ) + || (!lol_list->info.data_size + && (lol_list->flags & RSBAC_LIST_DEF_DATA) + && !lol_item_p->count) + ) { + next_lol_item_p = lol_item_p->next; + do_remove_lol_item(lol_list, lol_item_p, i); + remove_count++; + if (remove_count > rsbac_list_rcu_rate) { + rcu_head_lol_p = get_rcu_free_lol(lol_list); + spin_unlock(&lol_list->lock); + synchronize_rcu(); + rcu_free_do_cleanup_lol(rcu_head_lol_p); + goto lol_restart; + } + lol_item_p = next_lol_item_p; + } else { + tmp_count++; + subitem_count += lol_item_p->count; + lol_item_p = lol_item_p->next; + if (tmp_count > (2 * lol_list->max_items_per_hash)) { + tmp_count = 0; + rsbac_printk(KERN_WARNING "rsbac_check_lists(): list of lists %s hash %u on device %02u:%02u counts an invalid number %lu of items, should be %u, skipping further checks!\n", + lol_list->name, i, + RSBAC_MAJOR(lol_list->device), + RSBAC_MINOR(lol_list->device), + tmp_count, lol_list->hashed[i].count); + } + } + } + if ((tmp_count > 0) && (tmp_count != lol_list->hashed[i].count)) { + if (correct) { + rsbac_printk(KERN_WARNING "rsbac_check_lists(): correcting count mismatch for list of lists %s hash %u on %02u:%02u - was %u, counted %lu!\n", + lol_list->name, i, + RSBAC_MAJOR(lol_list->device), + RSBAC_MINOR(lol_list->device), + lol_list->hashed[i].count, tmp_count); + lol_list->hashed[i].count = tmp_count; + } else { + rsbac_printk(KERN_WARNING "rsbac_check_lists(): count mismatch for list of lists %s hash %u on %02u:%02u - is %u, counted %lu!\n", + lol_list->name, i, + RSBAC_MAJOR(lol_list->device), + RSBAC_MINOR(lol_list->device), + lol_list->hashed[i].count, tmp_count); + } + } + all_count += lol_list->hashed[i].count; + } + rcu_head_lol_p = get_rcu_free_lol(lol_list); + spin_unlock(&lol_list->lock); + do_sync_rcu_lol(rcu_head_lol_p); + if (lol_list->dirty + && (lol_list->flags & RSBAC_LIST_PERSIST)) { + dirty++; + rsbac_pr_debug(lists, "%s on %02u:%02u has %u items and %lu subitems (list is dirty)\n", + lol_list->name, + RSBAC_MAJOR(lol_list->device), + RSBAC_MINOR(lol_list->device), + all_count, subitem_count); + } else + rsbac_pr_debug(lists, "%s on %02u:%02u has %u items and %lu subitems\n", + lol_list->name, + RSBAC_MAJOR(lol_list->device), + RSBAC_MINOR(lol_list->device), + all_count, subitem_count); + lol_list = srcu_dereference(lol_list->next, &lol_reg_list_srcu); + } + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + return 0; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_check); +#endif +int rsbac_list_check(rsbac_list_handle_t handle, const int correct) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *item_p; + struct rsbac_list_item_t *next_item_p; + u_long tmp_count; + int i; + struct rsbac_list_rcu_free_head_t * rcu_head_p; + u_int remove_count; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(!list || (list->self != list))) + return -RSBAC_EINVALIDLIST; + + rsbac_pr_debug(lists, "checking list %s.\n", list->name); + +restart: + remove_count = 0; + + spin_lock(&list->lock); + nr_hashes = 1 << list->hash_bits; + for (i=0; ihashed[i].head; + while (item_p) { + if ((item_p->max_age + && (item_p->max_age <= RSBAC_CURRENT_TIME) + ) + || (list->def_data + && !memcmp(((char *) item_p) + sizeof(*item_p) + + list->info.desc_size, list->def_data, + list->info.data_size) + ) + ) { + next_item_p = item_p->next; + do_remove_item(list, item_p, i); + remove_count++; + if (remove_count > rsbac_list_rcu_rate) { + rcu_head_p = get_rcu_free(list); + spin_unlock(&list->lock); + synchronize_rcu(); + rcu_free_do_cleanup(rcu_head_p); + goto restart; + } + item_p = next_item_p; + list->dirty = TRUE; + } else { + tmp_count++; + item_p = item_p->next; + } + } + if (tmp_count != list->hashed[i].count) { + if (correct) { + rsbac_printk(KERN_WARNING "rsbac_list_check(): correcting count mismatch for list %s hash %u on device %02u:%02u - was %u, counted %lu!\n", + list->name, i, RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + list->hashed[i].count, tmp_count); + list->hashed[i].count = tmp_count; + list->dirty = TRUE; + } else { + rsbac_printk(KERN_WARNING "rsbac_list_check(): count mismatch for list %s hash %u on device %02u:%02u - is %u, counted %lu!\n", + list->name, i, RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device), + list->hashed[i].count, tmp_count); + } + } + } + rcu_head_p = get_rcu_free(list); + spin_unlock(&list->lock); + synchronize_rcu(); + rcu_free_do_cleanup(rcu_head_p); + return 0; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_lol_check); +#endif +int rsbac_list_lol_check(rsbac_list_handle_t handle, const int correct) +{ + struct rsbac_list_lol_reg_item_t *lol_list; + struct rsbac_list_lol_item_t *lol_item_p; + struct rsbac_list_lol_item_t *next_lol_item_p; + struct rsbac_list_item_t *lol_subitem_p; + struct rsbac_list_item_t *next_lol_subitem_p; + u_long tmp_count; + u_long tmp_subcount; + int i; + struct rsbac_list_rcu_free_head_lol_t * rcu_head_lol_p; + u_int remove_count; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + lol_list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(!lol_list || (lol_list->self != lol_list))) + return -RSBAC_EINVALIDLIST; + + rsbac_pr_debug(lists, "checking list %s.\n", lol_list->name); + +restart: + remove_count = 0; + spin_lock(&lol_list->lock); + nr_hashes = 1 << lol_list->hash_bits; + for (i=0; ihashed[i].head; + while (lol_item_p) { + if ((lol_item_p->max_age + && (lol_item_p->max_age <= RSBAC_CURRENT_TIME) + ) + || (lol_list->def_data + && !lol_item_p->count + && !memcmp(((char *) lol_item_p) + + sizeof(*lol_item_p) + + lol_list->info.desc_size, + lol_list->def_data, + lol_list->info.data_size) + ) + || (!lol_list->info.data_size + && (lol_list->flags & RSBAC_LIST_DEF_DATA) + && !lol_item_p->count) + ) { + next_lol_item_p = lol_item_p->next; + do_remove_lol_item(lol_list, lol_item_p, i); + remove_count++; + if (remove_count > rsbac_list_rcu_rate) { + rcu_head_lol_p = get_rcu_free_lol(lol_list); + spin_unlock(&lol_list->lock); + synchronize_rcu(); + rcu_free_do_cleanup_lol(rcu_head_lol_p); + goto restart; + } + lol_item_p = next_lol_item_p; + } else { + tmp_count++; + tmp_subcount = 0; + lol_subitem_p = lol_item_p->head; + while (lol_subitem_p) { + if ((lol_subitem_p->max_age + && (lol_subitem_p->max_age <= + RSBAC_CURRENT_TIME) + ) + || (lol_list->def_subdata + && !memcmp(((char *) lol_subitem_p) + + + sizeof(*lol_subitem_p) + + lol_list->info. + subdesc_size, + lol_list->def_subdata, + lol_list->info. + subdata_size) + ) + ) { + next_lol_subitem_p = + lol_subitem_p->next; + do_remove_lol_subitem(lol_item_p, + lol_subitem_p); + rcu_free_lol_sub(lol_list, lol_subitem_p); + lol_subitem_p = next_lol_subitem_p; + } else { + tmp_subcount++; + lol_subitem_p = + lol_subitem_p->next; + } + } + if (tmp_subcount != lol_item_p->count) { + if (correct) { + rsbac_printk(KERN_WARNING "rsbac_list_lol_check(): correcting count mismatch for list of lists %s hash %u sublist on %02u:%02u - was %lu, counted %lu!\n", + lol_list->name, i, + RSBAC_MAJOR(lol_list-> + device), + RSBAC_MINOR(lol_list-> + device), + lol_item_p->count, + tmp_subcount); + lol_item_p->count = tmp_subcount; + } else { + rsbac_printk(KERN_WARNING "rsbac_list_lol_check(): count mismatch for list of lists %s hash %u sublist on %02u:%02u - is %lu, counted %lu!\n", + lol_list->name, i, + RSBAC_MAJOR(lol_list-> + device), + RSBAC_MINOR(lol_list-> + device), + lol_item_p->count, + tmp_subcount); + } + } + lol_item_p = lol_item_p->next; + } + } + if (tmp_count != lol_list->hashed[i].count) { + if (correct) { + rsbac_printk(KERN_WARNING "rsbac_list_lol_check(): correcting count mismatch for list of lists %s hash %u on %02u:%02u - was %u, counted %lu!\n", + lol_list->name, i, + RSBAC_MAJOR(lol_list->device), + RSBAC_MINOR(lol_list->device), + lol_list->hashed[i].count, tmp_count); + lol_list->hashed[i].count = tmp_count; + } else { + rsbac_printk(KERN_WARNING "rsbac_list_lol_check(): count mismatch for list of lists %s hash %u on %02u:%02u - is %u, counted %lu!\n", + lol_list->name, i, + RSBAC_MAJOR(lol_list->device), + RSBAC_MINOR(lol_list->device), + lol_list->hashed[i].count, tmp_count); + } + } + } + rcu_head_lol_p = get_rcu_free_lol(lol_list); + spin_unlock(&lol_list->lock); + synchronize_rcu(); + rcu_free_do_cleanup_lol(rcu_head_lol_p); + return 0; +} + + +/********************/ +/* Registration */ +/********************/ + +/* get generic list registration version */ +inline rsbac_version_t rsbac_list_version(void) +{ + return RSBAC_LIST_VERSION; +} + +#if defined(CONFIG_RSBAC_PROC) +static int backup_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, backup_proc_show, NULL); +} + +static const struct file_operations backup_proc_fops = { + .owner = THIS_MODULE, + .open = backup_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int lol_backup_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, lol_backup_proc_show, NULL); +} + +static const struct file_operations lol_backup_proc_fops = { + .owner = THIS_MODULE, + .open = lol_backup_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + +/* register a new list */ +/* + * If list with same name exists in memory, error -RSBAC_EEXISTS is returned. + * If list with same name and key exists on device, it is restored depending on the flags. + * If list with same name, but different key exists, access is denied (error -EPERM). + * + * ds_version: for binary modules, must be RSBAC_LIST_VERSION. If version differs, return error. + * handle_p: for all list accesses, an opaque handle is put into *handle_p. + * key: positive, secret __u32 key, which must be the same as in on-disk version, if persistent + * list_version: positive __u32 version number for the list. If old on-disk version is + different, upconversion is tried (depending on flags and get_conv function) + * flags: see flag values + * desc_size: size of the descriptor (error is returned, if value is 0 or list exists and value differs) + * data_size: size of data (error is returned, if list exists and value differs). Can be 0 for sets. + * compare: for lookup and list optimization, can be NULL, then + memcmp(desc1, desc2, desc_size) is used + * def_data: default data value for flag RSBAC_LIST_DEF_DATA + (if NULL, flag is cleared) + * name: the on-disk name, must be distinct and max. 7 or 8.2 chars + (only used for statistics, if non-persistent) + * device: the device to read list from or to save list to - use 0 for root dev + (ignored, if non-persistent) + * hash_bits: Number of bits of hashes for this list, minimum is 1, + maximum is rsbac_list_max_hash_bits, + which is derived from CONFIG_RSBAC_LIST_MAX_HASH_BITS and must not be more than 31 + Number of hashes is 2^hash_bits. + If > maximum, it will be reduced to maximum automatically. + * hash_function: Hash function(desc,hash_bits), must always return a value + from 0 to 2^hash_bits - 1. + * old_base_name: If not NULL and persistent list with name cannot be read, + try to read all old_base_name with n from 0 to 31. + */ + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_register_hashed); +#endif +int rsbac_list_register_hashed(rsbac_version_t ds_version, + rsbac_list_handle_t * handle_p, + struct rsbac_list_info_t *info_p, + u_int flags, + rsbac_list_compare_function_t * compare, + rsbac_list_get_conv_t * get_conv, + void *def_data, char *name, kdev_t device, + __u8 hash_bits, + rsbac_list_hash_function_t hash_function, + char * old_base_name) +{ + struct rsbac_list_reg_item_t *reg_item_p; + struct rsbac_list_reg_item_t *new_reg_item_p; + int err = 0; + int srcu_idx; + + if (unlikely(ds_version != RSBAC_LIST_VERSION)) { + if (name) { + rsbac_printk(KERN_WARNING "rsbac_list_register: wrong ds_version %u for list %s, expected %u!\n", + ds_version, name, RSBAC_LIST_VERSION); + } + return -RSBAC_EINVALIDVERSION; + } + if (unlikely(!handle_p || !info_p)) + return -RSBAC_EINVALIDPOINTER; + *handle_p = NULL; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + if (unlikely(!info_p->key || !info_p->version || !info_p->desc_size)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(info_p->max_age > RSBAC_LIST_MAX_AGE_LIMIT)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(info_p->desc_size + info_p->data_size > + RSBAC_LIST_MAX_ITEM_SIZE)) + return -RSBAC_EINVALIDVALUE; + if (hash_bits > rsbac_list_max_hash_bits) + hash_bits = rsbac_list_max_hash_bits; + if (!hash_function) { + hash_bits = 0; + flags &= ~RSBAC_LIST_AUTO_HASH_RESIZE; + } + if (name) { + struct rsbac_list_lol_reg_item_t *lol_reg_item_p; + + srcu_idx = srcu_read_lock(®_list_srcu); + reg_item_p = lookup_reg_name(name, device); + srcu_read_unlock(®_list_srcu, srcu_idx); + if (reg_item_p) { + rsbac_pr_debug(lists, "list name %s already exists on device %02u:%02u!\n", + name, RSBAC_MAJOR(device), + RSBAC_MINOR(device)); + return -RSBAC_EEXISTS; + } + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + lol_reg_item_p = lookup_lol_reg_name(name, device); + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + if (lol_reg_item_p) { + rsbac_pr_debug(lists, "list name %s already exists on device %02u:%02u!\n", + name, RSBAC_MAJOR(device), + RSBAC_MINOR(device)); + return -RSBAC_EEXISTS; + } + } else if (flags & RSBAC_LIST_PERSIST) { + rsbac_printk(KERN_WARNING "rsbac_list_register: trial to register persistent list without name.\n"); + return -RSBAC_EINVALIDVALUE; + } + + if (flags & RSBAC_LIST_PERSIST) { + if (RSBAC_IS_AUTO_DEV(device)) + device = rsbac_root_dev; + if (!RSBAC_MAJOR(device)) + flags &= ~RSBAC_LIST_PERSIST; + } + rsbac_pr_debug(lists, "registering list %s for device %02u:%02u.\n", + name, RSBAC_MAJOR(device), RSBAC_MINOR(device)); + new_reg_item_p = + create_reg(info_p, flags, compare, get_conv, def_data, name, + device, hash_bits, hash_function, old_base_name); + if (unlikely(!new_reg_item_p)) { + return -RSBAC_ECOULDNOTADDITEM; + } + /* Restore from disk, but only for real device mounts */ + if ((flags & RSBAC_LIST_PERSIST) + && RSBAC_MAJOR(device) + && !rsbac_list_noread + ) { + rsbac_pr_debug(lists, "restoring list %s from device %02u:%02u.\n", + name, RSBAC_MAJOR(device), RSBAC_MINOR(device)); + err = read_list(new_reg_item_p); + /* not found is no error */ + if (err == -RSBAC_ENOTFOUND) + err = 0; + else if (err) { + char tmp[RSBAC_MAXNAMELEN]; + + if (rsbac_list_recover) { + rsbac_printk(KERN_WARNING "restoring list %s from device %02u:%02u failed with error %s, rsbac_list_recover is set so registering anyway.\n", + name, + RSBAC_MAJOR(device), + RSBAC_MINOR(device), + get_error_name(tmp, err)); + err = 0; + } else { + rsbac_printk(KERN_WARNING "restoring list %s from device %02u:%02u failed with error %s, unregistering list.\n", + name, + RSBAC_MAJOR(device), + RSBAC_MINOR(device), + get_error_name(tmp, err)); + clear_reg(new_reg_item_p); + return err; + } + } else + rsbac_pr_debug(lists, "restoring list %s from device %02u:%02u was successful.\n", + name, RSBAC_MAJOR(device), + RSBAC_MINOR(device)); + } + + spin_lock(®_head.lock); + reg_item_p = add_reg(new_reg_item_p); + spin_unlock(®_head.lock); + if (unlikely(!reg_item_p)) { + rsbac_printk(KERN_WARNING "rsbac_list_register: inserting list %s failed!\n", + name); + /* cleanup */ + clear_reg(new_reg_item_p); + return -RSBAC_ECOULDNOTADDITEM; + } + + /* finish */ +#if defined(CONFIG_RSBAC_PROC) + /* create proc entry, if requested */ + if (flags & RSBAC_LIST_BACKUP) { + reg_item_p->proc_entry_p = + proc_create_data(reg_item_p->name, S_IFREG | S_IRUGO, + proc_rsbac_backup_p, &backup_proc_fops, + (void *) reg_item_p); + } else { + reg_item_p->proc_entry_p = NULL; + } +#endif + *handle_p = reg_item_p; + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_register); +#endif +int rsbac_list_register(rsbac_version_t ds_version, + rsbac_list_handle_t * handle_p, + struct rsbac_list_info_t *info_p, + u_int flags, + rsbac_list_compare_function_t * compare, + rsbac_list_get_conv_t * get_conv, + void *def_data, char *name, kdev_t device) +{ + return rsbac_list_register_hashed(ds_version, handle_p, info_p, flags, + compare, get_conv, def_data, name, device, + 1, NULL, NULL); +} + +/* register a new list of lists */ +/* + * If list with same name exists in memory, error -RSBAC_EEXISTS is returned. + * If list with same name and key exists on device, it is restored depending on the flags. + * If list with same name, but different key exists, access is denied (error -EPERM). + * + * ds_version: for binary modules, must be RSBAC_LIST_VERSION. If version differs, return error. + * handle_p: for all list accesses, an opaque handle is put into *handle_p. + * key: positive, secret __u32 key, which must be the same as in on-disk version, if persistent + * list_version: positive __u32 version number for the list. If old on-disk version is + different, upconversion is tried (depending on flags and get_conv function) + * flags: see flag values + * desc_size: size of the descriptor (error is returned, if value is 0 or list exists and value differs) + * subdesc_size: size of the sublist descriptor (error is returned, if value is 0 or list exists + and value differs) + * data_size: size of data (error is returned, if list exists and value differs). Can be 0 for sets. + * subdata_size: size of sublist data (error is returned, if list exists and value differs). + Can be 0 for sets. + * compare: for lookup and list optimization, can be NULL, then + memcmp(desc1, desc2, desc_size) is used + * subcompare: for item lookup and optimization of sublist, can be NULL, then + memcmp(desc1, desc2, desc_size) is used + * def_data: default data value for flag RSBAC_LIST_DEF_DATA + (if NULL, flag is cleared) + * def_subdata: default subdata value for flag RSBAC_LIST_DEF_SUBDATA + (if NULL, flag is cleared) + * name: the on-disk name, must be distinct and max. 7 or 8.2 chars + (only used for info, if non-persistent) + * device: the device to read list from or to save list to - use 0 for root dev + (ignored, if non-persistent) + * hash_bits: Number of bits of hashes for this list, minimum is 1, + maximum is rsbac_list_max_hash_bits, + which is derived from CONFIG_RSBAC_LIST_MAX_HASH_BITS and must not be more than 31 + Number of hashes is 2^hash_bits. + If > maximum, it will be reduced to maximum automatically. + * hash_function: Hash function(desc,hash_bits), must always return a value + from 0 to 2^hash_bits - 1. + * old_base_name: If not NULL and persistent list with name cannot be read, + try to read all old_base_name with n from 0 to 31. + */ + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_lol_register_hashed); +#endif +int rsbac_list_lol_register_hashed(rsbac_version_t ds_version, + rsbac_list_handle_t * handle_p, + struct rsbac_list_lol_info_t *info_p, + u_int flags, + rsbac_list_compare_function_t * compare, + rsbac_list_compare_function_t * subcompare, + rsbac_list_get_conv_t * get_conv, + rsbac_list_get_conv_t * get_subconv, + void *def_data, + void *def_subdata, char *name, kdev_t device, + __u8 hash_bits, + rsbac_list_hash_function_t hash_function, + char * old_base_name) +{ + struct rsbac_list_lol_reg_item_t *reg_item_p; + struct rsbac_list_lol_reg_item_t *new_reg_item_p; + int err = 0; + int srcu_idx; + + if (unlikely(ds_version != RSBAC_LIST_VERSION)) + return -RSBAC_EINVALIDVERSION; + if (unlikely(!handle_p)) + return -RSBAC_EINVALIDPOINTER; + *handle_p = NULL; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + if (unlikely(!info_p->key || !info_p->version || !info_p->desc_size)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(info_p->max_age > RSBAC_LIST_MAX_AGE_LIMIT)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(info_p->desc_size + info_p->data_size > + RSBAC_LIST_MAX_ITEM_SIZE)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(info_p->subdesc_size + info_p->subdata_size > + RSBAC_LIST_MAX_ITEM_SIZE)) + return -RSBAC_EINVALIDVALUE; + if (hash_bits > rsbac_list_max_hash_bits) + hash_bits = rsbac_list_max_hash_bits; + if (!hash_function) { + hash_bits = 0; + flags &= ~RSBAC_LIST_AUTO_HASH_RESIZE; + } + if (name) { + struct rsbac_list_reg_item_t *std_reg_item_p; + + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + reg_item_p = lookup_lol_reg_name(name, device); + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + if (reg_item_p) { + rsbac_pr_debug(lists, "list name %s already exists on device %02u:%02u!\n", + name, RSBAC_MAJOR(device), + RSBAC_MINOR(device)); + return -RSBAC_EEXISTS; + } + srcu_idx = srcu_read_lock(®_list_srcu); + std_reg_item_p = lookup_reg_name(name, device); + srcu_read_unlock(®_list_srcu, srcu_idx); + if (std_reg_item_p) { + rsbac_pr_debug(lists, "list name %s already exists on device %02u:%02u!\n", + name, RSBAC_MAJOR(device), + RSBAC_MINOR(device)); + return -RSBAC_EEXISTS; + } + } else if (flags & RSBAC_LIST_PERSIST) { + rsbac_printk(KERN_WARNING "rsbac_list_lol_register: trial to register persistent list of lists without name.\n"); + return -RSBAC_EINVALIDVALUE; + } + + if (flags & RSBAC_LIST_PERSIST) { + if (RSBAC_IS_AUTO_DEV(device)) + device = rsbac_root_dev; + if (!RSBAC_MAJOR(device)) + flags &= ~RSBAC_LIST_PERSIST; + } + rsbac_pr_debug(lists, "registering list of lists %s.\n", + name); + new_reg_item_p = create_lol_reg(info_p, flags, compare, subcompare, + get_conv, get_subconv, + def_data, def_subdata, + name, device, + hash_bits, hash_function, + old_base_name); + if (unlikely(!new_reg_item_p)) { + return -RSBAC_ECOULDNOTADDITEM; + } + /* Restore from disk, but only for real device mounts */ + if ((flags & RSBAC_LIST_PERSIST) + && RSBAC_MAJOR(device) + && !rsbac_list_noread + ) { + rsbac_pr_debug(lists, "restoring list %s from device %02u:%02u.\n", + name, RSBAC_MAJOR(device), + RSBAC_MINOR(device)); + err = read_lol_list(new_reg_item_p); + /* not found is no error */ + if (err == -RSBAC_ENOTFOUND) + err = 0; + else if (err) { +#ifdef CONFIG_RSBAC_DEBUG + char tmp[RSBAC_MAXNAMELEN]; +#endif + + rsbac_pr_debug(lists, "restoring list %s from device %02u:%02u failed with error %s, unregistering list.\n", + name, RSBAC_MAJOR(device), + RSBAC_MINOR(device), + get_error_name(tmp, err)); + clear_lol_reg(new_reg_item_p); + return err; + } else + rsbac_pr_debug(lists, "restoring list %s from device %02u:%02u was successful.\n", + name, RSBAC_MAJOR(device), + RSBAC_MINOR(device)); + } + + spin_lock(&lol_reg_head.lock); + reg_item_p = add_lol_reg(new_reg_item_p); + spin_unlock(&lol_reg_head.lock); + if (unlikely(!reg_item_p)) { + rsbac_printk(KERN_WARNING "rsbac_list_lol_register: inserting list %s failed!\n", + name); + /* cleanup */ + clear_lol_reg(new_reg_item_p); + return -RSBAC_ECOULDNOTADDITEM; + } + + /* finish */ +#if defined(CONFIG_RSBAC_PROC) + /* create proc entry, if requested */ + if (flags & RSBAC_LIST_BACKUP) { + reg_item_p->proc_entry_p = + proc_create_data(reg_item_p->name, S_IFREG | S_IRUGO, + proc_rsbac_backup_p, &lol_backup_proc_fops, + (void *) reg_item_p); + } else { + reg_item_p->proc_entry_p = NULL; + } +#endif + *handle_p = reg_item_p; + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_lol_register); +#endif +int rsbac_list_lol_register(rsbac_version_t ds_version, + rsbac_list_handle_t * handle_p, + struct rsbac_list_lol_info_t *info_p, + u_int flags, + rsbac_list_compare_function_t * compare, + rsbac_list_compare_function_t * subcompare, + rsbac_list_get_conv_t * get_conv, + rsbac_list_get_conv_t * get_subconv, + void *def_data, + void *def_subdata, char *name, kdev_t device) { + return rsbac_list_lol_register_hashed (ds_version, handle_p, info_p, + flags, compare, subcompare, get_conv, + get_subconv, def_data, def_subdata, + name, device, + 1, NULL, NULL); +} + +/* destroy list */ +/* list is destroyed, disk file is deleted */ +/* list must have been opened with register */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_destroy); +#endif +int rsbac_list_destroy(rsbac_list_handle_t * handle_p, + rsbac_list_key_t key) +{ + struct rsbac_list_reg_item_t *reg_item_p; + int err = 0; + int srcu_idx; + + if (unlikely(!handle_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!*handle_p)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + srcu_idx = srcu_read_lock(®_list_srcu); + reg_item_p = + lookup_reg((struct rsbac_list_reg_item_t *) *handle_p); + if (!reg_item_p) { + srcu_read_unlock(®_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_destroy: destroying list failed due to invalid handle!\n"); + return -RSBAC_EINVALIDLIST; + } + if (reg_item_p->info.key != key) { + srcu_read_unlock(®_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_destroy: destroying list %s denied due to invalid key!\n", + reg_item_p->name); + return -EPERM; + } + srcu_read_unlock(®_list_srcu, srcu_idx); + rsbac_pr_debug(lists, "destroying list %s.\n", + reg_item_p->name); +#if defined(CONFIG_RSBAC_PROC) + /* delete proc entry, if it exists */ + if ((reg_item_p->flags & RSBAC_LIST_BACKUP) + && reg_item_p->proc_entry_p) { + remove_proc_entry(reg_item_p->name, proc_rsbac_backup_p); + reg_item_p->proc_entry_p = NULL; + } +#endif + +#if 0 + if (reg_item_p->flags & RSBAC_LIST_PERSIST) + err = unlink_list(reg_item_p); +#endif + + spin_lock(®_head.lock); + remove_reg(reg_item_p); + *handle_p = NULL; + spin_unlock(®_head.lock); + synchronize_srcu(®_list_srcu); + /* now we can remove the item from memory */ + clear_reg(reg_item_p); + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_lol_destroy); +#endif +int rsbac_list_lol_destroy(rsbac_list_handle_t * handle_p, + rsbac_list_key_t key) +{ + struct rsbac_list_lol_reg_item_t *reg_item_p; + int err = 0; + int srcu_idx; + + if (unlikely(!handle_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!*handle_p)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + reg_item_p = + lookup_lol_reg((struct rsbac_list_lol_reg_item_t *) *handle_p); + if (!reg_item_p) { + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_lol_destroy: destroying list failed due to invalid handle!\n"); + return -RSBAC_EINVALIDLIST; + } + if (reg_item_p->info.key != key) { + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_lol_destroy: destroying list %s denied due to invalid key %u!\n", + reg_item_p->name, key); + return -EPERM; + } + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + rsbac_pr_debug(lists, "destroying list %s.\n", + reg_item_p->name); +#if defined(CONFIG_RSBAC_PROC) + /* delete proc entry, if it exists */ + if ((reg_item_p->flags & RSBAC_LIST_BACKUP) + && reg_item_p->proc_entry_p) { + remove_proc_entry(reg_item_p->name, proc_rsbac_backup_p); + reg_item_p->proc_entry_p = NULL; + } +#endif +#if 0 + if (reg_item_p->flags & RSBAC_LIST_PERSIST) + err = unlink_lol_list(reg_item_p); +#endif + + spin_lock(&lol_reg_head.lock); + remove_lol_reg(reg_item_p); + spin_unlock(&lol_reg_head.lock); + synchronize_srcu(&lol_reg_list_srcu); + /* now we can remove the item from memory */ + clear_lol_reg(reg_item_p); + return err; +} + +/* detach from list */ +/* list is saved and removed from memory. Call register for new access. */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_detach); +#endif +int rsbac_list_detach(rsbac_list_handle_t * handle_p, rsbac_list_key_t key) +{ + struct rsbac_list_reg_item_t *reg_item_p; + int err = 0; + int srcu_idx; + + if (unlikely(!handle_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!*handle_p)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + srcu_idx = srcu_read_lock(®_list_srcu); + reg_item_p = + lookup_reg((struct rsbac_list_reg_item_t *) *handle_p); + if (!reg_item_p) { + srcu_read_unlock(®_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_detach: detaching list failed due to invalid handle!\n"); + return -RSBAC_EINVALIDLIST; + } + if (reg_item_p->info.key != key) { + srcu_read_unlock(®_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_detach: detaching list %s denied due to invalid key %u!\n", + reg_item_p->name, key); + return -EPERM; + } +#if defined(CONFIG_RSBAC_PROC) + /* delete proc entry, if it exists */ + if ((reg_item_p->flags & RSBAC_LIST_BACKUP) + && reg_item_p->proc_entry_p) { + remove_proc_entry(reg_item_p->name, proc_rsbac_backup_p); + reg_item_p->proc_entry_p = NULL; + } +#endif +#ifndef CONFIG_RSBAC_NO_WRITE + /* final write, if dirty etc. */ + if ((reg_item_p->flags & RSBAC_LIST_PERSIST) + && reg_item_p->dirty && !reg_item_p->no_write + && !rsbac_debug_no_write) { + struct vfsmount *mnt_p; + struct rsbac_list_write_head_t write_head; + struct rsbac_list_write_item_t *write_item_p; + + mnt_p = rsbac_get_vfsmount(reg_item_p->device); + if (mnt_p && rsbac_writable(mnt_p->mnt_sb)) { + reg_item_p->dirty = FALSE; + err = fill_buffer(reg_item_p, &write_item_p); + if (!err) { + write_head.head = write_item_p; + write_head.tail = write_item_p; + write_head.count = 1; + rsbac_list_write_buffers(write_head); + } else { + if (err != -RSBAC_ENOTWRITABLE) { + rsbac_printk(KERN_WARNING "rsbac_list_detach(): fill_buffer() for list %s returned error %i\n", + reg_item_p->name, err); + } + } + } + } +#endif + /* disable handle */ + *handle_p = NULL; + srcu_read_unlock(®_list_srcu, srcu_idx); + /* too bad that the list might have been changed again - we do not care anymore */ + spin_lock(®_head.lock); + remove_reg(reg_item_p); + spin_unlock(®_head.lock); + synchronize_srcu(®_list_srcu); + /* now we can remove the item from memory */ + clear_reg(reg_item_p); + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_lol_detach); +#endif +int rsbac_list_lol_detach(rsbac_list_handle_t * handle_p, + rsbac_list_key_t key) +{ + struct rsbac_list_lol_reg_item_t *reg_item_p; + int err = 0; + int srcu_idx; + + if (unlikely(!handle_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!*handle_p)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + reg_item_p = + lookup_lol_reg((struct rsbac_list_lol_reg_item_t *) *handle_p); + if (!reg_item_p) { + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_lol_detach: detaching list failed due to invalid handle!\n"); + return -RSBAC_EINVALIDLIST; + } + if (reg_item_p->info.key != key) { + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_lol_detach: detaching list %s denied due to invalid key %u!\n", + reg_item_p->name, key); + return -EPERM; + } +#if defined(CONFIG_RSBAC_PROC) + /* delete proc entry, if it exists */ + if ((reg_item_p->flags & RSBAC_LIST_BACKUP) + && reg_item_p->proc_entry_p) { + remove_proc_entry(reg_item_p->name, proc_rsbac_backup_p); + reg_item_p->proc_entry_p = NULL; + } +#endif +#ifndef CONFIG_RSBAC_NO_WRITE + /* final write, if dirty etc. */ + if ((reg_item_p->flags & RSBAC_LIST_PERSIST) + && reg_item_p->dirty && !reg_item_p->no_write + && !rsbac_debug_no_write) { + struct rsbac_list_lol_write_head_t write_head; + struct rsbac_list_lol_write_item_t *write_item_p; + struct vfsmount *mnt_p; + + mnt_p = rsbac_get_vfsmount(reg_item_p->device); + if (mnt_p && rsbac_writable(mnt_p->mnt_sb)) { + reg_item_p->dirty = FALSE; + err = fill_lol_buffer(reg_item_p, &write_item_p); + if (!err) { + write_head.head = write_item_p; + write_head.tail = write_item_p; + write_head.count = 1; + rsbac_list_write_lol_buffers(write_head); + } else { + if (err != -RSBAC_ENOTWRITABLE) { + rsbac_printk(KERN_WARNING "rsbac_list_lol_detach(): fill_lol_buffer() for list %s returned error %i\n", + reg_item_p->name, err); + } + } + } + } +#endif + /* disable handle */ + *handle_p = NULL; + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + /* too bad that the list might have been changed again - we do not care anymore */ + spin_lock(&lol_reg_head.lock); + remove_lol_reg(reg_item_p); + spin_unlock(&lol_reg_head.lock); + synchronize_srcu(&lol_reg_list_srcu); + /* now we can remove the item from memory */ + clear_lol_reg(reg_item_p); + return err; +} + +/* set list's no_write flag */ +/* TRUE: do not write to disk, FALSE: writing allowed */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_no_write); +#endif +int rsbac_list_no_write(rsbac_list_handle_t handle, rsbac_list_key_t key, + rsbac_boolean_t no_write) +{ + struct rsbac_list_reg_item_t *reg_item_p; + int srcu_idx; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely((no_write != FALSE) && (no_write != TRUE))) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + srcu_idx = srcu_read_lock(®_list_srcu); + reg_item_p = lookup_reg((struct rsbac_list_reg_item_t *) handle); + if (!reg_item_p) { + srcu_read_unlock(®_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_no_write: setting no_write for list denied due to invalid handle!\n"); + return -RSBAC_EINVALIDLIST; + } + if (reg_item_p->info.key != key) { + srcu_read_unlock(®_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_no_write: setting no_write for list %s denied due to invalid key %u!\n", + reg_item_p->name, key); + return -EPERM; + } + reg_item_p->no_write = no_write; + srcu_read_unlock(®_list_srcu, srcu_idx); + return 0; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_lol_no_write); +#endif +int rsbac_list_lol_no_write(rsbac_list_handle_t handle, + rsbac_list_key_t key, rsbac_boolean_t no_write) +{ + struct rsbac_list_lol_reg_item_t *reg_item_p; + int srcu_idx; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely((no_write != FALSE) && (no_write != TRUE))) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + reg_item_p = + lookup_lol_reg((struct rsbac_list_lol_reg_item_t *) handle); + if (!reg_item_p) { + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_lol_no_write: setting no_write for list denied due to invalid handle!\n"); + return -RSBAC_EINVALIDLIST; + } + if (reg_item_p->info.key != key) { + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_lol_no_write: setting no_write for list %s denied due to invalid key %u!\n", + reg_item_p->name, key); + return -EPERM; + } + reg_item_p->no_write = no_write; + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + return 0; +} + +/* set list's max_items_per_hash */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_max_items); +#endif +int rsbac_list_max_items(rsbac_list_handle_t handle, rsbac_list_key_t key, + u_int max_items) +{ + struct rsbac_list_reg_item_t *reg_item_p; + int srcu_idx; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + srcu_idx = srcu_read_lock(®_list_srcu); + reg_item_p = lookup_reg((struct rsbac_list_reg_item_t *) handle); + if (!reg_item_p) { + srcu_read_unlock(®_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_max_items: setting max_items_per_hash for list denied due to invalid handle!\n"); + return -RSBAC_EINVALIDLIST; + } + if (reg_item_p->info.key != key) { + srcu_read_unlock(®_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_max_items: setting max_items_per_hash for list %s denied due to invalid key %u!\n", + reg_item_p->name, key); + return -EPERM; + } + if (!max_items) + max_items = RSBAC_LIST_MAX_NR_ITEMS; + reg_item_p->max_items_per_hash = rsbac_min(max_items, RSBAC_LIST_MAX_NR_ITEMS_LIMIT); + srcu_read_unlock(®_list_srcu, srcu_idx); + return 0; +} + +/* set list's max_items_per_hash and max_subitems*/ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_lol_max_items); +#endif +int rsbac_list_lol_max_items(rsbac_list_handle_t handle, rsbac_list_key_t key, + u_int max_items, u_int max_subitems) +{ + struct rsbac_list_lol_reg_item_t *reg_item_p; + int srcu_idx; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + reg_item_p = lookup_lol_reg((struct rsbac_list_lol_reg_item_t *) handle); + if (!reg_item_p) { + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_lol_max_items: setting max_items_per_hash for list denied due to invalid handle!\n"); + return -RSBAC_EINVALIDLIST; + } + if (reg_item_p->info.key != key) { + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_list_lol_max_items: setting max_items_per_hash for list %s denied due to invalid key %u!\n", + reg_item_p->name, key); + return -EPERM; + } + if (!max_items) + max_items = RSBAC_LIST_MAX_NR_ITEMS; + if (!max_subitems) + max_subitems = RSBAC_LIST_MAX_NR_SUBITEMS; + reg_item_p->max_items_per_hash = rsbac_min(max_items, RSBAC_LIST_MAX_NR_ITEMS_LIMIT); + reg_item_p->max_subitems = rsbac_min(max_subitems, RSBAC_LIST_MAX_NR_ITEMS_LIMIT); + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + return 0; +} + + +/********************/ +/* Transactions */ +/********************/ + +#ifdef CONFIG_RSBAC_LIST_TRANS +static int do_commit(rsbac_list_ta_number_t ta_number) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_lol_reg_item_t *lol_list; + int i; + struct rsbac_list_rcu_free_head_t * rcu_head_p; + struct rsbac_list_rcu_free_head_lol_t * rcu_head_lol_p; + int srcu_idx; + int srcu_idx2; + u_int nr_hashes; + + srcu_idx = srcu_read_lock(®_list_srcu); + srcu_idx2 = srcu_read_lock(&lol_reg_list_srcu); + list = srcu_dereference(reg_head.head, ®_list_srcu); + while (list) { + spin_lock(&list->lock); + nr_hashes = 1 << list->hash_bits; + for (i=0; ihashed[i].ta_copied == ta_number) { + remove_all_items(list, i); + rcu_assign_pointer(list->hashed[i].head, list->hashed[i].ta_head); + rcu_assign_pointer(list->hashed[i].tail, list->hashed[i].ta_tail); + rcu_assign_pointer(list->hashed[i].curr, list->hashed[i].ta_curr); + list->hashed[i].count = list->hashed[i].ta_count; + list->hashed[i].ta_copied = 0; + rcu_assign_pointer(list->hashed[i].ta_head, NULL); + rcu_assign_pointer(list->hashed[i].ta_tail, NULL); + rcu_assign_pointer(list->hashed[i].ta_curr, NULL); + list->hashed[i].ta_count = 0; + list->dirty = TRUE; + } + } + rcu_head_p = get_rcu_free(list); + spin_unlock(&list->lock); + do_call_rcu(rcu_head_p); + list = srcu_dereference(list->next, ®_list_srcu); + } + lol_list = srcu_dereference(lol_reg_head.head, &lol_reg_list_srcu); + while (lol_list) { + spin_lock(&lol_list->lock); + nr_hashes = 1 << lol_list->hash_bits; + for (i=0; ihashed[i].ta_copied == ta_number) { + remove_all_lol_items(lol_list, i); + rcu_assign_pointer(lol_list->hashed[i].head, lol_list->hashed[i].ta_head); + rcu_assign_pointer(lol_list->hashed[i].tail, lol_list->hashed[i].ta_tail); + rcu_assign_pointer(lol_list->hashed[i].curr, lol_list->hashed[i].ta_curr); + lol_list->hashed[i].count = lol_list->hashed[i].ta_count; + lol_list->hashed[i].ta_copied = 0; + rcu_assign_pointer(lol_list->hashed[i].ta_head, NULL); + rcu_assign_pointer(lol_list->hashed[i].ta_tail, NULL); + rcu_assign_pointer(lol_list->hashed[i].ta_curr, NULL); + lol_list->hashed[i].ta_count = 0; + lol_list->dirty = TRUE; + } + } + rcu_head_lol_p = get_rcu_free_lol(lol_list); + spin_unlock(&lol_list->lock); + do_call_rcu_lol(rcu_head_lol_p); + lol_list = srcu_dereference(lol_list->next, &lol_reg_list_srcu); + } + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx2); + srcu_read_unlock(®_list_srcu, srcu_idx); + return 0; +} + +int rsbac_list_ta_commit(rsbac_list_ta_number_t ta_number, char *password) +{ + int err; + struct rsbac_list_ta_data_t ta_data; + + rsbac_printk(KERN_INFO "rsbac_list_ta_commit(): starting commit of transaction %u\n", + ta_number); + err = rsbac_list_get_data(ta_handle, &ta_number, &ta_data); + if (err) + return err; + if ((RSBAC_UID_NUM(ta_data.commit_uid) != RSBAC_ALL_USERS) + && (ta_data.commit_uid != (rsbac_get_vset(),__kuid_val(current_uid()))) + ) + return -EPERM; + + if (ta_data.password[0]) { + if (!password) + return -EPERM; + if (strncmp + (ta_data.password, password, + RSBAC_LIST_TA_MAX_PASSLEN)) + return -EPERM; + } + rsbac_printk(KERN_INFO "rsbac_list_ta_commit(): transaction %u data verified\n", + ta_number); + spin_lock(&ta_lock); + while (ta_committing) { + spin_unlock(&ta_lock); + msleep(100); + spin_lock(&ta_lock); + } + rsbac_list_remove(ta_handle, &ta_number); + ta_committing = TRUE; + spin_unlock(&ta_lock); + + rsbac_printk(KERN_INFO "rsbac_list_ta_commit(): committing transaction %u now\n", + ta_number); + + err = do_commit(ta_number); + ta_committing = FALSE; +#ifdef CONFIG_RSBAC_FD_CACHE + if (!err) + rsbac_fd_cache_invalidate_all(); +#endif + wake_up(&ta_wait); + rsbac_printk(KERN_INFO "rsbac_list_ta_commit(): committed transaction %u\n", + ta_number); + return err; +} + +static int do_forget(rsbac_list_ta_number_t ta_number) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_lol_reg_item_t *lol_list; + int i; + struct rsbac_list_rcu_free_head_t * rcu_head_p; + struct rsbac_list_rcu_free_head_lol_t * rcu_head_lol_p; + int srcu_idx; + int srcu_idx2; + u_int nr_hashes; + + spin_lock(&ta_lock); + while (ta_committing) { + spin_unlock(&ta_lock); + msleep(100); + spin_lock(&ta_lock); + } + rsbac_list_remove(ta_handle, &ta_number); + ta_committing = TRUE; + spin_unlock(&ta_lock); + + rsbac_printk(KERN_INFO "rsbac_list_ta_forget(): removing transaction %u\n", + ta_number); + + srcu_idx = srcu_read_lock(®_list_srcu); + srcu_idx2 = srcu_read_lock(&lol_reg_list_srcu); + list = srcu_dereference(reg_head.head, ®_list_srcu); + while (list) { + spin_lock(&list->lock); + nr_hashes = 1 << list->hash_bits; + for (i=0; ihashed[i].ta_copied == ta_number) { + ta_remove_all_items(list, i); + list->hashed[i].ta_copied = 0; + } + } + rcu_head_p = get_rcu_free(list); + spin_unlock(&list->lock); + do_call_rcu(rcu_head_p); + list = srcu_dereference(list->next, ®_list_srcu); + } + lol_list = srcu_dereference(lol_reg_head.head, &lol_reg_list_srcu); + while (lol_list) { + spin_lock(&lol_list->lock); + nr_hashes = 1 << lol_list->hash_bits; + for (i=0; ihashed[i].ta_copied == ta_number) { + ta_remove_all_lol_items(lol_list, i); + lol_list->hashed[i].ta_copied = 0; + } + } + rcu_head_lol_p = get_rcu_free_lol(lol_list); + spin_unlock(&lol_list->lock); + do_call_rcu_lol(rcu_head_lol_p); + lol_list = srcu_dereference(lol_list->next, &lol_reg_list_srcu); + } + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx2); + srcu_read_unlock(®_list_srcu, srcu_idx); + + ta_committing = FALSE; + wake_up(&ta_wait); + + return 0; +} + +int rsbac_list_ta_forget(rsbac_list_ta_number_t ta_number, char *password) +{ + int err; + struct rsbac_list_ta_data_t ta_data; + + err = rsbac_list_get_data(ta_handle, &ta_number, &ta_data); + if (err) + return err; + if ((RSBAC_UID_NUM(ta_data.commit_uid) != RSBAC_ALL_USERS) + && (ta_data.commit_uid != (rsbac_get_vset(),__kuid_val(current_uid()))) + ) + return -EPERM; + if (ta_data.password[0]) { + if (!password) + return -EPERM; + if (strncmp + (ta_data.password, password, + RSBAC_LIST_TA_MAX_PASSLEN)) + return -EPERM; + } + return do_forget(ta_number); +} + +int rsbac_list_ta_begin(rsbac_time_t ttl, + rsbac_list_ta_number_t * ta_number_p, + rsbac_uid_t commit_uid, + char * name, char *password) +{ + int err; + rsbac_list_ta_number_t ta; + struct rsbac_list_ta_data_t ta_data; + + if (unlikely(!ta_number_p)) + return -RSBAC_EINVALIDPOINTER; + + while(ta_committing) + msleep(100); + if (*ta_number_p) { + if (rsbac_list_exist(ta_handle, ta_number_p)) + return -RSBAC_EEXISTS; + ta = *ta_number_p; + } else { +#ifdef CONFIG_RSBAC_LIST_TRANS_RANDOM_TA + get_random_bytes(&ta, sizeof(ta)); +#else + ta = ta_next++; +#endif + while (!ta || rsbac_list_exist(ta_handle, &ta) +#ifdef CONFIG_RSBAC_RC_LEARN_TA + || (ta == CONFIG_RSBAC_RC_LEARN_TA) +#endif +#ifdef CONFIG_RSBAC_AUTH_LEARN_TA + || (ta == CONFIG_RSBAC_AUTH_LEARN_TA) +#endif +#ifdef CONFIG_RSBAC_ACL_LEARN_TA + || (ta == CONFIG_RSBAC_ACL_LEARN_TA) +#endif +#ifdef CONFIG_RSBAC_CAP_LEARN_TA + || (ta == CONFIG_RSBAC_CAP_LEARN_TA) +#endif + ) { +#ifdef CONFIG_RSBAC_LIST_TRANS_RANDOM_TA + get_random_bytes(&ta, sizeof(ta)); +#else + ta = ta_next++; +#endif + } + } + if (!ttl || (ttl > CONFIG_RSBAC_LIST_TRANS_MAX_TTL)) + ttl = CONFIG_RSBAC_LIST_TRANS_MAX_TTL; + + rsbac_printk(KERN_INFO "rsbac_list_ta_begin(): starting transaction %u with ttl of %us\n", + ta, ttl); + + ta_data.start = RSBAC_CURRENT_TIME; + ta_data.timeout = ta_data.start + ttl; + ta_data.commit_uid = commit_uid; + if (name) { + strncpy(ta_data.name, name, + RSBAC_LIST_TA_MAX_NAMELEN - 1); + ta_data.name[RSBAC_LIST_TA_MAX_NAMELEN - 1] = 0; + } else + ta_data.name[0] = 0; + if (password) { + strncpy(ta_data.password, password, + RSBAC_LIST_TA_MAX_PASSLEN - 1); + ta_data.password[RSBAC_LIST_TA_MAX_PASSLEN - 1] = 0; + } else + ta_data.password[0] = 0; + err = rsbac_list_add(ta_handle, &ta, &ta_data); + if (!err) + *ta_number_p = ta; + return err; +} + +int rsbac_list_ta_refresh(rsbac_time_t ttl, + rsbac_list_ta_number_t ta_number, char *password) +{ + struct rsbac_list_ta_data_t ta_data; + int err; + + if (!rsbac_list_exist(ta_handle, &ta_number)) { + return -RSBAC_ENOTFOUND; + } + if (!ttl || (ttl > CONFIG_RSBAC_LIST_TRANS_MAX_TTL)) + ttl = CONFIG_RSBAC_LIST_TRANS_MAX_TTL; + + rsbac_printk(KERN_INFO "rsbac_list_ta_refresh(): refreshing transaction %u for %us\n", + ta_number, ttl); + + err = rsbac_list_get_data(ta_handle, &ta_number, &ta_data); + if (err) + return err; + if ((RSBAC_UID_NUM(ta_data.commit_uid) != RSBAC_ALL_USERS) + && (ta_data.commit_uid != (rsbac_get_vset(),__kuid_val(current_uid()))) + ) + return -EPERM; + if (ta_data.password[0]) { + if (!password) + return -EPERM; + if (strncmp + (ta_data.password, password, + RSBAC_LIST_TA_MAX_PASSLEN)) + return -EPERM; + } + ta_data.timeout = RSBAC_CURRENT_TIME + ttl; + return rsbac_list_add(ta_handle, &ta_number, &ta_data); +} + +int rsbac_list_ta_exist(rsbac_list_ta_number_t ta_number) +{ + if (!ta_number) + return TRUE; + else + return rsbac_list_exist(ta_handle, &ta_number); +} +#endif + + +/********************/ +/* List Access */ +/********************/ + +/* add item */ +/* if item for desc exists, the data is updated */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_add_ttl); +#endif +int rsbac_ta_list_add_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t ttl, void *desc, void *data) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *item_p; + u_int hash = 0; + struct rsbac_list_rcu_free_head_t * rcu_head_p; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(!list || (list->self != list))) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + if (unlikely(list->info.data_size && !data)) { + return -RSBAC_EINVALIDVALUE; + } + +/* + rsbac_pr_debug(lists, "adding to list %s.\n", list->name); +*/ + if (ttl && (ttl != RSBAC_LIST_TTL_KEEP)) { + if (ttl > RSBAC_LIST_MAX_AGE_LIMIT) + ttl = RSBAC_LIST_MAX_AGE_LIMIT; + ttl += RSBAC_CURRENT_TIME; + } + spin_lock(&list->lock); + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (!ta_number) +#endif + { + item_p = lookup_item_locked(list, desc); + if (item_p) { /* exists -> update data, if any */ + if (ttl != RSBAC_LIST_TTL_KEEP) + item_p->max_age = ttl; + if (data && list->info.data_size) { + if (list->def_data + && !item_p->max_age + && !memcmp(list->def_data, data, + list->info.data_size) + ) + do_remove_item(list, item_p, hash); + else + memcpy(((char *) item_p) + + sizeof(*item_p) + + list->info.desc_size, data, + list->info.data_size); + } + } else { + if (ttl == RSBAC_LIST_TTL_KEEP) + ttl = 0; + if (!list->def_data + || memcmp(list->def_data, data, + list->info.data_size) + ) + add_item(list, ttl, desc, data); + } + touch(list); + list->dirty = TRUE; + } +#ifdef CONFIG_RSBAC_LIST_TRANS + if (list->hashed[hash].ta_copied || ta_number) { + if (!list->hashed[hash].ta_copied) + ta_copy(ta_number, list, hash); + else if (ta_number) { + if (list->hashed[hash].ta_copied != ta_number) { + spin_unlock(&list->lock); + return -RSBAC_EBUSY; + } + } else + ta_number = list->hashed[hash].ta_copied; + item_p = ta_lookup_item_locked(ta_number, list, desc); + if (item_p) { /* exists -> update data, if any */ + if (ttl != RSBAC_LIST_TTL_KEEP) + item_p->max_age = ttl; + if (data && list->info.data_size) { + if (list->def_data + && !item_p->max_age + && !memcmp(list->def_data, data, + list->info.data_size) + ) + ta_do_remove_item(list, item_p, hash); + else + memcpy(((char *) item_p) + + sizeof(*item_p) + + list->info.desc_size, data, + list->info.data_size); + } + } else { + if (ttl == RSBAC_LIST_TTL_KEEP) + ttl = 0; + if (!list->def_data + || memcmp(list->def_data, data, + list->info.data_size) + ) + ta_add_item(ta_number, list, ttl, desc, + data); + } + } +#endif +#ifdef CONFIG_RSBAC_LIST_STATS + list->write_count++; +#endif + rcu_head_p = get_rcu_free(list); + spin_unlock(&list->lock); + do_sync_rcu(rcu_head_p); + return 0; +} + +/* add list of lists sublist item */ +/* if item for desc exists, the data is updated */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_subadd_ttl); +#endif +int rsbac_ta_list_lol_subadd_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t ttl, + void *desc, void *subdesc, void *subdata) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + struct rsbac_list_item_t *item_p; + int err = 0; + u_int hash = 0; + struct rsbac_list_rcu_free_head_lol_t * rcu_head_lol_p; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc || !subdesc)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + if (unlikely(list->info.subdata_size && !subdata)) { + return -RSBAC_EINVALIDVALUE; + } + +/* + rsbac_pr_debug(lists, "adding to list %s.\n", list->name); +*/ + spin_lock(&list->lock); + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (!ta_number) +#endif + { + sublist = lookup_lol_item_locked(list, desc); + if (!sublist && (list->flags & RSBAC_LIST_DEF_DATA)) + sublist = add_lol_item(list, 0, desc, list->def_data); + if (sublist) { + if (sublist->max_age + && (sublist->max_age <= RSBAC_CURRENT_TIME) + ) { + remove_lol_item(list, desc); + err = -RSBAC_EINVALIDTARGET; + } else { + /* exists -> lookup subitem */ + if (ttl && (ttl != RSBAC_LIST_TTL_KEEP)) { + if (ttl > RSBAC_LIST_MAX_AGE_LIMIT) + ttl = RSBAC_LIST_MAX_AGE_LIMIT; + ttl += RSBAC_CURRENT_TIME; + } + item_p = + lookup_lol_subitem_locked(list, sublist, + subdesc); + if (item_p) { /* exists -> update data, if any */ + if (ttl != RSBAC_LIST_TTL_KEEP) + item_p->max_age = ttl; + if (subdata + && list->info.subdata_size) { + if (list->def_subdata + && !item_p->max_age + && !memcmp(list-> + def_subdata, + subdata, + list->info. + subdata_size) + ) { + do_remove_lol_subitem + (sublist, + item_p); + rcu_free_lol_sub(list, item_p); + } else + memcpy(((char *) + item_p) + + sizeof + (*item_p) + + list->info. + subdesc_size, + subdata, + list->info. + subdata_size); + } + } else { + if (ttl == RSBAC_LIST_TTL_KEEP) + ttl = 0; + if (!list->def_subdata + || memcmp(list->def_subdata, + subdata, + list->info. + subdata_size) + ) { + if (!add_lol_subitem(list, + sublist, + ttl, + subdesc, + subdata)) + err = -RSBAC_ECOULDNOTADDITEM; + } + } + lol_touch(list); + list->dirty = TRUE; + } + } else { + err = -RSBAC_EINVALIDTARGET; + goto out_unlock; + } + } +#ifdef CONFIG_RSBAC_LIST_TRANS + if (list->hashed[hash].ta_copied || ta_number) { + if (!list->hashed[hash].ta_copied) { + if ((err = ta_lol_copy(ta_number, list, hash))) + goto out_unlock; + } else if (ta_number) { + if (list->hashed[hash].ta_copied != ta_number) { + err = -RSBAC_EBUSY; + goto out_unlock; + } + } else + ta_number = list->hashed[hash].ta_copied; + sublist = ta_lookup_lol_item_locked(ta_number, list, desc); + if (!sublist && (list->flags & RSBAC_LIST_DEF_DATA) + ) + sublist = + ta_add_lol_item(ta_number, list, 0, desc, + list->def_data); + if (sublist) { + if (sublist->max_age + && (sublist->max_age <= RSBAC_CURRENT_TIME) + ) { + ta_remove_lol_item(ta_number, list, desc); + err = -RSBAC_EINVALIDTARGET; + } else { + /* exists -> lookup subitem */ + if (ttl && (ttl != RSBAC_LIST_TTL_KEEP)) { + if (ttl > RSBAC_LIST_MAX_AGE_LIMIT) + ttl = + RSBAC_LIST_MAX_AGE_LIMIT; + ttl += RSBAC_CURRENT_TIME; + } + item_p = + lookup_lol_subitem_locked(list, sublist, + subdesc); + if (item_p) { /* exists -> update data, if any */ + if (ttl != RSBAC_LIST_TTL_KEEP) + item_p->max_age = ttl; + if (subdata + && list->info.subdata_size) { + if (list->def_subdata + && !item_p->max_age + && !memcmp(list-> + def_subdata, + subdata, + list->info. + subdata_size) + ) { + do_remove_lol_subitem + (sublist, + item_p); + rcu_free_lol_sub(list, item_p); + } else + memcpy(((char *) + item_p) + + sizeof + (*item_p) + + list->info. + subdesc_size, + subdata, + list->info. + subdata_size); + } + } else { + if (ttl == RSBAC_LIST_TTL_KEEP) + ttl = 0; + if (!list->def_subdata + || memcmp(list->def_subdata, + subdata, + list->info. + subdata_size) + ) + add_lol_subitem(list, + sublist, + ttl, + subdesc, + subdata); + } + } + } else { + err = -RSBAC_EINVALIDTARGET; + } + } +#endif + +#ifdef CONFIG_RSBAC_LIST_STATS + list->write_count++; +#endif + +out_unlock: + rcu_head_lol_p = get_rcu_free_lol(list); + spin_unlock(&list->lock); + do_sync_rcu_lol(rcu_head_lol_p); + return err; +} + +/* add list of lists item */ +/* if item for desc exists, the data is updated */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_add_ttl); +#endif +int rsbac_ta_list_lol_add_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t ttl, void *desc, void *data) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *item_p; + u_int hash = 0; + struct rsbac_list_rcu_free_head_lol_t * rcu_head_lol_p; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + if (ttl && (ttl != RSBAC_LIST_TTL_KEEP)) { + if (ttl > RSBAC_LIST_MAX_AGE_LIMIT) + ttl = RSBAC_LIST_MAX_AGE_LIMIT; + ttl += RSBAC_CURRENT_TIME; + } + + if (list->info.data_size && !data) { + return -RSBAC_EINVALIDVALUE; + } + +/* + rsbac_pr_debug(lists, "adding to list %s.\n", list->name); +*/ + spin_lock(&list->lock); + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (!ta_number) +#endif + { + item_p = lookup_lol_item_locked(list, desc); + if (item_p) { /* exists -> update data, if any */ + if (ttl != RSBAC_LIST_TTL_KEEP) + item_p->max_age = ttl; + if (data && list->info.data_size) { + if (list->def_data + && !item_p->max_age + && !memcmp(list->def_data, data, + list->info.data_size) + && !item_p->count) + do_remove_lol_item(list, item_p, hash); + else + memcpy(((char *) item_p) + + sizeof(*item_p) + + list->info.desc_size, data, + list->info.data_size); + } + } else { + if (ttl == RSBAC_LIST_TTL_KEEP) + ttl = 0; + if (!list->def_data + || memcmp(list->def_data, data, + list->info.data_size) + ) + add_lol_item(list, ttl, desc, data); + } + lol_touch(list); + list->dirty = TRUE; + } +#ifdef CONFIG_RSBAC_LIST_TRANS + if (list->hashed[hash].ta_copied || ta_number) { + if (!list->hashed[hash].ta_copied) + ta_lol_copy(ta_number, list, hash); + else if (ta_number) { + if (list->hashed[hash].ta_copied != ta_number) { + rcu_head_lol_p = get_rcu_free_lol(list); + spin_unlock(&list->lock); + do_sync_rcu_lol(rcu_head_lol_p); + return -RSBAC_EBUSY; + } + } else + ta_number = list->hashed[hash].ta_copied; + item_p = ta_lookup_lol_item_locked(ta_number, list, desc); + if (item_p) { /* exists -> update data, if any */ + if (ttl != RSBAC_LIST_TTL_KEEP) + item_p->max_age = ttl; + if (data && list->info.data_size) { + if (list->def_data + && !item_p->max_age + && !memcmp(list->def_data, data, + list->info.data_size) + && !item_p->count) + ta_do_remove_lol_item(list, + item_p, + hash); + else + memcpy(((char *) item_p) + + sizeof(*item_p) + + list->info.desc_size, data, + list->info.data_size); + } + } else { + if (ttl == RSBAC_LIST_TTL_KEEP) + ttl = 0; + if (!list->def_data + || memcmp(list->def_data, data, + list->info.data_size) + ) + ta_add_lol_item(ta_number, list, ttl, desc, + data); + } + } +#endif +#ifdef CONFIG_RSBAC_LIST_STATS + list->write_count++; +#endif + rcu_head_lol_p = get_rcu_free_lol(list); + spin_unlock(&list->lock); + do_sync_rcu_lol(rcu_head_lol_p); + return 0; +} + +/* remove item */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_remove); +#endif +int rsbac_ta_list_remove(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_rcu_free_head_t * rcu_head_p; +#ifdef CONFIG_RSBAC_LIST_TRANS + u_int hash = 0; +#endif + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(!list || (list->self != list))) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + +/* + rsbac_pr_debug(lists, "removing from list %s.\n", list->name); +*/ + spin_lock(&list->lock); +#ifdef CONFIG_RSBAC_LIST_TRANS + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + if (list->hashed[hash].ta_copied) { + if (ta_number) { + if (ta_lookup_item_locked(list->hashed[hash].ta_copied, list, desc)) { + if (list->hashed[hash].ta_copied != ta_number) { + spin_unlock(&list->lock); + return -RSBAC_EBUSY; + } else + ta_remove_item(ta_number, list, + desc); + } + } else + ta_remove_item(list->hashed[hash].ta_copied, list, desc); + } else { + if (ta_number && lookup_item_locked(list, desc)) { + ta_copy(ta_number, list, hash); + ta_remove_item(ta_number, list, desc); + } + } + if (!ta_number) +#endif + { + if (lookup_item_locked(list, desc)) { /* exists -> remove */ + remove_item(list, desc); + touch(list); + list->dirty = TRUE; +#ifdef CONFIG_RSBAC_LIST_STATS + list->write_count++; +#endif + } + } + rcu_head_p = get_rcu_free(list); + spin_unlock(&list->lock); + do_sync_rcu(rcu_head_p); + return 0; +} + +/* remove all items */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_remove_all); +#endif +int rsbac_ta_list_remove_all(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle) +{ + struct rsbac_list_reg_item_t *list; + int i; + u_int nr_hashes; + struct rsbac_list_rcu_free_head_t ** rcu_head_pp = NULL; +#ifdef CONFIG_RSBAC_LIST_TRANS + struct rsbac_list_rcu_free_head_t ** ta_rcu_head_pp = NULL; +#endif + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + +/* + rsbac_pr_debug(lists, "removing all items from list %s.\n", list->name); +*/ + +restart: + nr_hashes = 1 << list->hash_bits; +#ifdef CONFIG_RSBAC_LIST_TRANS + if (!ta_number) +#endif + { + rcu_head_pp = rsbac_kmalloc_clear_unlocked(nr_hashes * sizeof(*rcu_head_pp)); + if (unlikely(!rcu_head_pp)) + return -RSBAC_ENOMEM; + } +#ifdef CONFIG_RSBAC_LIST_TRANS + ta_rcu_head_pp = rsbac_kmalloc_clear_unlocked(nr_hashes * sizeof(*ta_rcu_head_pp)); + if (unlikely(!ta_rcu_head_pp)) { + if (!ta_number) + rsbac_kfree(rcu_head_pp); + return -RSBAC_ENOMEM; + } +#endif + + spin_lock(&list->lock); + if (unlikely(nr_hashes != 1 << list->hash_bits)) { + spin_unlock(&list->lock); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (!ta_number) +#endif + rsbac_kfree(rcu_head_pp); +#ifdef CONFIG_RSBAC_LIST_TRANS + rsbac_kfree(ta_rcu_head_pp); +#endif + goto restart; + } + +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number) + for (i=0; ihashed[i].ta_copied && (list->hashed[i].ta_copied != ta_number)) { + spin_unlock(&list->lock); + rsbac_kfree(ta_rcu_head_pp); + return -RSBAC_EBUSY; + } + + for (i=0; ihashed[i].ta_copied) { + ta_remove_all_items(list, i); + if (ta_number && !list->hashed[i].head) + list->hashed[i].ta_copied = 0; + } else { + if (ta_number && list->hashed[i].head) { + list->hashed[i].ta_head = NULL; + list->hashed[i].ta_tail = NULL; + list->hashed[i].ta_curr = NULL; + list->hashed[i].ta_count = 0; + list->hashed[i].ta_copied = ta_number; + } + } + ta_rcu_head_pp[i] = get_rcu_free(list); + } + + if (!ta_number) +#endif + for (i=0; ihashed[i].head) { + remove_all_items(list, i); + touch(list); + list->dirty = TRUE; + rcu_head_pp[i] = get_rcu_free(list); + } + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->write_count++; +#endif + spin_unlock(&list->lock); + synchronize_rcu(); +#ifdef CONFIG_RSBAC_LIST_TRANS + for (i=0; iself != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + +/* + rsbac_pr_debug(lists, "removing from list of lists %s, device %02u:%02u.\n", + list->name, RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device)); +*/ + spin_lock(&list->lock); + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (list->hashed[hash].ta_copied) { + sublist = ta_lookup_lol_item_locked(list->hashed[hash].ta_copied, list, desc); + if (sublist) { + if (sublist->max_age + && (sublist->max_age <= RSBAC_CURRENT_TIME) + ) { + ta_do_remove_lol_item(list, sublist, hash); + } else { + struct rsbac_list_item_t * subitem_p; + + if (ta_number + && (list->hashed[hash].ta_copied != ta_number)) { + spin_unlock(&list->lock); + return -RSBAC_EBUSY; + } + while (sublist->head && (count > 0)) { + subitem_p = sublist->head; + do_remove_lol_subitem(sublist, + subitem_p); + rcu_free_lol_sub(list, subitem_p); + count--; + } + if (!sublist->count + && ((list->def_data + && !memcmp(((char *) sublist) + + sizeof(*sublist) + + list->info.desc_size, + list->def_data, + list->info.data_size) + ) + || (!list->info.data_size + && (list-> + flags & + RSBAC_LIST_DEF_DATA) + ) + ) + ) { + ta_do_remove_lol_item(list, + sublist, + hash); + } + } + } + } else { + if (ta_number && lookup_lol_item_locked(list, desc)) { + ta_lol_copy(ta_number, list, hash); + ta_remove_lol_item(ta_number, list, desc); + } + } + if (!ta_number) +#endif + { + sublist = lookup_lol_item_locked(list, desc); + if (sublist) { + if (sublist->max_age + && (sublist->max_age <= RSBAC_CURRENT_TIME) + ) { + do_remove_lol_item(list, sublist, hash); + lol_touch(list); + list->dirty = TRUE; +#ifdef CONFIG_RSBAC_LIST_STATS + list->write_count++; +#endif + } else { + struct rsbac_list_item_t * subitem_p; + + while (sublist->head && (count > 0)) { + subitem_p = sublist->head; + /* Changes sublist->head */ + do_remove_lol_subitem(sublist, + subitem_p); + rcu_free_lol_sub(list, subitem_p); + count--; + } + lol_touch(list); + list->dirty = TRUE; +#ifdef CONFIG_RSBAC_LIST_STATS + list->write_count++; +#endif + if (!sublist->count + && ((list->def_data + && !memcmp(((char *) sublist) + + sizeof(*sublist) + + list->info.desc_size, + list->def_data, + list->info.data_size) + ) + || (!list->info.data_size + && (list-> + flags & + RSBAC_LIST_DEF_DATA) + ) + ) + ) { + do_remove_lol_item(list, sublist, hash); + } + } + } + } + rcu_head_lol_p = get_rcu_free_lol(list); + spin_unlock(&list->lock); + do_sync_rcu_lol(rcu_head_lol_p); + return 0; +} + + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_subremove); +#endif +int rsbac_ta_list_lol_subremove(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, void *subdesc) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + u_int hash = 0; + struct rsbac_list_rcu_free_head_lol_t * rcu_head_lol_p; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc || !subdesc)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + +/* + rsbac_pr_debug(lists, "removing from list of lists %s, device %02u:%02u.\n", + list->name, RSBAC_MAJOR(list->device), + RSBAC_MINOR(list->device)); +*/ + spin_lock(&list->lock); + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (list->hashed[hash].ta_copied) { + sublist = ta_lookup_lol_item_locked(list->hashed[hash].ta_copied, list, desc); + if (sublist) { + if (sublist->max_age + && (sublist->max_age <= RSBAC_CURRENT_TIME) + ) { + ta_do_remove_lol_item(list, sublist, hash); + } else { + if (ta_number + && (list->hashed[hash].ta_copied != ta_number)) { + spin_unlock(&list->lock); + return -RSBAC_EBUSY; + } + if (lookup_lol_subitem_locked + (list, sublist, subdesc)) + remove_lol_subitem(list, sublist, + subdesc); + if (!sublist->head + && + ((list->def_data + && !memcmp(((char *) sublist) + + sizeof(*sublist) + + list->info.desc_size, + list->def_data, + list->info.data_size) + ) + || (!list->info.data_size + && (list-> + flags & RSBAC_LIST_DEF_DATA) + ) + ) + ) { + ta_do_remove_lol_item(list, + sublist, + hash); + } + } + } + } else { + if (ta_number && lookup_lol_item_locked(list, desc)) { + ta_lol_copy(ta_number, list, hash); + ta_remove_lol_item(ta_number, list, desc); + } + } + if (!ta_number) +#endif + { + sublist = lookup_lol_item_locked(list, desc); + if (sublist) { + if (sublist->max_age + && (sublist->max_age <= RSBAC_CURRENT_TIME) + ) { + do_remove_lol_item(list, sublist, hash); + lol_touch(list); + list->dirty = TRUE; +#ifdef CONFIG_RSBAC_LIST_STATS + list->write_count++; +#endif + } else { + if (lookup_lol_subitem_locked(list, sublist, subdesc)) { /* exists -> remove and set dirty */ + remove_lol_subitem(list, sublist, + subdesc); + lol_touch(list); + list->dirty = TRUE; +#ifdef CONFIG_RSBAC_LIST_STATS + list->write_count++; +#endif + } + if (!sublist->head + && ((list->def_data + && !memcmp(((char *) sublist) + + sizeof(*sublist) + + list->info.desc_size, + list->def_data, + list->info.data_size) + ) + || (!list->info.data_size + && (list-> + flags & + RSBAC_LIST_DEF_DATA) + ) + ) + ) { + do_remove_lol_item(list, sublist, hash); + lol_touch(list); + list->dirty = TRUE; + } + } + } + } + rcu_head_lol_p = get_rcu_free_lol(list); + spin_unlock(&list->lock); + do_sync_rcu_lol(rcu_head_lol_p); + return 0; +} + +/* remove same subitem from all items */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_subremove_from_all); +#endif +int rsbac_ta_list_lol_subremove_from_all(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *subdesc) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + int i; + struct rsbac_list_rcu_free_head_lol_t * rcu_head_lol_p; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!subdesc)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + +/* + rsbac_pr_debug(lists, "removing from list of lists %s.\n", list->name); +*/ + spin_lock(&list->lock); + nr_hashes = 1 << list->hash_bits; +#ifdef CONFIG_RSBAC_LIST_TRANS + for (i=0; ihashed[i].ta_copied) { + if (ta_number && (list->hashed[i].ta_copied != ta_number)) { + spin_unlock(&list->lock); + return -RSBAC_EBUSY; + } + sublist = list->hashed[i].head; + while (sublist) { + remove_lol_subitem(list, sublist, subdesc); + sublist = sublist->next; + } + } else { + if (ta_number) { + ta_lol_copy(ta_number, list, i); + sublist = list->hashed[i].head; + while (sublist) { + remove_lol_subitem(list, sublist, subdesc); + sublist = sublist->next; + } + } + } + } + if (!ta_number) +#endif + { + for (i=0; ihashed[i].head; + while (sublist) { + if (lookup_lol_subitem_locked(list, sublist, subdesc)) { /* exists -> remove and set dirty */ + remove_lol_subitem(list, sublist, subdesc); + lol_touch(list); + list->dirty = TRUE; + } + sublist = sublist->next; + } + } + } +#ifdef CONFIG_RSBAC_LIST_STATS + if (list->dirty) + list->write_count++; +#endif + rcu_head_lol_p = get_rcu_free_lol(list); + spin_unlock(&list->lock); + do_sync_rcu_lol(rcu_head_lol_p); + return 0; +} + +/* remove all subitems */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_subremove_all); +#endif +int rsbac_ta_list_lol_subremove_all(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + u_int hash = 0; + struct rsbac_list_rcu_free_head_lol_t * rcu_head_lol_p; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + +/* + rsbac_pr_debug(lists, "removing all subitems from list of lists %s.\n", + list->name); +*/ + spin_lock(&list->lock); + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (list->hashed[hash].ta_copied) { + sublist = ta_lookup_lol_item_locked(list->hashed[hash].ta_copied, list, desc); + if (sublist) { + if (sublist->max_age + && (sublist->max_age <= RSBAC_CURRENT_TIME) + ) { + ta_do_remove_lol_item(list, sublist, hash); + } else { + if (ta_number + && (list->hashed[hash].ta_copied != ta_number)) { + spin_unlock(&list->lock); + return -RSBAC_EBUSY; + } + remove_all_lol_subitems(list, sublist); + if ((list->def_data + && !memcmp(((char *) sublist) + + sizeof(*sublist) + + list->info.desc_size, + list->def_data, + list->info.data_size) + ) + || (!list->info.data_size + && (list-> + flags & RSBAC_LIST_DEF_DATA) + ) + + ) { + ta_do_remove_lol_item(list, + sublist, + hash); + } + } + } + } else { + if (ta_number && lookup_lol_item_locked(list, desc)) { + ta_lol_copy(ta_number, list, hash); + sublist = + ta_lookup_lol_item_locked(ta_number, list, desc); + if (sublist) + remove_all_lol_subitems(list, sublist); + } + } + if (!ta_number) +#endif + { + sublist = lookup_lol_item_locked(list, desc); + if (sublist && sublist->head) { + remove_all_lol_subitems(list, sublist); + lol_touch(list); + list->dirty = TRUE; +#ifdef CONFIG_RSBAC_LIST_STATS + list->write_count++; +#endif + } + } + rcu_head_lol_p = get_rcu_free_lol(list); + spin_unlock(&list->lock); + do_sync_rcu_lol(rcu_head_lol_p); + return 0; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_remove); +#endif +int rsbac_ta_list_lol_remove(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc) +{ + struct rsbac_list_lol_reg_item_t *list; + u_int hash = 0; + struct rsbac_list_rcu_free_head_lol_t * rcu_head_lol_p; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + +/* + rsbac_pr_debug(lists, "removing from list of lists %s.\n", + list->name); +*/ + spin_lock(&list->lock); + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (list->hashed[hash].ta_copied) { + if (ta_number) { + if (ta_lookup_lol_item_locked + (list->hashed[hash].ta_copied, list, desc)) { + if (list->hashed[hash].ta_copied != ta_number) { + spin_unlock(&list->lock); + return -RSBAC_EBUSY; + } else + ta_remove_lol_item(ta_number, list, + desc); + } + } else + ta_remove_lol_item(list->hashed[hash].ta_copied, list, desc); + } else { + if (ta_number && lookup_lol_item_locked(list, desc)) { + ta_lol_copy(ta_number, list, hash); + ta_remove_lol_item(ta_number, list, desc); + } + } + if (!ta_number) +#endif + { + if (lookup_lol_item_locked(list, desc)) { /* exists -> remove */ + remove_lol_item(list, desc); + lol_touch(list); + list->dirty = TRUE; +#ifdef CONFIG_RSBAC_LIST_STATS + list->write_count++; +#endif + } + } + rcu_head_lol_p = get_rcu_free_lol(list); + spin_unlock(&list->lock); + do_sync_rcu_lol(rcu_head_lol_p); + return 0; +} + +/* remove all items */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_remove_all); +#endif +int rsbac_ta_list_lol_remove_all(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle) +{ + struct rsbac_list_lol_reg_item_t *list; + int i; + u_int nr_hashes; + struct rsbac_list_rcu_free_head_lol_t ** rcu_head_lol_pp = NULL; +#ifdef CONFIG_RSBAC_LIST_TRANS + struct rsbac_list_rcu_free_head_lol_t ** ta_rcu_head_lol_pp = NULL; +#endif + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + +/* + rsbac_pr_debug(lists, "removing all items from list of lists %s.\n", + list->name); +*/ +restart: + nr_hashes = 1 << list->hash_bits; +#ifdef CONFIG_RSBAC_LIST_TRANS + if (!ta_number) +#endif + { + rcu_head_lol_pp = rsbac_kmalloc_clear_unlocked(nr_hashes * sizeof(*rcu_head_lol_pp)); + if (unlikely(!rcu_head_lol_pp)) + return -RSBAC_ENOMEM; + } +#ifdef CONFIG_RSBAC_LIST_TRANS + ta_rcu_head_lol_pp = rsbac_kmalloc_clear_unlocked(nr_hashes * sizeof(*ta_rcu_head_lol_pp)); + if (unlikely(!ta_rcu_head_lol_pp)) { + if (!ta_number) + rsbac_kfree(rcu_head_lol_pp); + return -RSBAC_ENOMEM; + } +#endif + spin_lock(&list->lock); + if (unlikely(nr_hashes != 1 << list->hash_bits)) { + spin_unlock(&list->lock); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (!ta_number) +#endif + rsbac_kfree(rcu_head_lol_pp); +#ifdef CONFIG_RSBAC_LIST_TRANS + rsbac_kfree(ta_rcu_head_lol_pp); +#endif + goto restart; + } + +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number) + for (i=0; ihashed[i].ta_copied && (list->hashed[i].ta_copied != ta_number)) { + spin_unlock(&list->lock); + rsbac_kfree(ta_rcu_head_lol_pp); + return -RSBAC_EBUSY; + } + + for (i=0; ihashed[i].ta_copied) { + ta_remove_all_lol_items(list, i); + if (ta_number && !list->hashed[i].head) + list->hashed[i].ta_copied = 0; + } else { + if (ta_number && list->hashed[i].head) { + list->hashed[i].ta_head = NULL; + list->hashed[i].ta_tail = NULL; + list->hashed[i].ta_curr = NULL; + list->hashed[i].ta_count = 0; + list->hashed[i].ta_copied = ta_number; + } + } + ta_rcu_head_lol_pp[i] = get_rcu_free_lol(list); + } + + if (!ta_number) +#endif + for (i=0; ihashed[i].head) { + remove_all_lol_items(list, i); + lol_touch(list); + list->dirty = TRUE; + rcu_head_lol_pp[i] = get_rcu_free_lol(list); + } + } +#ifdef CONFIG_RSBAC_LIST_STATS + if (list->dirty) + list->write_count++; +#endif + spin_unlock(&list->lock); + synchronize_rcu(); +#ifdef CONFIG_RSBAC_LIST_TRANS + for (i=0; iself != list)) + return -RSBAC_EINVALIDLIST; + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "getting data from list %s.\n", + list->name); +*/ + if (unlikely(data && !list->info.data_size)) { + rcu_read_unlock(); + return -RSBAC_EINVALIDREQUEST; + } + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + item_p = ta_lookup_item(ta_number, list, hashed, hash, desc); + else +#endif + item_p = lookup_item(list, hashed, hash, desc); + if (item_p + && (!item_p->max_age || (item_p->max_age > RSBAC_CURRENT_TIME) + ) + ) { /* exists -> copy data, if any */ + if (ttl_p) { + if (item_p->max_age) + *ttl_p = + item_p->max_age - RSBAC_CURRENT_TIME; + else + *ttl_p = 0; + } + if (data) { + memcpy(data, + ((char *) item_p) + sizeof(*item_p) + + list->info.desc_size, list->info.data_size); + } + } else { + if (!list->def_data) + err = -RSBAC_ENOTFOUND; + else { + if (ttl_p) + *ttl_p = 0; + if (data) + memcpy(data, + list->def_data, + list->info.data_size); + } + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_max_subdesc); +#endif +int rsbac_ta_list_lol_get_max_subdesc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, void *subdesc) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + struct rsbac_list_item_t *item_p; + int err = 0; + struct rsbac_list_lol_hashed_t * hashed; + u_int hash = 0; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc || !subdesc)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + hashed = rcu_dereference(list->hashed); +/* + rsbac_pr_debug(lists, "getting data from list %s.\n", + list->name); +*/ + +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + sublist = ta_lookup_lol_item(ta_number, list, hashed, hash, desc); + else +#endif + sublist = lookup_lol_item(list, hashed, hash, desc); + if (sublist) { /* exists -> lookup subitem */ + item_p = rcu_dereference(sublist->tail); + while (item_p + && item_p->max_age + && (item_p->max_age > RSBAC_CURRENT_TIME) + ) + item_p = rcu_dereference(item_p->prev); + if (item_p) + memcpy(subdesc, (char *) item_p + sizeof(*item_p), + list->info.subdesc_size); + else { + memset(subdesc, 0, list->info.subdesc_size); + err = -RSBAC_ENOTFOUND; + } + } else { + if (!(list->flags & RSBAC_LIST_DEF_DATA)) + err = -RSBAC_ENOTFOUND; + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_subdata_ttl); +#endif +int rsbac_ta_list_lol_get_subdata_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, + void *subdesc, void *subdata) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + struct rsbac_list_item_t *item_p; + int err = 0; + struct rsbac_list_lol_hashed_t * hashed; + u_int hash = 0; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc || !subdesc)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + if (unlikely(subdata && !list->info.subdata_size)) { + return -RSBAC_EINVALIDREQUEST; + } + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "getting data from list %s.\n", list->name); +*/ + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + sublist = ta_lookup_lol_item(ta_number, list, hashed, hash, desc); + else +#endif + sublist = lookup_lol_item(list, hashed, hash, desc); + if (sublist) { /* exists -> lookup subitem */ + item_p = lookup_lol_subitem(list, sublist, subdesc); + if (item_p + && (!item_p->max_age + || (item_p->max_age > RSBAC_CURRENT_TIME) + ) + ) { /* exists -> copy data, if any */ + if (ttl_p) { + if (item_p->max_age) + *ttl_p = + item_p->max_age - + RSBAC_CURRENT_TIME; + else + *ttl_p = 0; + } + if (subdata) { + memcpy(subdata, + ((char *) item_p) + + sizeof(*item_p) + + list->info.subdesc_size, + list->info.subdata_size); + } + } else { + if (!list->def_subdata) + err = -RSBAC_ENOTFOUND; + else { + if (ttl_p) + *ttl_p = 0; + if (subdata) + memcpy(subdata, + list->def_subdata, + list->info.subdata_size); + } + } + } else { + if (!list->def_subdata) + err = -RSBAC_ENOTFOUND; + else { + if (ttl_p) + *ttl_p = 0; + if (subdata) + memcpy(subdata, + list->def_subdata, + list->info.subdata_size); + } + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_data_ttl); +#endif +int rsbac_ta_list_lol_get_data_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, void *data) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *item_p; + int err = 0; + struct rsbac_list_lol_hashed_t * hashed; + u_int hash = 0; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + if (unlikely(data && !list->info.data_size)) { + return -RSBAC_EINVALIDREQUEST; + } + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "getting data from list %s.\n", list->name); +*/ + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + item_p = ta_lookup_lol_item(ta_number, list, hashed, hash, desc); + else +#endif + item_p = lookup_lol_item(list, hashed, hash, desc); + if (item_p + && (!item_p->max_age || (item_p->max_age > RSBAC_CURRENT_TIME) + ) + ) { /* exists -> copy data, if any */ + if (ttl_p) { + if (item_p->max_age) + *ttl_p = + item_p->max_age - RSBAC_CURRENT_TIME; + else + *ttl_p = 0; + } + if (data) { + memcpy(data, + ((char *) item_p) + sizeof(*item_p) + + list->info.desc_size, list->info.data_size); + } + } else { + if (!list->def_data) + err = -RSBAC_ENOTFOUND; + else { + if (ttl_p) + *ttl_p = 0; + if (data) + memcpy(data, + list->def_data, + list->info.data_size); + } + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_get_max_desc); +#endif +int rsbac_ta_list_get_max_desc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *item_p = NULL; + struct rsbac_list_item_t *tmp_item_p; + int err = 0; + int i; + struct rsbac_list_hashed_t * hashed; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + for (i=0; imax_age && (tmp_item_p->max_age > RSBAC_CURRENT_TIME) + ) + tmp_item_p = rcu_dereference(tmp_item_p->prev); + if(tmp_item_p) { + if(list->compare) { + if(!item_p || list->compare(&tmp_item_p[1], &item_p[1]) > 0) + item_p = tmp_item_p; + } else { + if(!item_p || memcmp(&tmp_item_p[1], &item_p[1], list->info.desc_size) > 0) + item_p = tmp_item_p; + } + } + } + if (item_p) + memcpy(desc, (char *) item_p + sizeof(*item_p), + list->info.desc_size); + else { + memset(desc, 0, list->info.desc_size); + err = -RSBAC_ENOTFOUND; + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_get_next_desc); +#endif +int rsbac_ta_list_get_next_desc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *old_desc, void *next_desc) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *item_p; + struct rsbac_list_hashed_t * hashed; + u_int nr_hashes; + u_int hash = 0; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + if (unlikely(!next_desc)) + return -RSBAC_EINVALIDPOINTER; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + if (old_desc) { + if(list->hash_function) + hash = list->hash_function(old_desc, list->hash_bits); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + item_p = ta_lookup_item(ta_number, list, hashed, hash, old_desc); + else +#endif + item_p = lookup_item(list, hashed, hash, old_desc); + if(item_p) { + item_p = rcu_dereference(item_p->next); + while (item_p + && item_p->max_age && (item_p->max_age > RSBAC_CURRENT_TIME) + ) { + item_p = rcu_dereference(item_p->next); + } + hash++; + } else + hash = 0; + } else + item_p = NULL; + while (!item_p && (hash < nr_hashes)) { +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + item_p = rcu_dereference(hashed[hash].ta_head); + else +#endif + item_p = rcu_dereference(hashed[hash].head); + while (item_p + && item_p->max_age && (item_p->max_age > RSBAC_CURRENT_TIME) + ) { + item_p = rcu_dereference(item_p->next); + } + hash++; + } + if (item_p) { + memcpy(next_desc, (char *) item_p + sizeof(*item_p), + list->info.desc_size); + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + if (item_p) + return 0; + else + return -RSBAC_ENOTFOUND; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_get_next_desc_selector); +#endif +int rsbac_ta_list_get_next_desc_selector( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *old_desc, + void *next_desc, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *item_p; + struct rsbac_list_hashed_t * hashed; + u_int nr_hashes; + u_int hash = 0; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + if (unlikely(!next_desc)) + return -RSBAC_EINVALIDPOINTER; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + if (old_desc) { + if(list->hash_function) + hash = list->hash_function(old_desc, list->hash_bits); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + item_p = ta_lookup_item(ta_number, list, hashed, hash, old_desc); + else +#endif + item_p = lookup_item(list, hashed, hash, old_desc); + if(item_p) { + item_p = rcu_dereference(item_p->next); + while (item_p + && item_p->max_age && (item_p->max_age > RSBAC_CURRENT_TIME) + && !selector((char *) item_p + sizeof(*item_p), param) + ) { + item_p = rcu_dereference(item_p->next); + } + hash++; + } else + hash = 0; + } else + item_p = NULL; + while (!item_p && (hash < nr_hashes)) { +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + item_p = rcu_dereference(hashed[hash].ta_head); + else +#endif + item_p = rcu_dereference(hashed[hash].head); + while (item_p + && item_p->max_age && (item_p->max_age > RSBAC_CURRENT_TIME) + && !selector((char *) item_p + sizeof(*item_p), param) + ) { + item_p = rcu_dereference(item_p->next); + } + hash++; + } + if (item_p) { + memcpy(next_desc, (char *) item_p + sizeof(*item_p), + list->info.desc_size); + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + if (item_p) + return 0; + else + return -RSBAC_ENOTFOUND; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_next_desc); +#endif +int rsbac_ta_list_lol_get_next_desc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *old_desc, void *next_desc) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *item_p; + struct rsbac_list_lol_hashed_t * hashed; + u_int nr_hashes; + u_int hash = 0; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + if (unlikely(!next_desc)) + return -RSBAC_EINVALIDPOINTER; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + if (old_desc) { + if(list->hash_function) + hash = list->hash_function(old_desc, list->hash_bits); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + item_p = ta_lookup_lol_item(ta_number, list, hashed, hash, old_desc); + else +#endif + item_p = lookup_lol_item(list, hashed, hash, old_desc); + if(item_p) { + item_p = rcu_dereference(item_p->next); + while (item_p + && item_p->max_age && (item_p->max_age > RSBAC_CURRENT_TIME) + ) { + item_p = rcu_dereference(item_p->next); + } + hash++; + } else + hash = 0; + } else + item_p = NULL; + while (!item_p && (hash < nr_hashes)) { +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + item_p = rcu_dereference(hashed[hash].ta_head); + else +#endif + item_p = rcu_dereference(hashed[hash].head); + while (item_p + && item_p->max_age && (item_p->max_age > RSBAC_CURRENT_TIME) + ) { + item_p = rcu_dereference(item_p->next); + } + hash++; + } + if (item_p) { + memcpy(next_desc, (char *) item_p + sizeof(*item_p), + list->info.desc_size); + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + if (item_p) + return 0; + else + return -RSBAC_ENOTFOUND; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_next_desc_selector); +#endif +int rsbac_ta_list_lol_get_next_desc_selector( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *old_desc, void *next_desc, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *item_p; + struct rsbac_list_lol_hashed_t * hashed; + u_int nr_hashes; + u_int hash = 0; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + if (unlikely(!next_desc)) + return -RSBAC_EINVALIDPOINTER; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + if (old_desc) { + if(list->hash_function) + hash = list->hash_function(old_desc, list->hash_bits); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + item_p = ta_lookup_lol_item(ta_number, list, hashed, hash, old_desc); + else +#endif + item_p = lookup_lol_item(list, hashed, hash, old_desc); + if(item_p) { + item_p = rcu_dereference(item_p->next); + while (item_p + && item_p->max_age && (item_p->max_age > RSBAC_CURRENT_TIME) + && !selector((char *) item_p + sizeof(*item_p), param) + ) { + item_p = rcu_dereference(item_p->next); + } + hash++; + } else + hash = 0; + } else + item_p = NULL; + while (!item_p && (hash < nr_hashes)) { +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + item_p = rcu_dereference(hashed[hash].ta_head); + else +#endif + item_p = rcu_dereference(hashed[hash].head); + while (item_p + && item_p->max_age && (item_p->max_age > RSBAC_CURRENT_TIME) + && !selector((char *) item_p + sizeof(*item_p), param) + ) { + item_p = rcu_dereference(item_p->next); + } + hash++; + } + if (item_p) { + memcpy(next_desc, (char *) item_p + sizeof(*item_p), + list->info.desc_size); + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + if (item_p) + return 0; + else + return -RSBAC_ENOTFOUND; +} + +/* get item desc by data */ +/* Item desc is copied - we cannot give a pointer, because item could be + * removed. + * If no compare function is provided (NULL value), memcmp is used. + * Note: The data value given here is always used as second parameter to the + * compare function, so you can use different types for storage and + * lookup. + */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_get_desc_ttl); +#endif +int rsbac_ta_list_get_desc_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *item_p; + int err = 0; + struct rsbac_list_hashed_t * hashed; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc || !data)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "getting desc from list %s.\n", list->name); +*/ + if (unlikely(!list->info.data_size)) { + rcu_read_unlock(); + return -RSBAC_EINVALIDREQUEST; + } + + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + item_p = ta_lookup_item_data(ta_number, list, hashed, list->hash_bits, data, compare); +#else + item_p = lookup_item_data(list, hashed, list->hash_bits, data, compare); +#endif + if (item_p) { /* exists -> copy desc */ + memcpy(desc, + ((char *) item_p) + sizeof(*item_p), + list->info.desc_size); + if (ttl_p) { + if (item_p->max_age) + *ttl_p = item_p->max_age - RSBAC_CURRENT_TIME; + else + *ttl_p = 0; + } + } else { + err = -RSBAC_ENOTFOUND; + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_get_desc_selector_ttl); +#endif +int rsbac_ta_list_get_desc_selector_ttl( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *item_p; + int err = 0; + struct rsbac_list_hashed_t * hashed; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc || !data)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "getting desc from list %s.\n", list->name); +*/ + if (unlikely(!list->info.data_size)) { + rcu_read_unlock(); + return -RSBAC_EINVALIDREQUEST; + } + + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + item_p = ta_lookup_item_data_selector(ta_number, list, + hashed, list->hash_bits, + data, compare, + selector, + param); +#else + item_p = lookup_item_data_selector(list, + hashed, list->hash_bits, + data, compare, + selector, + param); +#endif + if (item_p) { /* exists -> copy desc */ + memcpy(desc, + ((char *) item_p) + sizeof(*item_p), + list->info.desc_size); + if (ttl_p) { + if (item_p->max_age) + *ttl_p = item_p->max_age - RSBAC_CURRENT_TIME; + else + *ttl_p = 0; + } + } else { + err = -RSBAC_ENOTFOUND; + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_desc_ttl); +#endif +int rsbac_ta_list_lol_get_desc_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *item_p; + int err = 0; + struct rsbac_list_lol_hashed_t * hashed; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc || !data)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + if (unlikely(!list->info.data_size)) { + return -RSBAC_EINVALIDREQUEST; + } + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "getting desc from list %s.\n", list->name); +*/ + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + item_p = ta_lookup_lol_item_data(ta_number, list, hashed, list->hash_bits, data, compare); +#else + item_p = lookup_lol_item_data(list, hashed, list->hash_bits, data, compare); +#endif + if (item_p) { /* exists -> copy desc */ + memcpy(desc, + ((char *) item_p) + sizeof(*item_p), + list->info.desc_size); + if (ttl_p) { + if (item_p->max_age) + *ttl_p = item_p->max_age - RSBAC_CURRENT_TIME; + else + *ttl_p = 0; + } + } else { + err = -RSBAC_ENOTFOUND; + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_desc_selector_ttl); +#endif +int rsbac_ta_list_lol_get_desc_selector_ttl( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + rsbac_time_t * ttl_p, + void *desc, + void *data, + rsbac_list_data_compare_function_t compare, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *item_p; + int err = 0; + struct rsbac_list_lol_hashed_t * hashed; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!desc || !data)) + return -RSBAC_EINVALIDVALUE; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + if (unlikely(!list->info.data_size)) { + return -RSBAC_EINVALIDREQUEST; + } + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "getting desc from list %s.\n", list->name); +*/ + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + item_p = ta_lookup_lol_item_data_selector(ta_number, + list, hashed, list->hash_bits, + data, compare, + selector, + param); +#else + item_p = lookup_lol_item_data_selector(list, hashed, list->hash_bits, + data, compare, + selector, + param); +#endif + if (item_p) { /* exists -> copy desc */ + memcpy(desc, + ((char *) item_p) + sizeof(*item_p), + list->info.desc_size); + if (ttl_p) { + if (item_p->max_age) + *ttl_p = item_p->max_age - RSBAC_CURRENT_TIME; + else + *ttl_p = 0; + } + } else { + err = -RSBAC_ENOTFOUND; + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return err; +} + +/* returns TRUE, if item exists or def_data is defined, FALSE, if not */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_exist); +#endif +int rsbac_ta_list_exist(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *item_p; + int result; + struct rsbac_list_hashed_t * hashed; + u_int hash = 0; + + if (unlikely(!handle || !desc)) + return FALSE; + if (unlikely(!list_initialized)) + return FALSE; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return FALSE; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "testing on list %s.\n", list->name); +*/ + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + item_p = ta_lookup_item(ta_number, list, hashed, hash, desc); + else +#endif + item_p = lookup_item(list, hashed, hash, desc); + if (item_p + && (!item_p->max_age || (item_p->max_age > RSBAC_CURRENT_TIME) + ) + ) { /* exists -> TRUE */ + result = TRUE; + } else { + result = FALSE; + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return result; +} + +/* does item exist? */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_subexist); +#endif +int rsbac_ta_list_lol_subexist(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, void *subdesc) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + struct rsbac_list_item_t *item_p; + int result; + struct rsbac_list_lol_hashed_t * hashed; + u_int hash = 0; + + if (unlikely(!handle || !desc || !subdesc)) + return FALSE; + if (unlikely(!list_initialized)) + return FALSE; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return FALSE; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "testing on list %s.\n", list->name); +*/ + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + sublist = ta_lookup_lol_item(ta_number, list, hashed, hash, desc); + else +#endif + sublist = lookup_lol_item(list, hashed, hash, desc); + if (sublist) { /* exists -> lookup subitem */ + item_p = lookup_lol_subitem(list, sublist, subdesc); + if (item_p + && (!item_p->max_age + || (item_p->max_age > RSBAC_CURRENT_TIME) + ) + ) { /* exists -> TRUE */ + result = TRUE; + } else { + result = FALSE; + } + } else { + result = FALSE; + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return result; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_subexist_compare); +#endif +int rsbac_ta_list_lol_subexist_compare(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, + void *subdesc, + rsbac_list_compare_function_t + compare) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + struct rsbac_list_item_t *item_p; + int result; + struct rsbac_list_lol_hashed_t * hashed; + u_int hash = 0; + + if (unlikely(!handle || !desc || !subdesc)) + return FALSE; + if (unlikely(!list_initialized)) + return FALSE; + /* Use standard function, if compare is not provided. */ + if (!compare) + return rsbac_list_lol_subexist(handle, desc, subdesc); + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return FALSE; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "testing on list %s.\n", list->name); +*/ + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + sublist = ta_lookup_lol_item(ta_number, list, hashed, hash, desc); + else +#endif + sublist = lookup_lol_item(list, hashed, hash, desc); + if (sublist) { /* exists -> lookup subitem */ + item_p = + lookup_lol_subitem_user_compare(list, sublist, subdesc, + compare); + if (item_p + && (!item_p->max_age + || (item_p->max_age > RSBAC_CURRENT_TIME) + ) + ) { /* exists -> TRUE */ + result = TRUE; + } else { + result = FALSE; + } + } else { + result = FALSE; + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return result; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_exist); +#endif +int rsbac_ta_list_lol_exist(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *item_p; + int result; + struct rsbac_list_lol_hashed_t * hashed; + u_int hash = 0; + + if (unlikely(!handle || !desc)) + return FALSE; + if (unlikely(!list_initialized)) + return FALSE; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return FALSE; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "testing on list %s.\n", list->name); +*/ + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + item_p = ta_lookup_lol_item(ta_number, list, hashed, hash, desc); + else +#endif + item_p = lookup_lol_item(list, hashed, hash, desc); + if (item_p + && (!item_p->max_age || (item_p->max_age > RSBAC_CURRENT_TIME) + ) + ) { /* exists -> TRUE */ + result = TRUE; + } else { + result = FALSE; + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return result; +} + +/* count number of elements */ +/* returns number of elements or negative error code */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_subcount); +#endif +long rsbac_ta_list_lol_subcount(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void *desc) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + long result; + struct rsbac_list_lol_hashed_t * hashed; + u_int hash = 0; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + sublist = ta_lookup_lol_item(ta_number, list, hashed, hash, desc); + else +#endif + sublist = lookup_lol_item(list, hashed, hash, desc); + if (sublist) { + result = sublist->count; + } else { + result = -RSBAC_ENOTFOUND; + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return result; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_all_subcount); +#endif +long rsbac_ta_list_lol_all_subcount(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + long result = 0; + int i; + struct rsbac_list_lol_hashed_t * hashed; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + for (i=0; icount; + sublist = rcu_dereference(sublist->next); + } + } + rcu_read_unlock(); + return result; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_count); +#endif +long rsbac_ta_list_lol_count(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle) +{ + struct rsbac_list_lol_reg_item_t *list; + long result = 0; + int i; + struct rsbac_list_lol_hashed_t * hashed; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + rcu_read_lock(); + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + for (i=0; iself != list)) + return -RSBAC_EINVALIDLIST; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + for (i=0; i 0, *array_p contains a pointer to a rsbac_kmalloc'd array + of descs, otherwise *array_p is set to NULL. If *array_p has been set, + caller must call rsbac_kfree(*array_p) after use! */ + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_get_all_desc); +#endif +long rsbac_ta_list_get_all_desc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void **array_p) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *item_p; + char *buffer; + u_long offset = 0; + u_long count = 0; + long result = 0; + u_int item_size; + int i; + struct rsbac_list_hashed_t * hashed; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!array_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + *array_p = NULL; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + for (i=0; iinfo.desc_size; + if(count > RSBAC_MAX_KMALLOC / item_size) + count = RSBAC_MAX_KMALLOC / item_size; + buffer = rsbac_kmalloc(item_size * count); + if (unlikely(!buffer)) { + result = -ENOMEM; + goto out_unlock; + } + for (i=0; imax_age + || (item_p->max_age > + RSBAC_CURRENT_TIME) + ) { + memcpy(buffer + offset, + ((char *) item_p) + + sizeof(*item_p), item_size); + offset += item_size; + result++; + } + item_p = rcu_dereference(item_p->next); + } + } + *array_p = buffer; + +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif +out_unlock: + rcu_read_unlock(); + return result; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_get_all_desc_selector); +#endif +long rsbac_ta_list_get_all_desc_selector ( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void **array_p, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *item_p; + char *buffer; + u_long offset = 0; + u_long count = 0; + long result = 0; + u_int item_size; + int i; + struct rsbac_list_hashed_t * hashed; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!array_p || !selector)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + *array_p = NULL; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + for (i=0; iinfo.desc_size; + if(count > RSBAC_MAX_KMALLOC / item_size) + count = RSBAC_MAX_KMALLOC / item_size; + buffer = rsbac_kmalloc(item_size * count); + if (unlikely(!buffer)) { + result = -ENOMEM; + goto out_unlock; + } + for (i=0; imax_age + || (item_p->max_age > + RSBAC_CURRENT_TIME) + ) + && selector(((char *) item_p) + sizeof(*item_p), param) + ) { + memcpy(buffer + offset, + ((char *) item_p) + + sizeof(*item_p), item_size); + offset += item_size; + result++; + } + item_p = rcu_dereference(item_p->next); + } + } + *array_p = buffer; + +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif +out_unlock: + rcu_read_unlock(); + return result; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_all_subdesc_ttl); +#endif +long rsbac_ta_list_lol_get_all_subdesc_ttl(rsbac_list_ta_number_t + ta_number, + rsbac_list_handle_t handle, + void *desc, void **array_p, + rsbac_time_t ** ttl_array_p) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + struct rsbac_list_item_t *item_p; + char *buffer; + rsbac_time_t *ttl_p = NULL; + u_long offset = 0; + long result = 0; + u_long count; + u_int item_size; + struct rsbac_list_lol_hashed_t * hashed; + u_int hash = 0; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!array_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + *array_p = NULL; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + sublist = ta_lookup_lol_item(ta_number, list, hashed, hash, desc); + else +#endif + sublist = lookup_lol_item(list, hashed, hash, desc); + if (sublist && sublist->count) { + item_size = list->info.subdesc_size; + count = sublist->count; + if(unlikely(count > RSBAC_MAX_KMALLOC / item_size)) + count = RSBAC_MAX_KMALLOC / item_size; + buffer = rsbac_kmalloc(item_size * count); + if (buffer) { + if (ttl_array_p) + ttl_p = + rsbac_kmalloc(sizeof(**ttl_array_p) * + sublist->count); + item_p = rcu_dereference(sublist->head); + while (item_p && (result < count)) { + if (!item_p->max_age + || (item_p->max_age > + RSBAC_CURRENT_TIME) + ) { + memcpy(buffer + offset, + ((char *) item_p) + + sizeof(*item_p), item_size); + if (ttl_p) { + if (item_p->max_age) + ttl_p[result] = + item_p-> + max_age - + RSBAC_CURRENT_TIME; + else + ttl_p[result] = 0; + } + offset += item_size; + result++; + } + item_p = rcu_dereference(item_p->next); + } + *array_p = buffer; + if (ttl_array_p) + *ttl_array_p = ttl_p; + } else { + result = -RSBAC_ENOMEM; + } + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return result; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_all_desc); +#endif +long rsbac_ta_list_lol_get_all_desc(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void **array_p) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *item_p; + char *buffer; + u_long offset = 0; + long result = 0; + u_int item_size; + int i; + u_long count = 0; + struct rsbac_list_lol_hashed_t * hashed; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!array_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + *array_p = NULL; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + for (i=0; iinfo.desc_size; + if(unlikely(count > RSBAC_MAX_KMALLOC / item_size)) + count = RSBAC_MAX_KMALLOC / item_size; + buffer = rsbac_kmalloc(item_size * count); + if (unlikely(!buffer)) { + result = -ENOMEM; + rsbac_pr_debug(lists, "list %s: could not allocate buffer for %u items of size %u!\n", + list->name, count, item_size); + goto out_unlock; + } + for (i=0; imax_age + || (item_p->max_age > + RSBAC_CURRENT_TIME) + ) { + memcpy(buffer + offset, + ((char *) item_p) + + sizeof(*item_p), item_size); + offset += item_size; + result++; + } + item_p = rcu_dereference(item_p->next); + } + } + *array_p = buffer; + +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif +out_unlock: + rcu_read_unlock(); + return result; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_all_desc_selector); +#endif +long rsbac_ta_list_lol_get_all_desc_selector ( + rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void **array_p, + rsbac_list_desc_selector_function_t selector, + void * param) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *item_p; + char *buffer; + u_long offset = 0; + long result = 0; + u_int item_size; + int i; + u_long count = 0; + struct rsbac_list_lol_hashed_t * hashed; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!array_p || !selector)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + *array_p = NULL; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + for (i=0; iinfo.desc_size; + if(unlikely(count > RSBAC_MAX_KMALLOC / item_size)) + count = RSBAC_MAX_KMALLOC / item_size; + buffer = rsbac_kmalloc(item_size * count); + if (unlikely(!buffer)) { + result = -ENOMEM; + rsbac_pr_debug(lists, "list %s: could not allocate buffer for %u items of size %u!\n", + list->name, count, item_size); + goto out_unlock; + } + for (i=0; imax_age + || (item_p->max_age > + RSBAC_CURRENT_TIME) + ) + && selector(((char *) item_p) + sizeof(*item_p), param) + ) { + memcpy(buffer + offset, + ((char *) item_p) + + sizeof(*item_p), item_size); + offset += item_size; + result++; + } + item_p = rcu_dereference(item_p->next); + } + } + *array_p = buffer; + +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif +out_unlock: + rcu_read_unlock(); + return result; +} + +/* Get array of all data */ +/* Returns number of elements or negative error code */ +/* If return value > 0, *array_p contains a pointer to a rsbac_kmalloc'd array + of datas, otherwise *array_p is set to NULL. If *array_p has been set, + caller must call rsbac_kfree(*array_p) after use! */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_get_all_data); +#endif +long rsbac_ta_list_get_all_data(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, void **array_p) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *item_p; + char *buffer; + u_long offset = 0; + long result = 0; + u_int item_size; + u_int item_offset; + int i; + u_long count = 0; + struct rsbac_list_hashed_t * hashed; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!array_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + *array_p = NULL; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + if (unlikely(!list->info.data_size)) { + rcu_read_unlock(); + return -RSBAC_EINVALIDREQUEST; + } + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + for (i=0; iinfo.data_size; + item_offset = list->info.desc_size; + if(unlikely(count > RSBAC_MAX_KMALLOC / item_size)) + count = RSBAC_MAX_KMALLOC / item_size; + buffer = rsbac_kmalloc(item_size * count); + if (unlikely(!buffer)) { + result = -ENOMEM; + goto out_unlock; + } + for (i=0; imax_age + || (item_p->max_age > + RSBAC_CURRENT_TIME) + ) { + memcpy(buffer + offset, + ((char *) item_p) + + sizeof(*item_p) + + item_offset, item_size); + offset += item_size; + result++; + } + item_p = rcu_dereference(item_p->next); + } + } + *array_p = buffer; + +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + +out_unlock: + rcu_read_unlock(); + return result; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_all_subdata); +#endif +long rsbac_ta_list_lol_get_all_subdata(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void *desc, void **array_p) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + struct rsbac_list_item_t *item_p; + char *buffer; + u_long offset = 0; + long result = 0; + u_long count; + u_int item_size; + u_int item_offset; + struct rsbac_list_lol_hashed_t * hashed; + u_int hash = 0; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!array_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + *array_p = NULL; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + if (unlikely(!list->info.subdata_size)) { + return -RSBAC_EINVALIDREQUEST; + } + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + sublist = ta_lookup_lol_item(ta_number, list, hashed, hash, desc); + else +#endif + sublist = lookup_lol_item(list, hashed, hash, desc); + if (sublist && sublist->count) { + item_size = list->info.subdata_size; + item_offset = list->info.subdesc_size; + count = sublist->count; + if(unlikely(count > RSBAC_MAX_KMALLOC / item_size)) + count = RSBAC_MAX_KMALLOC / item_size; + buffer = rsbac_kmalloc(item_size * count); + if (buffer) { + item_p = rcu_dereference(sublist->head); + while (item_p && (result < count)) { + if (!item_p->max_age + || (item_p->max_age > + RSBAC_CURRENT_TIME) + ) { + memcpy(buffer + offset, + ((char *) item_p) + + sizeof(*item_p) + + item_offset, item_size); + offset += item_size; + result++; + } + item_p = rcu_dereference(item_p->next); + } + *array_p = buffer; + } else { + result = -RSBAC_ENOMEM; + } + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return result; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_all_data); +#endif +long rsbac_ta_list_lol_get_all_data(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void **array_p) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *item_p; + char *buffer; + u_long offset = 0; + long result = 0; + u_int item_size; + u_int item_offset; + int i; + u_long count = 0; + struct rsbac_list_lol_hashed_t * hashed; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!array_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + *array_p = NULL; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + if (unlikely(!list->info.data_size)) { + rcu_read_unlock(); + return -RSBAC_EINVALIDREQUEST; + } + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + for (i=0; iinfo.data_size; + item_offset = list->info.desc_size; + if(unlikely(count > RSBAC_MAX_KMALLOC / item_size)) + count = RSBAC_MAX_KMALLOC / item_size; + buffer = rsbac_kmalloc(item_size * count); + if (unlikely(!buffer)) { + result = -ENOMEM; + goto out_unlock; + } + for (i=0; imax_age + || (item_p->max_age > + RSBAC_CURRENT_TIME) + ) { + memcpy(buffer + offset, + ((char *) item_p) + + sizeof(*item_p) + + item_offset, item_size); + offset += item_size; + result++; + } + item_p = rcu_dereference(item_p->next); + } + } + *array_p = buffer; + +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif +out_unlock: + rcu_read_unlock(); + return result; +} + +/* Get item size */ + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_get_item_size); +#endif +int rsbac_list_get_item_size(rsbac_list_handle_t handle) +{ + struct rsbac_list_reg_item_t *list; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + return list->info.desc_size + list->info.data_size; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_lol_get_subitem_size); +#endif +int rsbac_list_lol_get_subitem_size(rsbac_list_handle_t handle) +{ + struct rsbac_list_lol_reg_item_t *list; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + return list->info.subdesc_size + list->info.subdata_size; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_lol_get_item_size); +#endif +int rsbac_list_lol_get_item_size(rsbac_list_handle_t handle) +{ + struct rsbac_list_lol_reg_item_t *list; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + return list->info.desc_size + list->info.data_size; +} + +/* Get array of all items */ +/* Returns number of items or negative error code */ +/* If return value > 0, *array_p contains a pointer to a rsbac_kmalloc'd array of items, + where desc and data are placed directly behind each other. + If *array_p has been set (return value > 0), caller must call rsbac_kfree(*array_p) after use! */ + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_get_all_items_ttl); +#endif +long rsbac_ta_list_get_all_items_ttl(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void **array_p, + rsbac_time_t ** ttl_array_p) +{ + struct rsbac_list_reg_item_t *list; + struct rsbac_list_item_t *item_p; + char *buffer; + rsbac_time_t *ttl_p = NULL; + u_long offset = 0; + long result = 0; + u_int item_size; + int i; + u_long count = 0; + struct rsbac_list_hashed_t * hashed; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!array_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + *array_p = NULL; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + for (i=0; iinfo.desc_size + list->info.data_size; + if(unlikely(count > RSBAC_MAX_KMALLOC / item_size)) + count = RSBAC_MAX_KMALLOC / item_size; + buffer = rsbac_kmalloc(item_size * count); + if (unlikely(!buffer)) { + result = -ENOMEM; + goto out_unlock; + } + if (ttl_array_p) { + ttl_p = rsbac_kmalloc(sizeof(**ttl_array_p) * count); + if (!ttl_p) { + result = -ENOMEM; + rsbac_kfree(buffer); + goto out_unlock; + } + } + for (i=0; imax_age + || (item_p->max_age > + RSBAC_CURRENT_TIME) + ) { + memcpy(buffer + offset, + ((char *) item_p) + + sizeof(*item_p), item_size); + if (ttl_p) { + if (item_p->max_age) + ttl_p[result] = + item_p->max_age - RSBAC_CURRENT_TIME; + else + ttl_p[result] = 0; + } + offset += item_size; + result++; + } + item_p = rcu_dereference(item_p->next); + } + } + *array_p = buffer; + if (ttl_array_p) + *ttl_array_p = ttl_p; + +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif +out_unlock: + rcu_read_unlock(); + return result; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_all_subitems_ttl); +#endif +long rsbac_ta_list_lol_get_all_subitems_ttl(rsbac_list_ta_number_t + ta_number, + rsbac_list_handle_t handle, + void *desc, void **array_p, + rsbac_time_t ** ttl_array_p) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *sublist; + struct rsbac_list_item_t *item_p; + char *buffer; + rsbac_time_t *ttl_p = NULL; + u_long offset = 0; + long result = 0; + u_long count; + u_int item_size; + struct rsbac_list_lol_hashed_t * hashed; + u_int hash = 0; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!array_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + *array_p = NULL; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + if(list->hash_function) + hash = list->hash_function(desc, list->hash_bits); + hashed = rcu_dereference(list->hashed); +#ifdef CONFIG_RSBAC_LIST_TRANS + if (ta_number && (hashed[hash].ta_copied == ta_number)) + sublist = ta_lookup_lol_item(ta_number, list, hashed, hash, desc); + else +#endif + sublist = lookup_lol_item(list, hashed, hash, desc); + if (sublist && sublist->count) { + count = sublist->count; + item_size = + list->info.subdesc_size + list->info.subdata_size; + if(unlikely(count > RSBAC_MAX_KMALLOC / item_size)) + count = RSBAC_MAX_KMALLOC / item_size; + buffer = rsbac_kmalloc(item_size * count); + if (likely(buffer)) { + if (ttl_array_p) + ttl_p = + rsbac_kmalloc(sizeof(**ttl_array_p) * + sublist->count); + item_p = rcu_dereference(sublist->head); + while (item_p && (result < count)) { + if (!item_p->max_age + || (item_p->max_age > + RSBAC_CURRENT_TIME) + ) { + memcpy(buffer + offset, + ((char *) item_p) + + sizeof(*item_p), item_size); + if (ttl_p) { + if (item_p->max_age) + ttl_p[result] = + item_p-> + max_age - + RSBAC_CURRENT_TIME; + else + ttl_p[result] = 0; + } + offset += item_size; + result++; + } + item_p = rcu_dereference(item_p->next); + } + *array_p = buffer; + if (ttl_array_p) + *ttl_array_p = ttl_p; + } else { + result = -RSBAC_ENOMEM; + } + } +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif + rcu_read_unlock(); + return result; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_ta_list_lol_get_all_items); +#endif +long rsbac_ta_list_lol_get_all_items(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t handle, + void **array_p) +{ + struct rsbac_list_lol_reg_item_t *list; + struct rsbac_list_lol_item_t *item_p; + char *buffer; + u_long offset = 0; + long result = 0; + u_int item_size; + int i; + u_long count = 0; + struct rsbac_list_lol_hashed_t * hashed; + u_int nr_hashes; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!array_p)) + return -RSBAC_EINVALIDPOINTER; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + *array_p = NULL; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s.\n", list->name); +*/ + nr_hashes = 1 << list->hash_bits; + hashed = rcu_dereference(list->hashed); + for (i=0; iinfo.desc_size + list->info.data_size; + if(unlikely(count > RSBAC_MAX_KMALLOC / item_size)) + count = RSBAC_MAX_KMALLOC / item_size; + buffer = rsbac_kmalloc(item_size * count); + if (unlikely(!buffer)) { + result = -ENOMEM; + goto out_unlock; + } + for (i=0; imax_age + || (item_p->max_age > + RSBAC_CURRENT_TIME) + ) { + memcpy(buffer + offset, + ((char *) item_p) + + sizeof(*item_p), item_size); + offset += item_size; + result++; + } + item_p = rcu_dereference(item_p->next); + } + } + *array_p = buffer; + +#ifdef CONFIG_RSBAC_LIST_STATS + list->read_count++; +#endif +out_unlock: + rcu_read_unlock(); + return result; +} + +/* List hash functions + * + * nr_hashes is always 2^n, so we can safely use bit operations + */ + + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_hash_u32); +#endif +u_int rsbac_list_hash_u32(void * desc, __u8 hash_bits) +{ + return hash_32(*((__u32 *) desc), rsbac_min(hash_bits, 32)); +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_hash_fd); +#endif +u_int rsbac_list_hash_fd(void * desc, __u8 hash_bits) +{ + return hash_bits ? hash_32(*((rsbac_inode_nr_t *) desc), rsbac_min(hash_bits, 32)) : 0; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_hash_old_fd); +#endif +u_int rsbac_list_hash_old_fd(void * desc, __u8 hash_bits) +{ + return hash_bits ? hash_32(*((rsbac_old_inode_nr_t *) desc), rsbac_min(hash_bits, 32)) : 0; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_hash_pid); +#endif +u_int rsbac_list_hash_pid(void * desc, __u8 hash_bits) +{ + return hash_bits ? hash_32(*((__u32 *) desc), rsbac_min(hash_bits, 32)) : 0; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_hash_uid); +#endif +u_int rsbac_list_hash_uid(void * desc, __u8 hash_bits) +{ + return hash_bits ? hash_32(*((rsbac_uid_t *) desc), rsbac_min(hash_bits, 32)) : 0; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_hash_gid); +#endif +u_int rsbac_list_hash_gid(void * desc, __u8 hash_bits) +{ + return hash_bits ? hash_32(*((rsbac_gid_t *) desc), rsbac_min(hash_bits, 32)) : 0; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_hash_ipc); +#endif +u_int rsbac_list_hash_ipc(void * desc, __u8 hash_bits) +{ + return hash_bits ? hash_32(((struct rsbac_ipc_t *) desc)->id.id_nr, rsbac_min(hash_bits, 32)) : 0; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_hash_dev); +#endif +u_int rsbac_list_hash_dev(void * desc, __u8 hash_bits) +{ + return hash_bits ? hash_32( ((struct rsbac_dev_desc_t *) desc)->major + ((struct rsbac_dev_desc_t *) desc)->minor, + rsbac_min(hash_bits, 32)) : 0; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_hash_nettemp); +#endif +u_int rsbac_list_hash_nettemp(void * desc, __u8 hash_bits) +{ + return hash_bits ? hash_32(*((rsbac_net_temp_id_t *) desc), rsbac_min(hash_bits, 32)) : 0; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_hash_netobj); +#endif +u_int rsbac_list_hash_netobj(void * desc, __u8 hash_bits) +{ + return hash_bits ? hash_32(*((__u32 *) desc), rsbac_min(hash_bits, 32)) : 0; +} +/* Copy a complete list to another */ + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_copy); +#endif +long rsbac_list_copy(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t from_handle, + rsbac_list_handle_t to_handle) +{ + struct rsbac_list_reg_item_t *from_list; + struct rsbac_list_reg_item_t *to_list; + struct rsbac_list_item_t *item_p; + int i; + int err = 0; + struct rsbac_list_rcu_free_head_t * rcu_head_p; + struct rsbac_list_hashed_t * from_hashed; + u_int nr_from_hashes; + u_int nr_to_hashes; + + if (unlikely(!from_handle || !to_handle)) + return -RSBAC_EINVALIDLIST; + + from_list = (struct rsbac_list_reg_item_t *) from_handle; + if (unlikely(from_list->self != from_list)) + return -RSBAC_EINVALIDLIST; + to_list = (struct rsbac_list_reg_item_t *) to_handle; + if (unlikely(to_list->self != to_list)) + return -RSBAC_EINVALIDLIST; + if(unlikely((from_list->info.desc_size != to_list->info.desc_size) + || (from_list->info.data_size != to_list->info.data_size))) + return -RSBAC_EINVALIDVALUE; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number)) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s to list %s.\n", + from_list->name, to_list->name); +*/ + spin_lock(&to_list->lock); + nr_to_hashes = 1 << to_list->hash_bits; + +#ifdef CONFIG_RSBAC_LIST_TRANS + /* Check for other transactions at the target list */ + if(unlikely(ta_number)) + for (i=0; ihashed[i].ta_copied != ta_number)) { + err = -RSBAC_EBUSY; + goto out_unlock; + } +#endif + for (i=0; ihashed[i].ta_copied == ta_number)) + ta_remove_all_items(to_list, i); + else +#endif + remove_all_items(to_list, i); + } + nr_from_hashes = 1 << from_list->hash_bits; + from_hashed = rcu_dereference(from_list->hashed); + for (i=0; imax_age, + &item_p[1], + &item_p[1] + from_list->info.desc_size)) { + err = -RSBAC_EWRITEFAILED; + goto out_unlock; + } + item_p = rcu_dereference(item_p->next); + } + } + else +#endif + { + item_p = rcu_dereference(from_hashed[i].head); + while(item_p) { + if (!add_item(to_list, + item_p->max_age, + &item_p[1], + &item_p[1] + from_list->info.desc_size)) { + err = -RSBAC_EWRITEFAILED; + goto out_unlock; + } + item_p = rcu_dereference(item_p->next); + } + } + } + +#ifdef CONFIG_RSBAC_LIST_STATS + from_list->read_count++; + to_list->write_count++; +#endif +out_unlock: + rcu_head_p = get_rcu_free(to_list); + spin_unlock(&to_list->lock); + rcu_read_unlock(); + do_sync_rcu(rcu_head_p); + return err; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_lol_copy); +#endif +long rsbac_list_lol_copy(rsbac_list_ta_number_t ta_number, + rsbac_list_handle_t from_handle, + rsbac_list_handle_t to_handle) +{ + struct rsbac_list_lol_reg_item_t *from_list; + struct rsbac_list_lol_reg_item_t *to_list; + struct rsbac_list_lol_item_t *item_p; + struct rsbac_list_lol_item_t *new_item_p; + struct rsbac_list_item_t *subitem_p; + struct rsbac_list_item_t *new_subitem_p; + u_int subitem_size; + int i; + int err = 0; + struct rsbac_list_rcu_free_head_lol_t * rcu_head_lol_p; + struct rsbac_list_lol_hashed_t * from_hashed; + u_int nr_from_hashes; + u_int nr_to_hashes; + + if (unlikely(!from_handle || !to_handle)) + return -RSBAC_EINVALIDLIST; + + from_list = (struct rsbac_list_lol_reg_item_t *) from_handle; + if (unlikely(from_list->self != from_list)) + return -RSBAC_EINVALIDLIST; + to_list = (struct rsbac_list_lol_reg_item_t *) to_handle; + if (unlikely(to_list->self != to_list)) + return -RSBAC_EINVALIDLIST; + if(unlikely((from_list->info.desc_size != to_list->info.desc_size) + || (from_list->info.data_size != to_list->info.data_size) + || (from_list->info.subdesc_size != to_list->info.subdesc_size) + || (from_list->info.subdata_size != to_list->info.subdata_size))) + return -RSBAC_EINVALIDVALUE; + +#ifdef CONFIG_RSBAC_LIST_TRANS + while(ta_committing) + msleep(100); + if (unlikely(ta_number && !rsbac_ta_list_exist(0, ta_handle, &ta_number))) + return -RSBAC_EINVALIDTRANSACTION; +#endif + + subitem_size = sizeof(*new_subitem_p) + + from_list->info.subdesc_size + from_list->info.subdata_size; + + rcu_read_lock(); +/* + rsbac_pr_debug(lists, "list %s to list %s.\n", + from_list->name, to_list->name); +*/ + spin_lock(&to_list->lock); + nr_to_hashes = 1 << to_list->hash_bits; + +#ifdef CONFIG_RSBAC_LIST_TRANS + /* Check for other transactions at the target list */ + if(unlikely(ta_number)) + for (i=0; ihashed[i].ta_copied != ta_number)) { + err = -RSBAC_EBUSY; + goto out_unlock; + } +#endif + for (i=0; ihashed[i].ta_copied == ta_number)) + ta_remove_all_lol_items(to_list, i); + else +#endif + remove_all_lol_items(to_list, i); + } + nr_from_hashes = 1 << from_list->hash_bits; + from_hashed = rcu_dereference(from_list->hashed); + for (i=0; imax_age, + &item_p[1], + &item_p[1] + from_list->info.desc_size); + if(unlikely(!new_item_p)) { + err = -RSBAC_EWRITEFAILED; + goto out_unlock; + } + subitem_p = rcu_dereference(item_p->head); + while (subitem_p) { + if (to_list->subslab) + new_subitem_p = rsbac_smalloc(to_list->subslab); + else + new_subitem_p = rsbac_kmalloc(subitem_size); + if (!new_subitem_p) { + err = -RSBAC_ENOMEM; + goto out_unlock; + } + memcpy(new_subitem_p, subitem_p, subitem_size); + new_subitem_p->prev = NULL; + new_subitem_p->next = NULL; + if (new_item_p->tail) { + new_subitem_p->prev = new_item_p->tail; + new_item_p->tail->next = new_subitem_p; + new_item_p->tail = new_subitem_p; + new_item_p->count++; + } else { + new_item_p->head = new_subitem_p; + new_item_p->tail = new_subitem_p; + new_item_p->count = 1; + } + subitem_p = rcu_dereference(subitem_p->next); + } + item_p = rcu_dereference(item_p->next); + } + } + else +#endif + { + item_p = rcu_dereference(from_hashed[i].head); + while(item_p) { + new_item_p = add_lol_item(to_list, + item_p->max_age, + &item_p[1], + &item_p[1] + from_list->info.desc_size); + if(unlikely(!new_item_p)) { + err = -RSBAC_EWRITEFAILED; + goto out_unlock; + } + subitem_p = rcu_dereference(item_p->head); + while (subitem_p) { + if (to_list->subslab) + new_subitem_p = rsbac_smalloc(to_list->subslab); + else + new_subitem_p = rsbac_kmalloc(subitem_size); + if (!new_subitem_p) { + err = -RSBAC_ENOMEM; + goto out_unlock; + } + memcpy(new_subitem_p, subitem_p, subitem_size); + new_subitem_p->prev = NULL; + new_subitem_p->next = NULL; + if (new_item_p->tail) { + new_subitem_p->prev = new_item_p->tail; + new_item_p->tail->next = new_subitem_p; + new_item_p->tail = new_subitem_p; + new_item_p->count++; + } else { + new_item_p->head = new_subitem_p; + new_item_p->tail = new_subitem_p; + new_item_p->count = 1; + } + subitem_p = rcu_dereference(subitem_p->next); + } + item_p = rcu_dereference(item_p->next); + } + } + } + +#ifdef CONFIG_RSBAC_LIST_STATS + from_list->read_count++; + to_list->write_count++; +#endif +out_unlock: + rcu_head_lol_p = get_rcu_free_lol(to_list); + spin_unlock(&to_list->lock); + rcu_read_unlock(); + do_sync_rcu_lol(rcu_head_lol_p); + return err; +} + +static int do_rehash(struct rsbac_list_reg_item_t *list, __u8 new_bits) +{ + struct rsbac_list_hashed_t * old_hashed; + struct rsbac_list_hashed_t * new_hashed; + int i; + struct rsbac_list_item_t *item_p; + struct rsbac_list_item_t *new_item_p; + u_int new_hash; + u_int old_nr; + u_int new_nr = 1 << new_bits; + u_int item_size; + + new_hashed = rsbac_kmalloc_clear_unlocked(new_nr*sizeof(struct rsbac_list_hashed_t)); + if(unlikely(!new_hashed)) { + return -RSBAC_ENOMEM; + } + spin_lock(&list->lock); + old_nr = 1 << list->hash_bits; +#ifdef CONFIG_RSBAC_LIST_TRANS + for(i=0; ihashed[i].ta_copied) { + spin_unlock(&list->lock); + rsbac_kfree(new_hashed); + return -RSBAC_EBUSY; + } +#endif + old_hashed = list->hashed; + item_size = sizeof(*item_p) + list->info.desc_size + list->info.data_size; + for(i=0; islab) + new_item_p = rsbac_smalloc(list->slab); + else + new_item_p = rsbac_kmalloc(item_size); + if (!new_item_p) + goto out_nomem; + memcpy(new_item_p, item_p, item_size); + new_hash = list->hash_function(&new_item_p[1], new_bits); + new_item_p->next = NULL; + if (!new_hashed[new_hash].head) { + new_hashed[new_hash].head = new_item_p; + new_hashed[new_hash].tail = new_item_p; + new_hashed[new_hash].count = 1; + new_item_p->prev = NULL; + } else { + new_item_p->prev = new_hashed[new_hash].tail; + new_hashed[new_hash].tail->next = new_item_p; + new_hashed[new_hash].tail = new_item_p; + new_hashed[new_hash].count++; + } + item_p = item_p->next; + } + } + rcu_assign_pointer(list->hashed, new_hashed); + list->hash_bits = new_bits; + spin_unlock(&list->lock); + synchronize_rcu(); + for(i=0; inext; + rsbac_sfree(list->slab, item_p); + item_p = new_item_p; + } + } + rsbac_kfree(old_hashed); + return 0; + +out_nomem: + spin_unlock(&list->lock); + for(i=0; inext; + rsbac_sfree(list->slab, item_p); + item_p = new_item_p; + } + } + rsbac_kfree(new_hashed); + return -RSBAC_ENOMEM; +} + +static int do_lol_rehash(struct rsbac_list_lol_reg_item_t *list, __u8 new_bits) +{ + struct rsbac_list_lol_hashed_t * old_hashed; + struct rsbac_list_lol_hashed_t * new_hashed; + int i; + struct rsbac_list_lol_item_t *item_p; + struct rsbac_list_lol_item_t *new_item_p; + u_int new_hash; + u_int old_nr; + u_int new_nr = 1 << new_bits; + u_int item_size; + + new_hashed = rsbac_kmalloc_clear_unlocked(new_nr*sizeof(struct rsbac_list_lol_hashed_t)); + if(unlikely(!new_hashed)) { + return -RSBAC_ENOMEM; + } + spin_lock(&list->lock); + old_nr = 1 << list->hash_bits; +#ifdef CONFIG_RSBAC_LIST_TRANS + for(i=0; ihashed[i].ta_copied) { + spin_unlock(&list->lock); + rsbac_kfree(new_hashed); + return -RSBAC_EBUSY; + } +#endif + old_hashed = list->hashed; + item_size = sizeof(*item_p) + list->info.desc_size + list->info.data_size; + for(i=0; islab) + new_item_p = rsbac_smalloc(list->slab); + else + new_item_p = rsbac_kmalloc(item_size); + if (!new_item_p) + goto out_nomem; + memcpy(new_item_p, item_p, item_size); + new_hash = list->hash_function(&new_item_p[1], new_bits); + new_item_p->next = NULL; + if (!new_hashed[new_hash].head) { + new_hashed[new_hash].head = new_item_p; + new_hashed[new_hash].tail = new_item_p; + new_hashed[new_hash].count = 1; + new_item_p->prev = NULL; + } else { + new_item_p->prev = new_hashed[new_hash].tail; + new_hashed[new_hash].tail->next = new_item_p; + new_hashed[new_hash].tail = new_item_p; + new_hashed[new_hash].count++; + } + item_p = item_p->next; + } + } + rcu_assign_pointer(list->hashed, new_hashed); + list->hash_bits = new_bits; + spin_unlock(&list->lock); + synchronize_rcu(); + for(i=0; inext; + rsbac_sfree(list->slab, item_p); + item_p = new_item_p; + } + } + rsbac_kfree(old_hashed); + return 0; + +out_nomem: + spin_unlock(&list->lock); + for(i=0; inext; + rsbac_sfree(list->slab, item_p); + item_p = new_item_p; + } + } + rsbac_kfree(new_hashed); + return -RSBAC_ENOMEM; +} + +#ifdef CONFIG_RSBAC_AUTO_WRITE +/* Work through all lists and resize, if allowed and necessary */ +int rsbac_list_auto_rehash(void) +{ + int i; + int err; + struct rsbac_list_reg_item_t *list; + struct rsbac_list_lol_reg_item_t *lol_list; + long count; + u_int nr_rehashed = 0; + u_int nr_hashes; + int srcu_idx; + + srcu_idx = srcu_read_lock(®_list_srcu); + list = srcu_dereference(reg_head.head, ®_list_srcu); + while(list) { + if((list->flags & RSBAC_LIST_AUTO_HASH_RESIZE) + && (list->hash_bits < rsbac_list_max_hash_bits)) { + count = 0; + nr_hashes = 1 << list->hash_bits; + for (i=0; ihashed[i].count <= list->max_items_per_hash) { + count += list->hashed[i].count; + } else { + rsbac_printk(KERN_WARNING "rsbac_list_auto_rehash(): list %s on device %02u:%02u has an invalid count %u in hash %u, skipping it\n", + list->name, MAJOR(list->device), MINOR(list->device), list->hashed[i].count, i); + i = -1; + break; + } + } + if (i == -1) { + list = list->next; + continue; + } + if(count / (1 << list->hash_bits) > rsbac_list_auto_rehash_trigger) { + u_int new_bits; + + new_bits = list->hash_bits; + while((new_bits < rsbac_list_max_hash_bits) + && (count / (1 << new_bits) > rsbac_list_auto_rehash_trigger)) + new_bits++; + if(new_bits > rsbac_list_max_hash_bits) + new_bits = rsbac_list_max_hash_bits; +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_auto) + rsbac_printk(KERN_DEBUG "rsbac_list_auto_rehash(): changing list %s hash bits on device %02u:%02u from %u to %u, sum of %li items\n", + list->name, MAJOR(list->device), MINOR(list->device), list->hash_bits, new_bits, count); +#endif + err = do_rehash(list, new_bits); + if(!err) + nr_rehashed++; + else { + rsbac_printk(KERN_WARNING "rsbac_list_auto_rehash(): changing list %s hash bits on device %02u:%02u from %u to %u failed with error %i\n", + list->name, MAJOR(list->device), MINOR(list->device), list->hash_bits, new_bits, err); + } + } + } + list = srcu_dereference(list->next, ®_list_srcu); + } + srcu_read_unlock(®_list_srcu, srcu_idx); + srcu_idx = srcu_read_lock(&lol_reg_list_srcu); + lol_list = srcu_dereference(lol_reg_head.head, &lol_reg_list_srcu); + while(lol_list) { + if((lol_list->flags & RSBAC_LIST_AUTO_HASH_RESIZE) + && (lol_list->hash_bits < rsbac_list_max_hash_bits)) { + count = 0; + nr_hashes = 1 << lol_list->hash_bits; + for (i=0; ihashed[i].count <= lol_list->max_items_per_hash) { + count += lol_list->hashed[i].count; + } else { + rsbac_printk(KERN_WARNING "rsbac_list_auto_rehash(): list of lists %s on device %02u:%02u has an invalid count %u in hash %u, skipping it\n", + lol_list->name, MAJOR(lol_list->device), MINOR(lol_list->device), lol_list->hashed[i].count, i); + i = -1; + break; + } + } + if (i == -1) { + lol_list = lol_list->next; + continue; + } + if(count / (1 << lol_list->hash_bits) > rsbac_list_auto_rehash_trigger) { + u_int new_bits; + + new_bits = lol_list->hash_bits; + while((new_bits < rsbac_list_max_hash_bits) + && (count / (1 << new_bits) > rsbac_list_auto_rehash_trigger)) + new_bits++; + if(new_bits > rsbac_list_max_hash_bits) + new_bits = rsbac_list_max_hash_bits; +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_auto) + rsbac_printk(KERN_DEBUG "rsbac_list_auto_rehash(): changing list of lists %s hash bits on device %02u:%02u from %u to %u, sum of %li items\n", + lol_list->name, MAJOR(lol_list->device), MINOR(lol_list->device), lol_list->hash_bits, new_bits, count); +#endif + err = do_lol_rehash(lol_list, new_bits); + if(!err) + nr_rehashed++; + else { + rsbac_printk(KERN_WARNING "rsbac_list_auto_rehash(): changing list of lists %s hash bits on device %02u:%02u from %u to %u failed with error %i\n", + lol_list->name, MAJOR(lol_list->device), MINOR(lol_list->device), lol_list->hash_bits, new_bits, err); + } + } + } + lol_list = srcu_dereference(lol_list->next, &lol_reg_list_srcu); + } + srcu_read_unlock(&lol_reg_list_srcu, srcu_idx); + +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_auto && (nr_rehashed > 0)) + rsbac_printk(KERN_DEBUG "rsbac_list_auto_rehash(): %u lists rehashed\n", + nr_rehashed); +#endif + return nr_rehashed; +} +#endif + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_get_hash_bits); +#endif +int rsbac_list_get_hash_bits(rsbac_list_handle_t handle) +{ + struct rsbac_list_reg_item_t *list; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + + return list->hash_bits; +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_list_lol_get_hash_bits); +#endif +int rsbac_list_lol_get_hash_bits(rsbac_list_handle_t handle) +{ + struct rsbac_list_lol_reg_item_t *list; + + if (unlikely(!handle)) + return -RSBAC_EINVALIDLIST; + if (unlikely(!list_initialized)) + return -RSBAC_ENOTINITIALIZED; + + list = (struct rsbac_list_lol_reg_item_t *) handle; + if (unlikely(list->self != list)) + return -RSBAC_EINVALIDLIST; + + return list->hash_bits; +} diff --git a/rsbac/data_structures/mac_data_structures.c b/rsbac/data_structures/mac_data_structures.c new file mode 100644 index 000000000000..366b912ad6be --- /dev/null +++ b/rsbac/data_structures/mac_data_structures.c @@ -0,0 +1,1234 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of MAC data structures */ +/* Author and (c) 1999-2016: Amon Ott */ +/* */ +/* Last modified: 25/Jan/2016 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************** */ +/* Global Variables */ +/************************************************************************** */ + +static struct rsbac_mac_device_list_head_t device_list_head; +static struct srcu_struct device_list_srcu; +static struct lock_class_key device_list_lock_class; + +static rsbac_list_handle_t process_handle = NULL; + +/**************************************************/ +/* Declarations of external functions */ +/**************************************************/ + +rsbac_boolean_t writable(struct super_block *sb_p); + +/**************************************************/ +/* Declarations of internal functions */ +/**************************************************/ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +static u_int nr_fd_hash_bits = RSBAC_MAC_NR_TRU_FD_LIST_HASH_BITS; + +static int fd_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + memcpy(new_desc, old_desc, sizeof(rsbac_old_inode_nr_t)); + return 0; +} + +static rsbac_list_conv_function_t *fd_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_MAC_FD_OLD_LIST_VERSION: + return fd_conv; + default: + return NULL; + } +} + +static int fd_subconv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + *((rsbac_uid_t *) new_desc) = *((rsbac_old_uid_t *) old_desc); + return 0; +} + +static rsbac_list_conv_function_t *fd_get_subconv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_MAC_FD_OLD_LIST_VERSION: + return fd_subconv; + default: + return NULL; + } +} + + + +/* mac_register_fd_lists() */ +/* register fd ACL lists for device */ + +static int mac_register_fd_lists(struct rsbac_mac_device_list_item_t + *device_p, kdev_t kdev) +{ + int err = 0; + int tmperr; + struct rsbac_list_lol_info_t lol_info; + + if (!device_p) + return -RSBAC_EINVALIDPOINTER; + + lol_info.version = RSBAC_MAC_FD_LIST_VERSION; + lol_info.key = RSBAC_MAC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_old_inode_nr_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_uid_t); + lol_info.subdata_size = 0; /* rights */ + lol_info.max_age = 0; + tmperr = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &device_p->handle, + &lol_info, + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA, + NULL, + NULL, + fd_get_conv, fd_get_subconv, + NULL, NULL, + RSBAC_MAC_FD_FILENAME, kdev, + nr_fd_hash_bits, + rsbac_list_hash_old_fd, + RSBAC_MAC_FD_OLD_FILENAME); + if (tmperr) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "mac_register_fd_lists(): registering list %s for device %02u:%02u failed with error %s!\n", + RSBAC_MAC_FD_FILENAME, + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev), + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + err = tmperr; + } + return err; +} + +/* mac_detach_fd_lists() */ +/* detach from fd MAC lists for device */ + +static int mac_detach_fd_lists(struct rsbac_mac_device_list_item_t + *device_p) +{ + int err = 0; + + if (!device_p) + return -RSBAC_EINVALIDPOINTER; + + err = rsbac_list_lol_detach(&device_p->handle, + RSBAC_MAC_LIST_KEY); + if (err) { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (tmp) { + rsbac_printk(KERN_WARNING "mac_detach_fd_lists(): detaching from list %s for device %02u:%02u failed with error %s!\n", + RSBAC_MAC_FD_FILENAME, + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } + return err; +} + +/************************************************************************** */ +/* The lookup functions return NULL, if the item is not found, and a */ +/* pointer to the item otherwise. */ + +/* first the device item lookup */ +static struct rsbac_mac_device_list_item_t *lookup_device(kdev_t kdev) +{ + struct rsbac_mac_device_list_item_t *curr = srcu_dereference(device_list_head.curr, &device_list_srcu); + + /* if there is no current item or it is not the right one, search... */ + if (!(curr && (RSBAC_MAJOR(curr->id) == RSBAC_MAJOR(kdev)) + && (RSBAC_MINOR(curr->id) == RSBAC_MINOR(kdev)) + ) + ) { + curr = srcu_dereference(device_list_head.head, &device_list_srcu); + while (curr + && ((RSBAC_MAJOR(curr->id) != RSBAC_MAJOR(kdev)) + || (RSBAC_MINOR(curr->id) != RSBAC_MINOR(kdev)) + ) + ) { + curr = srcu_dereference(curr->next, &device_list_srcu); + } + if (curr) + device_list_head.curr = curr; + } + /* it is the current item -> return it */ + return curr; +} + +static struct rsbac_mac_device_list_item_t *lookup_device_locked(kdev_t kdev) +{ + struct rsbac_mac_device_list_item_t *curr = device_list_head.curr; + + /* if there is no current item or it is not the right one, search... */ + if (!(curr && (RSBAC_MAJOR(curr->id) == RSBAC_MAJOR(kdev)) + && (RSBAC_MINOR(curr->id) == RSBAC_MINOR(kdev)) + ) + ) { + curr = device_list_head.head; + while (curr + && ((RSBAC_MAJOR(curr->id) != RSBAC_MAJOR(kdev)) + || (RSBAC_MINOR(curr->id) != RSBAC_MINOR(kdev)) + ) + ) { + curr = curr->next; + } + if (curr) + device_list_head.curr = curr; + } + /* it is the current item -> return it */ + return curr; +} + +/************************************************************************** */ +/* The add_item() functions add an item to the list, set head.curr to it, */ +/* and return a pointer to the item. */ +/* These functions will NOT check, if there is already an item under the */ +/* same ID! If this happens, the lookup functions will return the old item! */ +/* All list manipulation is protected by rw-spinlocks to prevent inconsistency */ +/* and undefined behaviour in other concurrent functions. */ + +/* Create a device item without adding to list. No locking needed. */ +static struct rsbac_mac_device_list_item_t +*create_device_item(kdev_t kdev) +{ + struct rsbac_mac_device_list_item_t *new_item_p; + + /* allocate memory for new device, return NULL, if failed */ + if (!(new_item_p = (struct rsbac_mac_device_list_item_t *) + rsbac_kmalloc(sizeof(*new_item_p)))) + return NULL; + + new_item_p->id = kdev; + new_item_p->mount_count = 1; + + /* init file/dir sublists */ + new_item_p->handle = NULL; + return new_item_p; +} + +/* Add an existing device item to list. Locking needed. */ +static struct rsbac_mac_device_list_item_t +*add_device_item(struct rsbac_mac_device_list_item_t *device_p) +{ + if (!device_p) + return NULL; + + /* add new device to device list */ + if (!device_list_head.head) { /* first device */ + device_p->prev = NULL; + device_p->next = NULL; + rcu_assign_pointer(device_list_head.head, device_p); + rcu_assign_pointer(device_list_head.tail, device_p); + rcu_assign_pointer(device_list_head.curr, device_p); + device_list_head.count = 1; + } else { /* there is another device -> hang to tail */ + device_p->prev = device_list_head.tail; + device_p->next = NULL; + rcu_assign_pointer(device_list_head.tail->next, device_p); + rcu_assign_pointer(device_list_head.tail, device_p); + rcu_assign_pointer(device_list_head.curr, device_p); + device_list_head.count++; + } + return device_p; +} + +/************************************************************************** */ +/* The remove_item() functions remove an item from the list. If this item */ +/* is head, tail or curr, these pointers are set accordingly. */ +/* To speed up removing several subsequent items, curr is set to the next */ +/* item, if possible. */ +/* If the item is not found, nothing is done. */ + +static void clear_device_item(struct rsbac_mac_device_list_item_t *item_p) +{ + if (!item_p) + return; + + /* First deregister lists... */ + mac_detach_fd_lists(item_p); + rsbac_kfree(item_p); +} + +static void remove_device_item(struct rsbac_mac_device_list_item_t *item_p) +{ + if (item_p) { /* ok, item was found */ + if (device_list_head.head == item_p) { /* item is head */ + if (device_list_head.tail == item_p) { /* item is head and tail = only item -> list will be empty */ + rcu_assign_pointer(device_list_head.head, NULL); + rcu_assign_pointer(device_list_head.tail, NULL); + } else { /* item is head, but not tail -> next item becomes head */ + rcu_assign_pointer(item_p->next->prev, NULL); + rcu_assign_pointer(device_list_head.head, item_p->next); + } + } else { /* item is not head */ + if (device_list_head.tail == item_p) { /*item is not head, but tail -> previous item becomes tail */ + rcu_assign_pointer(item_p->prev->next, NULL); + rcu_assign_pointer(device_list_head.tail, item_p->prev); + } else { /* item is neither head nor tail -> item is cut out */ + rcu_assign_pointer(item_p->prev->next, item_p->next); + rcu_assign_pointer(item_p->next->prev, item_p->prev); + } + } + + /* curr is no longer valid -> reset. */ + device_list_head.curr = NULL; + /* adjust counter */ + device_list_head.count--; + } +} + +/************************************************************************** */ +/* The copy_fp_tru_set_item() function copies a file cap set to a process */ +/* cap set */ + +static int copy_fp_tru_set_item(struct rsbac_mac_device_list_item_t + *device_p, rsbac_mac_file_t file, + rsbac_pid_t pid) +{ + rsbac_uid_t *tru_item_p; + rsbac_time_t *ttl_p; + int i; + long count; + enum rsbac_target_t target = T_FILE; + union rsbac_target_id_t tid; + rsbac_old_inode_nr_t inode_nr = file.inode; + + rsbac_list_lol_remove(process_handle, &pid); + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->handle, + &inode_nr, + (void **) &tru_item_p, + &ttl_p); + if (!count || (count == -RSBAC_ENOTFOUND) + ) { + tid.file = file; + if (!rsbac_get_parent(target, tid, &target, &tid)) { + inode_nr = tid.file.inode; + count = rsbac_list_lol_get_all_subdesc_ttl(device_p->handle, + &inode_nr, + (void **) + &tru_item_p, + &ttl_p); + } + } + if (count > 0) { + for (i = 0; i < count; i++) { + rsbac_list_lol_subadd_ttl(process_handle, + ttl_p[i], + &pid, + &tru_item_p[i], NULL); + } + rsbac_kfree(tru_item_p); + rsbac_kfree(ttl_p); + } else { + if ((count < 0) + && (count != -RSBAC_ENOTFOUND) + ) + return count; + } + + return 0; +} /* end of copy_fp_tru_set_item() */ + +/************************************************************************** */ +/* The copy_pp_tru_set_item() function copies a process cap set to another */ + +static int copy_pp_tru_set_item_handle(rsbac_list_handle_t handle, + rsbac_pid_t old_pid, + rsbac_pid_t new_pid) +{ + rsbac_uid_t *tru_item_p; + rsbac_time_t *ttl_p; + int i; + long count; + + rsbac_list_lol_remove(handle, &new_pid); + count = rsbac_list_lol_get_all_subdesc_ttl(handle, + &old_pid, + (void **) &tru_item_p, + &ttl_p); + if (count > 0) { + for (i = 0; i < count; i++) { + rsbac_list_lol_subadd_ttl(handle, + ttl_p[i], + &new_pid, + &tru_item_p[i], NULL); + } + rsbac_kfree(tru_item_p); + rsbac_kfree(ttl_p); + } else { + if (count < 0) + return count; + } + return 0; +} + +static int copy_pp_tru_set_item(rsbac_pid_t old_pid, rsbac_pid_t new_pid) +{ + return copy_pp_tru_set_item_handle(process_handle, old_pid, + new_pid); +} /* end of copy_pp_tru_set_item() */ + +/************************************************* */ +/* proc functions */ +/************************************************* */ + +#if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS) +static int +mac_devices_proc_show(struct seq_file *m, void *v) +{ + struct rsbac_mac_device_list_item_t *device_p; + int srcu_idx; + + if (!rsbac_is_initialized()) + return -ENOSYS; + + seq_printf(m, "%u RSBAC MAC Devices\n-------------------\n", + device_list_head.count); + + /* wait for read access to device_list_head */ + srcu_idx = srcu_read_lock(&device_list_srcu); + /* OK, go on */ + for (device_p = srcu_dereference(device_list_head.head, &device_list_srcu); device_p; + device_p = srcu_dereference(device_p->next, &device_list_srcu)) { + seq_printf(m, + "%02u:%02u with mount_count = %u\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + device_p->mount_count); + } + + /* free access to device_list_head */ + srcu_read_unlock(&device_list_srcu, srcu_idx); + + return 0; +} + +static int mac_devices_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, mac_devices_proc_show, NULL); +} + +static const struct file_operations mac_devices_proc_fops = { + .owner = THIS_MODULE, + .open = mac_devices_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *mac_devices; + +static int +stats_mac_proc_show(struct seq_file *m, void *v) +{ + struct rsbac_mac_device_list_item_t *device_p; + int srcu_idx; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "stats_mac_proc_info(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(aef_mac, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, "MAC Status\n----------\n"); + + seq_printf(m, + "%lu process trusted user set items, sum of %lu members\n", + rsbac_list_lol_count(process_handle), + rsbac_list_lol_all_subcount(process_handle)); + + /* protect device list */ + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = srcu_dereference(device_list_head.head, &device_list_srcu); + while (device_p) { + /* reset counters */ + seq_printf(m, + "device %02u:%02u has %lu file trusted user set items, sum of %lu members\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + rsbac_list_lol_count(device_p->handle), + rsbac_list_lol_all_subcount(device_p->handle)); + device_p = srcu_dereference(device_p->next, &device_list_srcu); + } + /* unprotect device list */ + srcu_read_unlock(&device_list_srcu, srcu_idx); + + return 0; +} + +static int stats_mac_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, stats_mac_proc_show, NULL); +} + +static const struct file_operations stats_mac_proc_fops = { + .owner = THIS_MODULE, + .open = stats_mac_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *stats_mac; + +static int +mac_trulist_proc_show(struct seq_file *m, void *v) +{ + u_int count = 0; + u_int member_count = 0; + u_long all_member_count; + int i, j; + struct rsbac_mac_device_list_item_t *device_p; + rsbac_pid_t *p_list; + rsbac_old_inode_nr_t *f_list; + rsbac_uid_t *tru_list; + int srcu_idx; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "mac_trulist_proc_info(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(aef_mac, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, + "MAC Trusted User Lists\n---------------------\n"); + + /* protect process cap set list */ + seq_printf(m, + "Process trusted user sets:\nset-id count members"); + + all_member_count = 0; + count = rsbac_list_lol_get_all_desc(process_handle, + (void **) &p_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc(process_handle, + &p_list[i], + (void **) + &tru_list); + seq_printf(m, "\n %u\t%u\t", pid_vnr(p_list[i]), + member_count); + if (member_count > 0) { + for (j = 0; j < member_count; j++) { + if (RSBAC_UID_SET(tru_list[j])) + seq_printf(m, "%u/%u ", + RSBAC_UID_SET(tru_list[j]), + RSBAC_UID_NUM(tru_list[j])); + else + seq_printf(m, "%u ", + RSBAC_UID_NUM(tru_list[j])); + } + rsbac_kfree(tru_list); + all_member_count += member_count; + } + } + rsbac_kfree(p_list); + } + seq_printf(m, + "\n%u process trusted user set items, sum of %lu members\n", + count, all_member_count); + + seq_printf(m, + "\nFile trusted user sets:\nset-id count members"); + + /* protect device list */ + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = srcu_dereference(device_list_head.head, &device_list_srcu); + while (device_p) { + /* reset counters */ + all_member_count = 0; + count = rsbac_list_lol_get_all_desc(device_p->handle, + (void **) &f_list); + if (count > 0) { + for (i = 0; i < count; i++) { + member_count = + rsbac_list_lol_get_all_subdesc + (device_p->handle, + &f_list[i], + (void **) &tru_list); + seq_printf(m, + "\n %u\t%u\t", + f_list[i], + member_count); + if (member_count > 0) { + for (j = 0; + j < member_count; + j++) { + if (RSBAC_UID_SET(tru_list[j])) + seq_printf(m, + "%u/%u ", + RSBAC_UID_SET(tru_list[j]), + RSBAC_UID_NUM(tru_list[j])); + else + seq_printf(m, + "%u ", + RSBAC_UID_NUM(tru_list[j])); + } + rsbac_kfree(tru_list); + all_member_count += + member_count; + } + } + rsbac_kfree(f_list); + } + seq_printf(m, + "\ndevice %02u:%02u has %u file trusted user set items, sum of %lu members\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), count, + all_member_count); + device_p = srcu_dereference(device_p->next, &device_list_srcu); + } + /* unprotect device list */ + srcu_read_unlock(&device_list_srcu, srcu_idx); + + return 0; +} + +static int mac_trulist_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, mac_trulist_proc_show, NULL); +} + +static const struct file_operations mac_trulist_proc_fops = { + .owner = THIS_MODULE, + .open = mac_trulist_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *mac_trulist; + +#endif /* CONFIG_PROC_FS && CONFIG_RSBAC_PROC */ + +/************************************************* */ +/* Init functions */ +/************************************************* */ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac/error.h. */ + +/************************************************************************** */ +/* Initialization of all MAC data structures. After this call, all MAC */ +/* data is kept in memory for performance reasons, but is written to disk */ +/* on every change. */ + +/* Because there can be no access to aci data structures before init, */ +/* rsbac_init_mac() will initialize all rw-spinlocks to unlocked. */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_init_mac(void) +#else +int __init rsbac_init_mac(void) +#endif +{ + int err = 0; + struct rsbac_mac_device_list_item_t *device_p = NULL; + struct rsbac_list_lol_info_t lol_info; + + if (rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_init_mac(): RSBAC already initialized\n"); + return -RSBAC_EREINIT; + } + + rsbac_printk(KERN_INFO "rsbac_init_mac(): Initializing RSBAC: MAC subsystem\n"); + + lol_info.version = RSBAC_MAC_P_LIST_VERSION; + lol_info.key = RSBAC_MAC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_pid_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_uid_t); + lol_info.subdata_size = 0; + lol_info.max_age = 0; + err = rsbac_list_lol_register(RSBAC_LIST_VERSION, + &process_handle, + &lol_info, + RSBAC_LIST_DEF_DATA, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + RSBAC_MAC_P_LIST_NAME, + RSBAC_AUTO_DEV); + if (err) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_mac(): Registering MAC process trusted user list failed with error %s\n", + get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } + + /* Init FD lists */ + spin_lock_init(&device_list_head.lock); + init_srcu_struct(&device_list_srcu); + lockdep_set_class(&device_list_head.lock, &device_list_lock_class); + device_list_head.head = NULL; + device_list_head.tail = NULL; + device_list_head.curr = NULL; + device_list_head.count = 0; + + /* read all data */ + rsbac_pr_debug(ds_mac, "rsbac_init_mac(): Registering FD lists\n"); + device_p = create_device_item(rsbac_root_dev); + if (!device_p) { + rsbac_printk(KERN_CRIT + "rsbac_init_mac(): Could not add device!\n"); + return -RSBAC_ECOULDNOTADDDEVICE; + } + if ((err = mac_register_fd_lists(device_p, rsbac_root_dev))) { + char tmp[RSBAC_MAXNAMELEN]; + + rsbac_printk(KERN_WARNING "rsbac_init_mac(): File/Dir trusted user set registration failed for dev %02u:%02u, err %s!\n", + RSBAC_MAJOR(rsbac_root_dev), + RSBAC_MINOR(rsbac_root_dev), + get_error_name(tmp, err)); + } + /* wait for write access to device_list_head */ + spin_lock(&device_list_head.lock); + device_p = add_device_item(device_p); + /* device was added, allow access */ + spin_unlock(&device_list_head.lock); + if (!device_p) { + rsbac_printk(KERN_CRIT + "rsbac_init_mac(): Could not add device!\n"); + return -RSBAC_ECOULDNOTADDDEVICE; + } +#if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS) + mac_devices = proc_create("mac_devices", + S_IFREG | S_IRUGO | S_IWUGO, + proc_rsbac_root_p, &mac_devices_proc_fops); + stats_mac = proc_create("stats_mac", + S_IFREG | S_IRUGO, + proc_rsbac_root_p, &stats_mac_proc_fops); + mac_trulist = proc_create("mac_trusted", + S_IFREG | S_IRUGO, + proc_rsbac_root_p, &mac_trulist_proc_fops); +#endif + + rsbac_pr_debug(aef_mac, "Ready.\n"); + return err; +} + +int rsbac_mount_mac(kdev_t kdev) +{ + int err = 0; + struct rsbac_mac_device_list_item_t *device_p; + struct rsbac_mac_device_list_item_t *new_device_p; + int srcu_idx; + + rsbac_pr_debug(aef_mac, "mounting device %02u:%02u\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(kdev); + /* repeated mount? */ + if (device_p) { + rsbac_printk(KERN_WARNING "rsbac_mount_mac: repeated mount %u of device %02u:%02u\n", + device_p->mount_count, RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev)); + device_p->mount_count++; + srcu_read_unlock(&device_list_srcu, srcu_idx); + return 0; + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + + new_device_p = create_device_item(kdev); + if (!new_device_p) + return -RSBAC_ECOULDNOTADDDEVICE; + + /* register lists */ + if ((err = mac_register_fd_lists(new_device_p, kdev))) { + char tmp[RSBAC_MAXNAMELEN]; + + rsbac_printk(KERN_WARNING "rsbac_mount_mac(): File/Dir ACL registration failed for dev %02u:%02u, err %s!\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev), + get_error_name(tmp, err)); + } + + srcu_idx = srcu_read_lock(&device_list_srcu); + /* make sure to only add, if this device item has not been added in the meantime */ + device_p = lookup_device(kdev); + if (device_p) { + rsbac_printk(KERN_WARNING "rsbac_mount_mac(): mount race for device %02u:%02u detected!\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + device_p->mount_count++; + srcu_read_unlock(&device_list_srcu, srcu_idx); + clear_device_item(new_device_p); + } else { + srcu_read_unlock(&device_list_srcu, srcu_idx); + spin_lock(&device_list_head.lock); + device_p = add_device_item(new_device_p); + spin_unlock(&device_list_head.lock); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_mount_mac: adding device %02u:%02u failed!\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + clear_device_item(new_device_p); + err = -RSBAC_ECOULDNOTADDDEVICE; + } + } + return err; +} + +/* When umounting a device, its file lists must be removed. */ + +int rsbac_umount_mac(kdev_t kdev) +{ + struct rsbac_mac_device_list_item_t *device_p; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_umount(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(aef_mac, "umounting device %02u:%02u\n", + RSBAC_MAJOR(kdev), RSBAC_MINOR(kdev)); + /* sync of attribute lists was done in rsbac_umount */ + spin_lock(&device_list_head.lock); + /* OK, nobody else is working on it... */ + device_p = lookup_device_locked(kdev); + if (device_p) { + if (device_p->mount_count == 1) { + remove_device_item(device_p); + spin_unlock(&device_list_head.lock); + synchronize_srcu(&device_list_srcu); + clear_device_item(device_p); + } else { + if (device_p->mount_count > 1) { + device_p->mount_count--; + } else { + rsbac_printk(KERN_WARNING "rsbac_mount_mac: device %02u:%02u has mount_count < 1!\n", + RSBAC_MAJOR(kdev), + RSBAC_MINOR(kdev)); + } + spin_unlock(&device_list_head.lock); + } + } else + spin_unlock(&device_list_head.lock); + return 0; +} + +/***************************************************/ +/* We also need some status information... */ + +int rsbac_stats_mac(void) +{ + struct rsbac_mac_device_list_item_t *device_p; + int srcu_idx; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_stats_mac(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + rsbac_pr_debug(aef_mac, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + rsbac_printk(KERN_INFO "MAC Status\n----------\n"); + + rsbac_printk(KERN_INFO "%lu process trusted user set items, sum of %lu members\n", + rsbac_list_lol_count(process_handle), + rsbac_list_lol_all_subcount(process_handle)); + + /* protect device list */ + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = srcu_dereference(device_list_head.head, &device_list_srcu); + while (device_p) { + rsbac_printk(KERN_INFO "device %02u:%02u has %u file trusted user set items, sum of %u members\n", + RSBAC_MAJOR(device_p->id), + RSBAC_MINOR(device_p->id), + rsbac_list_lol_count(device_p->handle), + rsbac_list_lol_all_subcount(device_p->handle)); + device_p = srcu_dereference(device_p->next, &device_list_srcu); + } + srcu_read_unlock(&device_list_srcu, srcu_idx); + return 0; +} + +/************************************************* */ +/* Access functions */ +/************************************************* */ + +/* All these procedures handle the rw-spinlocks to protect the targets during */ +/* access. */ +/* Trying to access a never created or removed set returns an error! */ + +/* rsbac_mac_add_to_truset */ +/* Add a set member to a set sublist. Set behaviour: also returns success, */ +/* if member was already in set! */ + +int rsbac_mac_add_to_p_truset(rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + rsbac_uid_t member, rsbac_time_t ttl) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_mac_add_to_p_truset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_mac_add_to_p_truset(): called from interrupt!\n"); + } + return rsbac_ta_list_lol_subadd_ttl(ta_number, process_handle, ttl, + &pid, &member, NULL); +} + +int rsbac_mac_add_to_f_truset(rsbac_list_ta_number_t ta_number, + rsbac_mac_file_t file, + rsbac_uid_t member, rsbac_time_t ttl) +{ + int err = 0; + struct rsbac_mac_device_list_item_t *device_p; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr = file.inode; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_mac_add_to_f_truset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_mac_add_to_f_truset(): called from interrupt!\n"); + } + + /* protect device list */ + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(file.device); + if (!device_p) { + srcu_read_unlock(&device_list_srcu, srcu_idx); + rsbac_printk(KERN_WARNING "rsbac_mac_add_to_f_truset(): invalid device %02u:%02u!\n", + RSBAC_MAJOR(file.device), + RSBAC_MINOR(file.device)); + return -RSBAC_EINVALIDDEV; + } + + err = rsbac_ta_list_lol_subadd_ttl(ta_number, + device_p->handle, + ttl, &inode_nr, &member, + NULL); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; +} + +/* rsbac_mac_remove_from_truset */ +/* Remove a set member from a sublist. Set behaviour: Returns no error, if */ +/* member is not in list. */ + +int rsbac_mac_remove_from_p_truset(rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, rsbac_uid_t member) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_mac_remove_from_p_truset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_mac_remove_from_p_truset(): called from interrupt!\n"); + } + return rsbac_ta_list_lol_subremove(ta_number, process_handle, &pid, + &member); +} + +int rsbac_mac_remove_from_f_truset(rsbac_list_ta_number_t ta_number, + rsbac_mac_file_t file, + rsbac_uid_t member) +{ + int err = 0; + struct rsbac_mac_device_list_item_t *device_p; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr = file.inode; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_mac_remove_from_f_truset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_mac_remove_from_f_truset(): called from interrupt!\n"); + } + + /* protect device list */ + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_mac_remove_from_f_truset(): invalid device %02u:%02u!\n", + RSBAC_MAJOR(file.device), + RSBAC_MINOR(file.device)); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + err = rsbac_ta_list_lol_subremove(ta_number, + device_p->handle, + &inode_nr, &member); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; +} + +/* rsbac_mac_clear_truset */ +/* Remove all set members from a sublist. Set behaviour: Returns no error, */ +/* if list is empty. */ + +int rsbac_mac_clear_p_truset(rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_mac_clear_p_truset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_mac_clear_p_truset(): called from interrupt!\n"); + } + return rsbac_ta_list_lol_remove(ta_number, process_handle, &pid); +} + +int rsbac_mac_clear_f_truset(rsbac_list_ta_number_t ta_number, + rsbac_mac_file_t file) +{ + int err = 0; + struct rsbac_mac_device_list_item_t *device_p; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr = file.inode; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_mac_clear_f_truset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_mac_clear_f_truset(): called from interrupt!\n"); + } + /* protect device list */ + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_mac_clear_f_truset(): invalid device %02u:%02u!\n", + RSBAC_MAJOR(file.device), + RSBAC_MINOR(file.device)); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + err = rsbac_ta_list_lol_remove(ta_number, + device_p->handle, + &inode_nr); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; +} + +/* rsbac_mac_truset_member */ +/* Return truth value, whether member is in set */ + +rsbac_boolean_t rsbac_mac_p_truset_member(rsbac_pid_t pid, + rsbac_uid_t member) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_mac_p_truset_member(): RSBAC not initialized\n"); + return FALSE; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_mac_p_truset_member(): called from interrupt!\n"); + } + if (rsbac_list_lol_subexist(process_handle, &pid, &member)) + return TRUE; + member = RSBAC_ALL_USERS; + return rsbac_list_lol_subexist(process_handle, &pid, &member); +} + +/* rsbac_mac_remove_truset */ +/* Remove a full set. For cleanup, if object is deleted. */ +/* To empty an existing set use rsbac_mac_clear_truset. */ + +int rsbac_mac_remove_p_trusets(rsbac_pid_t pid) +{ + return rsbac_mac_clear_p_truset(FALSE, pid); +} + +int rsbac_mac_remove_f_trusets(rsbac_mac_file_t file) +{ + return rsbac_mac_clear_f_truset(FALSE, file); +} + +int rsbac_mac_copy_fp_truset(rsbac_mac_file_t file, + rsbac_pid_t p_tru_set_id) +{ + struct rsbac_mac_device_list_item_t *device_p; + int err = 0; + int srcu_idx; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_mac_copy_fp_truset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_mac_copy_fp_truset(): called from interrupt!\n"); + } +/* + rsbac_pr_debug(ds_mac, "Copying file cap set data to process cap set\n"); +*/ + /* protect device list */ + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_mac_copy_fp_truset(): invalid device %02u:%02u!\n", + RSBAC_MAJOR(file.device), + RSBAC_MINOR(file.device)); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + /* call the copy function */ + err = copy_fp_tru_set_item(device_p, file, p_tru_set_id); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return err; +} + +int rsbac_mac_copy_pp_truset(rsbac_pid_t old_p_set_id, + rsbac_pid_t new_p_set_id) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_mac_copy_pp_truset(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_mac_copy_pp_truset(): called from interrupt!\n"); + } +/* + rsbac_pr_debug(ds_mac, "Copying process cap set data to process cap set\n"); +*/ + /* call the copy function */ + return copy_pp_tru_set_item(old_p_set_id, new_p_set_id); +} + +int rsbac_mac_get_f_trulist(rsbac_list_ta_number_t ta_number, + rsbac_mac_file_t file, + rsbac_uid_t ** trulist_p, + rsbac_time_t ** ttllist_p) +{ + struct rsbac_mac_device_list_item_t *device_p; + long count; + int srcu_idx; + rsbac_old_inode_nr_t inode_nr = file.inode; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_mac_get_f_trulist(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_mac_get_f_trulist(): called from interrupt!\n"); + } +/* + rsbac_pr_debug(ds_mac, "Getting file/dir trusted user set list\n"); +*/ + /* protect device list */ + srcu_idx = srcu_read_lock(&device_list_srcu); + device_p = lookup_device(file.device); + if (!device_p) { + rsbac_printk(KERN_WARNING "rsbac_mac_get_f_trulist(): invalid device %02u:%02u!\n", + RSBAC_MAJOR(file.device), + RSBAC_MINOR(file.device)); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return -RSBAC_EINVALIDDEV; + } + count = rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + device_p->handle, + &inode_nr, + (void **) trulist_p, + ttllist_p); + srcu_read_unlock(&device_list_srcu, srcu_idx); + return count; +} + +int rsbac_mac_get_p_trulist(rsbac_list_ta_number_t ta_number, + rsbac_pid_t pid, + rsbac_uid_t ** trulist_p, + rsbac_time_t ** ttllist_p) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_mac_get_p_trulist(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_mac_get_p_trulist(): called from interrupt!\n"); + } +/* + rsbac_pr_debug(ds_mac, "Getting process trusted user set list\n"); +*/ + return rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + process_handle, + &pid, + (void **) trulist_p, + ttllist_p); +} diff --git a/rsbac/data_structures/rc_data_structures.c b/rsbac/data_structures/rc_data_structures.c new file mode 100644 index 000000000000..e98cdd5ca3c8 --- /dev/null +++ b/rsbac/data_structures/rc_data_structures.c @@ -0,0 +1,4437 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of RC data structures */ +/* Author and (C) 1999-2016: Amon Ott */ +/* */ +/* Last modified: 07/Jan/2016 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************** */ +/* Global Variables */ +/************************************************************************** */ + +/* The following global variables are needed for access to RC data. */ + +static rsbac_list_handle_t role_handle = NULL; +static rsbac_list_handle_t role_rc_handle = NULL; +static rsbac_list_handle_t role_adr_handle = NULL; +static rsbac_list_handle_t role_asr_handle = NULL; +static rsbac_list_handle_t role_dfdc_handle = NULL; +static rsbac_list_handle_t role_tcfd_handle = NULL; +static rsbac_list_handle_t role_tcdv_handle = NULL; +static rsbac_list_handle_t role_tcus_handle = NULL; +static rsbac_list_handle_t role_tcpr_handle = NULL; +static rsbac_list_handle_t role_tcip_handle = NULL; +static rsbac_list_handle_t role_tcsc_handle = NULL; +static rsbac_list_handle_t role_tcgr_handle = NULL; +static rsbac_list_handle_t role_tcnd_handle = NULL; +static rsbac_list_handle_t role_tcnt_handle = NULL; +static rsbac_list_handle_t role_tcno_handle = NULL; + +static rsbac_list_handle_t type_fd_handle = NULL; +static rsbac_list_handle_t type_dev_handle = NULL; +static rsbac_list_handle_t type_ipc_handle = NULL; +static rsbac_list_handle_t type_user_handle = NULL; +static rsbac_list_handle_t type_process_handle = NULL; +static rsbac_list_handle_t type_group_handle = NULL; +static rsbac_list_handle_t type_netdev_handle = NULL; +static rsbac_list_handle_t type_nettemp_handle = NULL; +static rsbac_list_handle_t type_netobj_handle = NULL; + +/**************************************************/ +/* Declarations of external functions */ +/**************************************************/ + +/**************************************************/ +/* Declarations of internal functions */ +/**************************************************/ + +/* As some function use later defined functions, we declare those here. */ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +/* nr_hashes is always 2^n, no matter what the macros say */ +/* We ignore the lowest bit */ +static u_int nr_role_hash_bits = RSBAC_RC_NR_ROLE_LIST_HASH_BITS; +static u_int nr_type_hash_bits = RSBAC_RC_NR_TYPE_LIST_HASH_BITS; + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int role_conv( +#else +static int __init role_conv( +#endif + void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + struct rsbac_rc_role_entry_t *new = new_data; + struct rsbac_rc_old_role_entry_t *old = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_rc_role_id_t)); + new->admin_type = old->admin_type; + memcpy(new->name, old->name, RSBAC_RC_NAME_LEN); + new->def_fd_create_type = old->def_fd_create_type; + new->def_user_create_type = old->def_user_create_type; + new->def_process_create_type = old->def_process_create_type; + new->def_process_chown_type = old->def_process_chown_type; + new->def_process_execute_type = old->def_process_execute_type; + new->def_ipc_create_type = old->def_ipc_create_type; + new->def_group_create_type = RSBAC_RC_GENERAL_TYPE; + new->def_unixsock_create_type = RC_type_use_fd; + new->boot_role = old->boot_role; + new->req_reauth = old->req_reauth; + return 0; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int old_role_conv( +#else +static int __init old_role_conv( +#endif + void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + struct rsbac_rc_role_entry_t *new = new_data; + struct rsbac_rc_old_role_entry_t *old = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_rc_role_id_t)); + new->admin_type = old->admin_type; + memcpy(new->name, old->name, RSBAC_RC_NAME_LEN); + new->def_fd_create_type = old->def_fd_create_type; + new->def_user_create_type = old->def_user_create_type; + new->def_process_create_type = old->def_process_create_type; + new->def_process_chown_type = old->def_process_chown_type; + new->def_process_execute_type = old->def_process_execute_type; + new->def_ipc_create_type = old->def_ipc_create_type; + new->def_group_create_type = RSBAC_RC_GENERAL_TYPE; + new->def_unixsock_create_type = RC_type_use_fd; + new->boot_role = old->boot_role; + new->req_reauth = FALSE; + return 0; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int old_old_role_conv( +#else +static int __init old_old_role_conv( +#endif + void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + struct rsbac_rc_role_entry_t *new = new_data; + struct rsbac_rc_old_role_entry_t *old = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_rc_role_id_t)); + new->admin_type = old->admin_type; + memcpy(new->name, old->name, RSBAC_RC_NAME_LEN); + new->def_fd_create_type = old->def_fd_create_type; + new->def_user_create_type = old->def_user_create_type; + new->def_process_create_type = old->def_process_create_type; + new->def_process_chown_type = old->def_process_chown_type; + new->def_process_execute_type = old->def_process_execute_type; + new->def_ipc_create_type = old->def_ipc_create_type; + new->def_group_create_type = RSBAC_RC_GENERAL_TYPE; + new->def_unixsock_create_type = RC_type_use_fd; + new->boot_role = old->boot_role; + new->req_reauth = FALSE; + return 0; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int old_old_old_role_conv( +#else +static int __init old_old_old_role_conv( +#endif + void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + struct rsbac_rc_role_entry_t *new = new_data; + struct rsbac_rc_old_role_entry_t *old = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_rc_role_id_t)); + new->admin_type = old->admin_type; + memcpy(new->name, old->name, RSBAC_RC_NAME_LEN); + new->def_fd_create_type = old->def_fd_create_type; + new->def_user_create_type = RSBAC_RC_GENERAL_TYPE; + new->def_process_create_type = old->def_process_create_type; + new->def_process_chown_type = old->def_process_chown_type; + new->def_process_execute_type = old->def_process_execute_type; + new->def_ipc_create_type = old->def_ipc_create_type; + new->def_group_create_type = RSBAC_RC_GENERAL_TYPE; + new->def_unixsock_create_type = RC_type_use_fd; + new->boot_role = FALSE; + new->req_reauth = FALSE; + return 0; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static rsbac_list_conv_function_t *role_get_conv(rsbac_version_t + old_version) +#else +static rsbac_list_conv_function_t *__init role_get_conv(rsbac_version_t + old_version) +#endif +{ + switch (old_version) { + case RSBAC_RC_ROLE_OLD_LIST_VERSION: + return role_conv; + case RSBAC_RC_ROLE_OLD_OLD_LIST_VERSION: + return old_role_conv; + case RSBAC_RC_ROLE_OLD_OLD_OLD_LIST_VERSION: + return old_old_role_conv; + case RSBAC_RC_ROLE_OLD_OLD_OLD_OLD_LIST_VERSION: + return old_old_old_role_conv; + default: + return NULL; + } +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int tc_subconv( +#else +static int __init tc_subconv( +#endif + void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + rsbac_rc_rights_vector_t *new = new_data; + rsbac_rc_rights_vector_t *old = old_data; + + memcpy(new_desc, old_desc, sizeof(rsbac_rc_type_id_t)); + *new = (*old & RSBAC_ALL_REQUEST_VECTOR) + | ((*old & ~(RSBAC_ALL_REQUEST_VECTOR)) << + (RSBAC_RC_SPECIAL_RIGHT_BASE - + RSBAC_RC_OLD_SPECIAL_RIGHT_BASE)); + return 0; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static rsbac_list_conv_function_t *tcfd_get_subconv(rsbac_version_t + old_version) +#else +static rsbac_list_conv_function_t *__init tcfd_get_subconv(rsbac_version_t + old_version) +#endif +{ + switch (old_version) { + case RSBAC_RC_ROLE_TCFD_OLD_LIST_VERSION: + return tc_subconv; + default: + return NULL; + } +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int tc_conv( +#else +static int __init tc_conv( +#endif + void *old_desc, + void *old_data, + void *new_desc, void *new_data) +{ + memcpy(new_desc, old_desc, sizeof(rsbac_rc_role_id_t)); + return 0; +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static rsbac_list_conv_function_t *tcfd_get_conv(rsbac_version_t + old_version) +#else +static rsbac_list_conv_function_t *__init tcfd_get_conv(rsbac_version_t + old_version) +#endif +{ + switch (old_version) { + case RSBAC_RC_ROLE_TCFD_OLD_LIST_VERSION: + return tc_conv; + default: + return NULL; + } +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static int rsbac_rc_role_compare_data(void *data1, void *data2) +#else +static int __init rsbac_rc_role_compare_data(void *data1, void *data2) +#endif +{ + struct rsbac_rc_role_entry_t *role = data1; + + if (!data1) + return 1; + if (role->boot_role) + return 0; + else + return 1; +} + +/************************************************* */ +/* proc functions */ +/************************************************* */ + +#if defined(CONFIG_RSBAC_PROC) +static int +stats_rc_proc_show(struct seq_file *m, void *v) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "stats_rc_proc_info(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + rsbac_pr_debug(aef_rc, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, "RC Status\n---------\n"); + seq_printf(m, + "Role entry size is %Zd, %lu entries used\n", + sizeof(struct rsbac_rc_role_entry_t), + rsbac_list_count(role_handle)); + seq_printf(m, + "Used type entries: fd: %lu, dev: %lu, ipc: %lu, user: %lu, process: %lu, group: %lu, netdev: %lu, nettemp: %lu, netobj: %lu\n", + rsbac_list_count(type_fd_handle), + rsbac_list_count(type_dev_handle), + rsbac_list_count(type_ipc_handle), + rsbac_list_count(type_user_handle), + rsbac_list_count(type_process_handle), + rsbac_list_count(type_group_handle), + rsbac_list_count(type_netdev_handle), + rsbac_list_count(type_nettemp_handle), + rsbac_list_count(type_netobj_handle)); + return 0; +} + +static int stats_rc_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, stats_rc_proc_show, NULL); +} + +static const struct file_operations stats_rc_proc_fops = { + .owner = THIS_MODULE, + .open = stats_rc_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *stats_rc; + +#endif /* CONFIG_PROC_FS && CONFIG_RSBAC_PROC */ + +/************************************************* */ +/* Init functions */ +/************************************************* */ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac/error.h. */ + +/************************************************************************** */ +/* Initialization of all RC data structures. After this call, all RC data */ +/* is kept in memory for performance reasons, but is written to disk on */ +/* every change. */ + +/* There can be no access to aci data structures before init. */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +static void registration_error(int err, char *listname) +#else +static void __init registration_error(int err, char *listname) +#endif +{ + if (err) { + char *tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_rc(): Registering RC %s list failed with error %s\n", + listname, get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static void create_def_roles(void) +#else +static void __init create_def_roles(void) +#endif +{ + rsbac_rc_role_id_t role; + rsbac_rc_type_id_t type; + rsbac_rc_rights_vector_t rights; + struct rsbac_rc_role_entry_t gen_entry = + RSBAC_RC_GENERAL_ROLE_ENTRY; + struct rsbac_rc_role_entry_t ra_entry = + RSBAC_RC_ROLE_ADMIN_ROLE_ENTRY; + struct rsbac_rc_role_entry_t sa_entry = + RSBAC_RC_SYSTEM_ADMIN_ROLE_ENTRY; + + rsbac_printk(KERN_WARNING "rsbac_init_rc(): no RC roles read, generating default role entries!\n"); + + role = RSBAC_RC_GENERAL_ROLE; + if (!rsbac_list_add(role_handle, &role, &gen_entry)) { + if (!rsbac_list_lol_add + (role_tcfd_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_EXECUTE_REQUEST_VECTOR) + & RSBAC_FD_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcfd_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcdv_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_READ_WRITE_REQUEST_VECTOR & + RSBAC_DEV_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcdv_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcus_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_REQUEST_VECTOR(R_SEARCH) | + RSBAC_REQUEST_VECTOR(R_CHANGE_OWNER) | + RSBAC_REQUEST_VECTOR + (R_GET_STATUS_DATA); + rsbac_list_lol_subadd(role_tcus_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcpr_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_READ_WRITE_REQUEST_VECTOR & + RSBAC_PROCESS_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcpr_handle, + &role, &type, + &rights); + type = CONFIG_RSBAC_RC_KERNEL_PROCESS_TYPE; + rights = + RSBAC_READ_REQUEST_VECTOR & + RSBAC_PROCESS_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcpr_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcip_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_READ_WRITE_REQUEST_VECTOR & + RSBAC_IPC_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcip_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcgr_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_REQUEST_VECTOR(R_SEARCH) | + RSBAC_REQUEST_VECTOR + (R_GET_STATUS_DATA); + rsbac_list_lol_subadd(role_tcgr_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcnd_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_READ_WRITE_REQUEST_VECTOR & + RSBAC_NETDEV_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcnd_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcno_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_READ_WRITE_REQUEST_VECTOR & + RSBAC_NETOBJ_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcno_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcsc_handle, &role, NULL)) { +#ifdef CONFIG_RSBAC_USER_MOD_IOPERM + type = ST_ioports; + rights = + RSBAC_RC_RIGHTS_VECTOR + (R_MODIFY_PERMISSIONS_DATA); + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); +#endif + type = ST_rlimit; + rights = + RSBAC_RC_RIGHTS_VECTOR + (R_GET_STATUS_DATA) + | + RSBAC_RC_RIGHTS_VECTOR + (R_MODIFY_SYSTEM_DATA); + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + type = ST_other; + rights = + RSBAC_RC_RIGHTS_VECTOR(R_MAP_EXEC); + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + type = ST_network; + rights = + RSBAC_RC_RIGHTS_VECTOR + (R_GET_STATUS_DATA); + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + } + } + role = RSBAC_RC_ROLE_ADMIN_ROLE; + if (!rsbac_list_add(role_handle, &role, &ra_entry)) { + if (!rsbac_list_lol_add + (role_tcfd_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = ((RSBAC_READ_WRITE_REQUEST_VECTOR + | RSBAC_EXECUTE_REQUEST_VECTOR + | RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_FD_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcfd_handle, + &role, &type, + &rights); + type = RSBAC_RC_SEC_TYPE; + rsbac_list_lol_subadd(role_tcfd_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rights = + (RSBAC_READ_REQUEST_VECTOR & + RSBAC_FD_REQUEST_VECTOR) + | RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcfd_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcdv_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_DEV_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcdv_handle, + &role, &type, + &rights); + type = RSBAC_RC_SEC_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_DEV_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcdv_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcus_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR | + RSBAC_REQUEST_VECTOR(R_AUTHENTICATE)) + & RSBAC_USER_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcus_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR | + RSBAC_REQUEST_VECTOR(R_AUTHENTICATE)) + & RSBAC_USER_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcus_handle, + &role, &type, + &rights); + type = RSBAC_RC_SEC_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR | + RSBAC_REQUEST_VECTOR(R_AUTHENTICATE)) + & RSBAC_USER_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcus_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcpr_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_PROCESS_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcpr_handle, + &role, &type, + &rights); + type = RSBAC_RC_SEC_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_PROCESS_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcpr_handle, + &role, &type, + &rights); + type = CONFIG_RSBAC_RC_KERNEL_PROCESS_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_PROCESS_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcpr_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcip_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_IPC_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcip_handle, + &role, &type, + &rights); + type = RSBAC_RC_SEC_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_IPC_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcip_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcgr_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_GROUP_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcgr_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcnd_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + ((RSBAC_REQUEST_VECTOR + (R_GET_STATUS_DATA) | + RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_NETDEV_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcnd_handle, + &role, &type, + &rights); + type = RSBAC_RC_SEC_TYPE; + rsbac_list_lol_subadd(role_tcnd_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rsbac_list_lol_subadd(role_tcnd_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcnt_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_NETTEMP_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcnt_handle, + &role, &type, + &rights); + type = RSBAC_RC_SEC_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_NETTEMP_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcnt_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcno_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + ((RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SECURITY_REQUEST_VECTOR) + & RSBAC_NETOBJ_REQUEST_VECTOR) | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcno_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcsc_handle, &role, NULL)) { +#ifdef CONFIG_RSBAC_USER_MOD_IOPERM + type = ST_ioports; + rights = + RSBAC_RC_RIGHTS_VECTOR + (R_MODIFY_PERMISSIONS_DATA) + | RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); +#endif + type = ST_rlimit; + rights = + RSBAC_SCD_REQUEST_VECTOR | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + type = ST_rsbac; + rights = + RSBAC_SCD_REQUEST_VECTOR | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + type = ST_rsbac_log; + rights = + RSBAC_SCD_REQUEST_VECTOR | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + type = ST_other; + rights = RSBAC_RC_RIGHTS_VECTOR(R_MAP_EXEC) + | + RSBAC_RC_RIGHTS_VECTOR + (R_MODIFY_PERMISSIONS_DATA) + | RSBAC_RC_RIGHTS_VECTOR(R_SWITCH_LOG) + | + RSBAC_RC_RIGHTS_VECTOR(R_SWITCH_MODULE) + | RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + type = ST_network; + rights = + RSBAC_RC_RIGHTS_VECTOR + (R_GET_STATUS_DATA) + | RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + type = ST_firewall; + rights = + RSBAC_RC_RIGHTS_VECTOR + (R_GET_STATUS_DATA) + | RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + type = RST_auth_administration; + rights = + RSBAC_SCD_REQUEST_VECTOR | + RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + type = ST_sysfs; + rights = + RSBAC_RC_RIGHTS_VECTOR + (R_GET_STATUS_DATA) + | RSBAC_RC_SPECIAL_RIGHTS_VECTOR; + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + } + } + role = RSBAC_RC_SYSTEM_ADMIN_ROLE; + if (!rsbac_list_add(role_handle, &role, &sa_entry)) { + if (!rsbac_list_lol_add + (role_tcfd_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = (RSBAC_READ_WRITE_REQUEST_VECTOR + | RSBAC_EXECUTE_REQUEST_VECTOR + | RSBAC_SYSTEM_REQUEST_VECTOR) + & RSBAC_FD_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcfd_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rsbac_list_lol_subadd(role_tcfd_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcdv_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_DEV_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcdv_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_DEV_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcdv_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcus_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_REQUEST_VECTOR(R_CHANGE_OWNER) | + RSBAC_REQUEST_VECTOR(R_SEARCH) | + RSBAC_REQUEST_VECTOR(R_GET_STATUS_DATA) | + RSBAC_REQUEST_VECTOR(R_AUTHENTICATE); + rsbac_list_lol_subadd(role_tcus_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rights = + RSBAC_REQUEST_VECTOR(R_SEARCH) | + RSBAC_REQUEST_VECTOR(R_GET_STATUS_DATA) | + RSBAC_REQUEST_VECTOR(R_AUTHENTICATE); + rsbac_list_lol_subadd(role_tcus_handle, + &role, &type, + &rights); + type = RSBAC_RC_SEC_TYPE; + rights = + RSBAC_REQUEST_VECTOR(R_SEARCH) | + RSBAC_REQUEST_VECTOR(R_AUTHENTICATE); + rsbac_list_lol_subadd(role_tcus_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcpr_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_REQUEST_VECTOR(R_CONNECT) | + RSBAC_REQUEST_VECTOR(R_SEND) | + RSBAC_REQUEST_VECTOR(R_RECEIVE) | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_PROCESS_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcpr_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_PROCESS_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcpr_handle, + &role, &type, + &rights); + type = CONFIG_RSBAC_RC_KERNEL_PROCESS_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_PROCESS_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcpr_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcip_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_IPC_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcip_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_IPC_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcip_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcgr_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_REQUEST_VECTOR(R_SEARCH) | + RSBAC_REQUEST_VECTOR(R_GET_STATUS_DATA) | + RSBAC_REQUEST_VECTOR(R_READ); + rsbac_list_lol_subadd(role_tcgr_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcnd_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_NETDEV_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcnd_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcnt_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_REQUEST_VECTOR) & + RSBAC_NETTEMP_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcnt_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcno_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_NETOBJ_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcno_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcsc_handle, &role, NULL)) { + rights = + RSBAC_SCD_REQUEST_VECTOR & + (RSBAC_SYSTEM_REQUEST_VECTOR | + RSBAC_READ_WRITE_REQUEST_VECTOR); + for (type = ST_time_strucs; + type <= ST_rsbac; type++) { + rsbac_list_lol_subadd + (role_tcsc_handle, &role, + &type, &rights); + } + for (type = ST_network; type < ST_none; + type++) { + rsbac_list_lol_subadd + (role_tcsc_handle, &role, + &type, &rights); + } + type = ST_other; + rights = + RSBAC_RC_RIGHTS_VECTOR(R_ADD_TO_KERNEL) + | RSBAC_RC_RIGHTS_VECTOR(R_MAP_EXEC) + | + RSBAC_RC_RIGHTS_VECTOR + (R_MODIFY_SYSTEM_DATA) + | RSBAC_RC_RIGHTS_VECTOR(R_MOUNT) + | + RSBAC_RC_RIGHTS_VECTOR + (R_REMOVE_FROM_KERNEL) + | RSBAC_RC_RIGHTS_VECTOR(R_UMOUNT) + | RSBAC_RC_RIGHTS_VECTOR(R_SHUTDOWN); + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + } + } +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +static void create_def_roles2(void) +#else +static void __init create_def_roles2(void) +#endif +{ + rsbac_rc_role_id_t role; + rsbac_rc_type_id_t type; + rsbac_rc_rights_vector_t rights; + struct rsbac_rc_role_entry_t au_entry = + RSBAC_RC_AUDITOR_ROLE_ENTRY; + struct rsbac_rc_role_entry_t bo_entry = + RSBAC_RC_BOOT_ROLE_ENTRY; + + rsbac_printk(KERN_WARNING "rsbac_init_rc(): no RC roles read, generating default role entries!\n"); + + role = RSBAC_RC_AUDITOR_ROLE; + if (!rsbac_list_add(role_handle, &role, &au_entry)) { + if (!rsbac_list_lol_add + (role_tcfd_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_EXECUTE_REQUEST_VECTOR) + & RSBAC_FD_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcfd_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcdv_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_READ_WRITE_REQUEST_VECTOR & + RSBAC_DEV_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcdv_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcus_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_REQUEST_VECTOR(R_CHANGE_OWNER) | + RSBAC_REQUEST_VECTOR(R_SEARCH) | + RSBAC_REQUEST_VECTOR + (R_GET_STATUS_DATA); + rsbac_list_lol_subadd(role_tcus_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcgr_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_REQUEST_VECTOR(R_SEARCH) | + RSBAC_REQUEST_VECTOR + (R_GET_STATUS_DATA); + rsbac_list_lol_subadd(role_tcgr_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcpr_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_READ_WRITE_REQUEST_VECTOR & + RSBAC_PROCESS_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcpr_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcip_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_READ_WRITE_REQUEST_VECTOR & + RSBAC_IPC_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcip_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcnd_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_READ_WRITE_REQUEST_VECTOR & + RSBAC_NETDEV_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcnd_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcno_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + RSBAC_READ_WRITE_REQUEST_VECTOR & + RSBAC_NETOBJ_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcno_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcsc_handle, &role, NULL)) { +#ifdef CONFIG_RSBAC_USER_MOD_IOPERM + type = ST_ioports; + rights = + RSBAC_RC_RIGHTS_VECTOR + (R_MODIFY_PERMISSIONS_DATA); + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); +#endif + type = ST_rlimit; + rights = + RSBAC_RC_RIGHTS_VECTOR + (R_GET_STATUS_DATA) + | + RSBAC_RC_RIGHTS_VECTOR + (R_MODIFY_SYSTEM_DATA); + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + type = ST_rsbac_log; + rights = + RSBAC_RC_RIGHTS_VECTOR + (R_GET_STATUS_DATA) + | + RSBAC_RC_RIGHTS_VECTOR + (R_MODIFY_SYSTEM_DATA); + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + type = ST_other; + rights = + RSBAC_RC_RIGHTS_VECTOR(R_MAP_EXEC); + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + type = ST_network; + rights = + RSBAC_RC_RIGHTS_VECTOR + (R_GET_STATUS_DATA); + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + } + } + role = RSBAC_RC_BOOT_ROLE; + if (!rsbac_list_add(role_handle, &role, &bo_entry)) { + if (!rsbac_list_lol_add + (role_tcfd_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = (RSBAC_READ_WRITE_REQUEST_VECTOR + | RSBAC_EXECUTE_REQUEST_VECTOR + | RSBAC_SYSTEM_REQUEST_VECTOR) + & RSBAC_FD_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcfd_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rsbac_list_lol_subadd(role_tcfd_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcdv_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_DEV_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcdv_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_DEV_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcdv_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcus_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_REQUEST_VECTOR | + RSBAC_REQUEST_VECTOR(R_CHANGE_OWNER) | + RSBAC_SYSTEM_REQUEST_VECTOR | + RSBAC_REQUEST_VECTOR(R_AUTHENTICATE)) & + RSBAC_USER_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcus_handle, + &role, &type, + &rights); + type = RSBAC_RC_SEC_TYPE; + rights = + RSBAC_REQUEST_VECTOR(R_SEARCH) | + RSBAC_REQUEST_VECTOR(R_CHANGE_OWNER) | + RSBAC_REQUEST_VECTOR(R_AUTHENTICATE); + rsbac_list_lol_subadd(role_tcus_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rights = + (RSBAC_READ_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_USER_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcus_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcpr_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_PROCESS_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcpr_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_PROCESS_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcpr_handle, + &role, &type, + &rights); + type = CONFIG_RSBAC_RC_KERNEL_PROCESS_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_PROCESS_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcpr_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcip_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_IPC_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcip_handle, + &role, &type, + &rights); + type = RSBAC_RC_SYS_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_IPC_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcip_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcnd_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_NETDEV_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcnd_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcnt_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_REQUEST_VECTOR) & + RSBAC_NETTEMP_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcnt_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcno_handle, &role, NULL)) { + type = RSBAC_RC_GENERAL_TYPE; + rights = + (RSBAC_READ_WRITE_REQUEST_VECTOR | + RSBAC_SYSTEM_REQUEST_VECTOR) & + RSBAC_NETOBJ_REQUEST_VECTOR; + rsbac_list_lol_subadd(role_tcno_handle, + &role, &type, + &rights); + } + if (!rsbac_list_lol_add + (role_tcsc_handle, &role, NULL)) { + rights = + RSBAC_SCD_REQUEST_VECTOR & + (RSBAC_SYSTEM_REQUEST_VECTOR | + RSBAC_READ_WRITE_REQUEST_VECTOR); + for (type = ST_time_strucs; + type <= ST_rsbac; type++) { + rsbac_list_lol_subadd + (role_tcsc_handle, &role, + &type, &rights); + } + for (type = ST_network; type < ST_none; + type++) { + rsbac_list_lol_subadd + (role_tcsc_handle, &role, + &type, &rights); + } + type = ST_other; + rights = + RSBAC_RC_RIGHTS_VECTOR(R_ADD_TO_KERNEL) + | RSBAC_RC_RIGHTS_VECTOR(R_MAP_EXEC) + | + RSBAC_RC_RIGHTS_VECTOR + (R_MODIFY_SYSTEM_DATA) + | RSBAC_RC_RIGHTS_VECTOR(R_MOUNT) + | + RSBAC_RC_RIGHTS_VECTOR + (R_REMOVE_FROM_KERNEL) + | RSBAC_RC_RIGHTS_VECTOR(R_UMOUNT) + | RSBAC_RC_RIGHTS_VECTOR(R_SHUTDOWN); + rsbac_list_lol_subadd(role_tcsc_handle, + &role, &type, + &rights); + } + } +} + +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_init_rc(void) +#else +int __init rsbac_init_rc(void) +#endif +{ + int err = 0; + struct rsbac_list_lol_info_t lol_info; + struct rsbac_list_info_t list_info; + rsbac_rc_rights_vector_t def_tc = RSBAC_RC_DEFAULT_RIGHTS_VECTOR; + + if (rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_init_rc(): RSBAC already initialized\n"); + return -RSBAC_EREINIT; + } + + /* init data structures */ + rsbac_printk(KERN_INFO "rsbac_init_rc(): Initializing RSBAC: RC subsystem\n"); + rsbac_pr_debug(stack, "free stack: %lu\n", rsbac_stack_free_space()); + + list_info.version = RSBAC_RC_ROLE_LIST_VERSION; + list_info.key = RSBAC_RC_LIST_KEY; + list_info.desc_size = sizeof(rsbac_rc_role_id_t); + list_info.data_size = sizeof(struct rsbac_rc_role_entry_t); + list_info.max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &role_handle, &list_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, role_get_conv, + NULL, RSBAC_RC_ROLE_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "role"); + } + + lol_info.version = RSBAC_RC_ROLE_RC_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_role_id_t); + lol_info.subdata_size = 0; + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_rc_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, NULL, NULL, + NULL, NULL, + RSBAC_RC_ROLE_RC_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "role compatibilities"); + } + lol_info.version = RSBAC_RC_ROLE_ADR_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_role_id_t); + lol_info.subdata_size = 0; + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_adr_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, NULL, NULL, + NULL, NULL, + RSBAC_RC_ROLE_ADR_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "admin roles"); + } + lol_info.version = RSBAC_RC_ROLE_ASR_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_role_id_t); + lol_info.subdata_size = 0; + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_asr_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, NULL, NULL, + NULL, NULL, + RSBAC_RC_ROLE_ASR_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "assign roles"); + } + lol_info.version = RSBAC_RC_ROLE_DFDC_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t); + lol_info.subdata_size = sizeof(rsbac_rc_type_id_t); + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_dfdc_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, NULL, NULL, + NULL, NULL, + RSBAC_RC_ROLE_DFDC_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "Role default FD create types"); + } + lol_info.version = RSBAC_RC_ROLE_TCFD_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t); + lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t); + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_tcfd_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_DEF_SUBDATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + tcfd_get_conv, tcfd_get_subconv, + NULL, &def_tc, + RSBAC_RC_ROLE_TCFD_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "Role FD type compatibilities"); + } + lol_info.version = RSBAC_RC_ROLE_TCDV_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t); + lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t); + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_tcdv_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_DEF_SUBDATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + tcfd_get_conv, tcfd_get_subconv, + NULL, &def_tc, + RSBAC_RC_ROLE_TCDV_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "Role DEV type compatibilities"); + } + lol_info.version = RSBAC_RC_ROLE_TCUS_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t); + lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t); + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_tcus_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_DEF_SUBDATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + tcfd_get_conv, tcfd_get_subconv, + NULL, &def_tc, + RSBAC_RC_ROLE_TCUS_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "Role User type compatibilities"); + } + lol_info.version = RSBAC_RC_ROLE_TCPR_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t); + lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t); + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_tcpr_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_DEF_SUBDATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + tcfd_get_conv, tcfd_get_subconv, + NULL, &def_tc, + RSBAC_RC_ROLE_TCPR_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, + "Role Process type compatibilities"); + } + lol_info.version = RSBAC_RC_ROLE_TCIP_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t); + lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t); + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_tcip_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_DEF_SUBDATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + tcfd_get_conv, tcfd_get_subconv, + NULL, &def_tc, + RSBAC_RC_ROLE_TCIP_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "Role IPC type compatibilities"); + } + lol_info.version = RSBAC_RC_ROLE_TCSC_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t); + lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t); + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_tcsc_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_DEF_SUBDATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + tcfd_get_conv, tcfd_get_subconv, + NULL, &def_tc, + RSBAC_RC_ROLE_TCSC_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "Role SCD type compatibilities"); + } + lol_info.version = RSBAC_RC_ROLE_TCGR_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t); + lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t); + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_tcgr_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_DEF_SUBDATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + tcfd_get_conv, tcfd_get_subconv, + NULL, &def_tc, + RSBAC_RC_ROLE_TCGR_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "Role Group type compatibilities"); + } + lol_info.version = RSBAC_RC_ROLE_TCND_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t); + lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t); + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_tcnd_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_DEF_SUBDATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + tcfd_get_conv, tcfd_get_subconv, + NULL, &def_tc, + RSBAC_RC_ROLE_TCND_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, + "Role NETDEV type compatibilities"); + } + lol_info.version = RSBAC_RC_ROLE_TCNT_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t); + lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t); + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_tcnt_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_DEF_SUBDATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + tcfd_get_conv, tcfd_get_subconv, + NULL, &def_tc, + RSBAC_RC_ROLE_TCNT_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, + "Role NETTEMP type compatibilities"); + } + lol_info.version = RSBAC_RC_ROLE_TCNO_LIST_VERSION; + lol_info.key = RSBAC_RC_LIST_KEY; + lol_info.desc_size = sizeof(rsbac_rc_role_id_t); + lol_info.data_size = 0; + lol_info.subdesc_size = sizeof(rsbac_rc_type_id_t); + lol_info.subdata_size = sizeof(rsbac_rc_rights_vector_t); + lol_info.max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &role_tcno_handle, &lol_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_DEF_SUBDATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, + NULL, + tcfd_get_conv, tcfd_get_subconv, + NULL, &def_tc, + RSBAC_RC_ROLE_TCNO_FILENAME, + RSBAC_AUTO_DEV, + nr_role_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, + "Role NETOBJ type compatibilities"); + } + + /* Create default role settings, if none there */ + if (!rsbac_no_defaults && !rsbac_list_count(role_handle)) { + create_def_roles(); + create_def_roles2(); + } + + list_info.version = RSBAC_RC_TYPE_FD_LIST_VERSION; + list_info.key = RSBAC_RC_LIST_KEY; + list_info.desc_size = sizeof(rsbac_rc_type_id_t); + list_info.data_size = sizeof(struct rsbac_rc_type_fd_entry_t); + list_info.max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &type_fd_handle, &list_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, NULL, + RSBAC_RC_TYPE_FD_FILENAME, + RSBAC_AUTO_DEV, + nr_type_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "type FD"); + } + if (!rsbac_no_defaults && !rsbac_list_count(type_fd_handle)) { + rsbac_rc_type_id_t type; + struct rsbac_rc_type_fd_entry_t entry; + + type = RSBAC_RC_GENERAL_TYPE; + strcpy(entry.name, "General FD"); + entry.need_secdel = 0; + rsbac_list_add(type_fd_handle, &type, &entry); + type = RSBAC_RC_SEC_TYPE; + strcpy(entry.name, "Security FD"); + entry.need_secdel = 0; + rsbac_list_add(type_fd_handle, &type, &entry); + type = RSBAC_RC_SYS_TYPE; + strcpy(entry.name, "System FD"); + entry.need_secdel = 0; + rsbac_list_add(type_fd_handle, &type, &entry); + } + list_info.version = RSBAC_RC_TYPE_DEV_LIST_VERSION; + list_info.key = RSBAC_RC_LIST_KEY; + list_info.desc_size = sizeof(rsbac_rc_type_id_t); + list_info.data_size = RSBAC_RC_NAME_LEN; + list_info.max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &type_dev_handle, &list_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, NULL, + RSBAC_RC_TYPE_DEV_FILENAME, + RSBAC_AUTO_DEV, + nr_type_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "type DEV"); + } + if (!rsbac_no_defaults && !rsbac_list_count(type_dev_handle)) { + rsbac_rc_type_id_t type; + char name[RSBAC_RC_NAME_LEN]; + + type = RSBAC_RC_GENERAL_TYPE; + strcpy(name, "General Device"); + rsbac_list_add(type_dev_handle, &type, name); + type = RSBAC_RC_SEC_TYPE; + strcpy(name, "Security Device"); + rsbac_list_add(type_dev_handle, &type, name); + type = RSBAC_RC_SYS_TYPE; + strcpy(name, "System Device"); + rsbac_list_add(type_dev_handle, &type, &name); + } + list_info.version = RSBAC_RC_TYPE_IPC_LIST_VERSION; + list_info.key = RSBAC_RC_LIST_KEY; + list_info.desc_size = sizeof(rsbac_rc_type_id_t); + list_info.data_size = RSBAC_RC_NAME_LEN; + list_info.max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &type_ipc_handle, &list_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, NULL, + RSBAC_RC_TYPE_IPC_FILENAME, + RSBAC_AUTO_DEV, + nr_type_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "type IPC"); + } + if (!rsbac_no_defaults && !rsbac_list_count(type_ipc_handle)) { + rsbac_rc_type_id_t type; + char name[RSBAC_RC_NAME_LEN]; + + type = RSBAC_RC_GENERAL_TYPE; + strcpy(name, "General IPC"); + rsbac_list_add(type_ipc_handle, &type, name); + type = RSBAC_RC_SEC_TYPE; + strcpy(name, "Security IPC"); + rsbac_list_add(type_ipc_handle, &type, name); + type = RSBAC_RC_SYS_TYPE; + strcpy(name, "System IPC"); + rsbac_list_add(type_ipc_handle, &type, &name); + } + list_info.version = RSBAC_RC_TYPE_USER_LIST_VERSION; + list_info.key = RSBAC_RC_LIST_KEY; + list_info.desc_size = sizeof(rsbac_rc_type_id_t); + list_info.data_size = RSBAC_RC_NAME_LEN; + list_info.max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &type_user_handle, &list_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, NULL, + RSBAC_RC_TYPE_USER_FILENAME, + RSBAC_AUTO_DEV, + nr_type_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "type USER"); + } + if (!rsbac_no_defaults && !rsbac_list_count(type_user_handle)) { + rsbac_rc_type_id_t type; + char name[RSBAC_RC_NAME_LEN]; + + type = RSBAC_RC_GENERAL_TYPE; + strcpy(name, "General User"); + rsbac_list_add(type_user_handle, &type, name); + type = RSBAC_RC_SEC_TYPE; + strcpy(name, "Security User"); + rsbac_list_add(type_user_handle, &type, name); + type = RSBAC_RC_SYS_TYPE; + strcpy(name, "System User"); + rsbac_list_add(type_user_handle, &type, &name); + } + list_info.version = RSBAC_RC_TYPE_PROCESS_LIST_VERSION; + list_info.key = RSBAC_RC_LIST_KEY; + list_info.desc_size = sizeof(rsbac_rc_type_id_t); + list_info.data_size = RSBAC_RC_NAME_LEN; + list_info.max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &type_process_handle, &list_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, NULL, + RSBAC_RC_TYPE_PROCESS_FILENAME, + RSBAC_AUTO_DEV, + nr_type_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "type PROCESS"); + } + if (!rsbac_no_defaults && !rsbac_list_count(type_process_handle)) { + rsbac_rc_type_id_t type; + char name[RSBAC_RC_NAME_LEN]; + + type = RSBAC_RC_GENERAL_TYPE; + strcpy(name, "General Process"); + rsbac_list_add(type_process_handle, &type, name); + type = RSBAC_RC_SEC_TYPE; + strcpy(name, "Security Proc"); + rsbac_list_add(type_process_handle, &type, name); + type = RSBAC_RC_SYS_TYPE; + strcpy(name, "System Process"); + rsbac_list_add(type_process_handle, &type, &name); + } + if (!rsbac_no_defaults) { + rsbac_rc_type_id_t type = + CONFIG_RSBAC_RC_KERNEL_PROCESS_TYPE; + + if (!rsbac_list_exist(type_process_handle, &type)) { + char name[RSBAC_RC_NAME_LEN]; + rsbac_rc_role_id_t *role_array; + u_long count; + rsbac_rc_rights_vector_t rights; + + strcpy(name, "Kernel Process"); + rsbac_list_add(type_process_handle, &type, &name); + + /* Set type compatibilities for the new type for all roles */ + rights = RSBAC_READ_WRITE_REQUEST_VECTOR + & RSBAC_PROCESS_REQUEST_VECTOR; + + count = + rsbac_list_lol_get_all_desc(role_tcpr_handle, + (void **) + &role_array); + if (count > 0) { + u_int i; + + for (i = 0; i < count; i++) { + if (!rsbac_list_lol_subexist + (role_tcpr_handle, + &role_array[i], &type)) + rsbac_list_lol_subadd + (role_tcpr_handle, + &role_array[i], &type, + &rights); + } + rsbac_kfree(role_array); + } + } + } + list_info.version = RSBAC_RC_TYPE_GROUP_LIST_VERSION; + list_info.key = RSBAC_RC_LIST_KEY; + list_info.desc_size = sizeof(rsbac_rc_type_id_t); + list_info.data_size = RSBAC_RC_NAME_LEN; + list_info.max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &type_group_handle, &list_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, NULL, + RSBAC_RC_TYPE_GROUP_FILENAME, + RSBAC_AUTO_DEV, + nr_type_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "type GROUP"); + } + if (!rsbac_no_defaults && !rsbac_list_count(type_group_handle)) { + rsbac_rc_type_id_t type; + char name[RSBAC_RC_NAME_LEN]; + + type = RSBAC_RC_GENERAL_TYPE; + strcpy(name, "General Group"); + rsbac_list_add(type_group_handle, &type, name); + } + list_info.version = RSBAC_RC_TYPE_NETDEV_LIST_VERSION; + list_info.key = RSBAC_RC_LIST_KEY; + list_info.desc_size = sizeof(rsbac_rc_type_id_t); + list_info.data_size = RSBAC_RC_NAME_LEN; + list_info.max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &type_netdev_handle, &list_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, NULL, + RSBAC_RC_TYPE_NETDEV_FILENAME, + RSBAC_AUTO_DEV, + nr_type_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "type NETDEV"); + } + if (!rsbac_no_defaults && !rsbac_list_count(type_netdev_handle)) { + rsbac_rc_type_id_t type; + char name[RSBAC_RC_NAME_LEN]; + + type = RSBAC_RC_GENERAL_TYPE; + strcpy(name, "General NETDEV"); + rsbac_list_add(type_netdev_handle, &type, name); + type = RSBAC_RC_SEC_TYPE; + strcpy(name, "Security NETDEV"); + rsbac_list_add(type_netdev_handle, &type, name); + type = RSBAC_RC_SYS_TYPE; + strcpy(name, "System NETDEV"); + rsbac_list_add(type_netdev_handle, &type, &name); + } + list_info.version = RSBAC_RC_TYPE_NETTEMP_LIST_VERSION; + list_info.key = RSBAC_RC_LIST_KEY; + list_info.desc_size = sizeof(rsbac_rc_type_id_t); + list_info.data_size = RSBAC_RC_NAME_LEN; + list_info.max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &type_nettemp_handle, &list_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, NULL, + RSBAC_RC_TYPE_NETTEMP_FILENAME, + RSBAC_AUTO_DEV, + nr_type_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "type NETTEMP"); + } + if (!rsbac_no_defaults && !rsbac_list_count(type_nettemp_handle)) { + rsbac_rc_type_id_t type; + char name[RSBAC_RC_NAME_LEN]; + + type = RSBAC_RC_GENERAL_TYPE; + strcpy(name, "General NETTEMP"); + rsbac_list_add(type_nettemp_handle, &type, name); + type = RSBAC_RC_SEC_TYPE; + strcpy(name, "Securit NETTEMP"); + rsbac_list_add(type_nettemp_handle, &type, name); + type = RSBAC_RC_SYS_TYPE; + strcpy(name, "System NETTEMP"); + rsbac_list_add(type_nettemp_handle, &type, &name); + } + list_info.version = RSBAC_RC_TYPE_NETOBJ_LIST_VERSION; + list_info.key = RSBAC_RC_LIST_KEY; + list_info.desc_size = sizeof(rsbac_rc_type_id_t); + list_info.data_size = RSBAC_RC_NAME_LEN; + list_info.max_age = 0; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &type_netobj_handle, &list_info, +#if defined(CONFIG_RSBAC_RC_BACKUP) + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | RSBAC_LIST_OWN_SLAB | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, NULL, + RSBAC_RC_TYPE_NETOBJ_FILENAME, + RSBAC_AUTO_DEV, + nr_type_hash_bits, + rsbac_list_hash_u32, + NULL); + if (err) { + registration_error(err, "type NETOBJ"); + } + if (!rsbac_no_defaults && !rsbac_list_count(type_netobj_handle)) { + rsbac_rc_type_id_t type; + char name[RSBAC_RC_NAME_LEN]; + + type = RSBAC_RC_GENERAL_TYPE; + strcpy(name, "General NETOBJ"); + rsbac_list_add(type_netobj_handle, &type, name); + type = RSBAC_RC_SEC_TYPE; + strcpy(name, "Security NETOBJ"); + rsbac_list_add(type_netobj_handle, &type, name); + type = RSBAC_RC_SYS_TYPE; + strcpy(name, "System NETOBJ"); + rsbac_list_add(type_netobj_handle, &type, &name); + } + rsbac_pr_debug(stack, "free stack before adding proc entry: %lu\n", + rsbac_stack_free_space()); +#if defined(CONFIG_RSBAC_PROC) + stats_rc = proc_create("stats_rc", + S_IFREG | S_IRUGO, + proc_rsbac_root_p, &stats_rc_proc_fops); +#endif + rsbac_pr_debug(stack, "final free stack: %lu\n", + rsbac_stack_free_space()); + rsbac_pr_debug(ds_rc, "Ready.\n"); + return (err); +} + +/***************************************************/ +/* We also need some status information... */ + +int rsbac_stats_rc(void) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_stats_rc(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + + rsbac_printk(KERN_INFO "Role entry size is %u, %lu entries used\n", + sizeof(struct rsbac_rc_role_entry_t), + rsbac_list_count(role_handle)); + + rsbac_printk(KERN_INFO "Used type entries: fd: %lu, dev: %lu, ipc: %lu, user: %lu, process: %lu, group: %lu, netdev: %lu, nettemp: %lu, netobj: %lu\n", + rsbac_list_count(type_fd_handle), + rsbac_list_count(type_dev_handle), + rsbac_list_count(type_ipc_handle), + rsbac_list_count(type_user_handle), + rsbac_list_count(type_process_handle), + rsbac_list_count(type_group_handle), + rsbac_list_count(type_netdev_handle), + rsbac_list_count(type_nettemp_handle), + rsbac_list_count(type_netobj_handle)); + return 0; +} + +/************************************************* */ +/* Access functions */ +/************************************************* */ + +/* Find the boot role */ +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_rc_get_boot_role(rsbac_rc_role_id_t * role_p) +#else +int __init rsbac_rc_get_boot_role(rsbac_rc_role_id_t * role_p) +#endif +{ + /* Try to find role marked as boot role */ + if (rsbac_list_get_desc(role_handle, + role_p, role_p, rsbac_rc_role_compare_data) + ) { /* none found */ + return -RSBAC_ENOTFOUND; + } + return 0; +} + +/* Checking whether role exists */ +rsbac_boolean_t rsbac_rc_role_exists(rsbac_list_ta_number_t ta_number, + rsbac_rc_role_id_t role) +{ + return rsbac_ta_list_exist(ta_number, role_handle, &role); +} + +rsbac_boolean_t rsbac_rc_type_exists(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + rsbac_rc_type_id_t type) +{ + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_FD: + return rsbac_ta_list_exist(ta_number, type_fd_handle, + &type); + case T_DEV: + return rsbac_ta_list_exist(ta_number, type_dev_handle, + &type); + case T_IPC: + return rsbac_ta_list_exist(ta_number, type_ipc_handle, + &type); + case T_USER: + return rsbac_ta_list_exist(ta_number, type_user_handle, + &type); + case T_PROCESS: + return rsbac_ta_list_exist(ta_number, type_process_handle, + &type); + case T_NETDEV: + return rsbac_ta_list_exist(ta_number, type_netdev_handle, + &type); + case T_NETTEMP: + return rsbac_ta_list_exist(ta_number, type_nettemp_handle, + &type); + case T_NETOBJ: + return rsbac_ta_list_exist(ta_number, type_netobj_handle, + &type); + case T_SCD: + if (type < ST_none) + return TRUE; + else + return FALSE; + default: + return FALSE; + } +} + +/* Invalid parameter combinations return an error. */ + +int rsbac_rc_copy_role(rsbac_list_ta_number_t ta_number, + rsbac_rc_role_id_t from_role, + rsbac_rc_role_id_t to_role) +{ + struct rsbac_rc_role_entry_t entry; + rsbac_rc_role_id_t *role_array; + char *item_array; + long count; + u_long i; + int err; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_rc_copy_role(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + if ((from_role > RC_role_max_value) + || (to_role > RC_role_max_value) + || (to_role == from_role) + ) + return (-RSBAC_EINVALIDTARGET); + + /* copy */ + err = + rsbac_ta_list_get_data_ttl(ta_number, role_handle, NULL, + &from_role, &entry); + if (err) + return err; + err = + rsbac_ta_list_add_ttl(ta_number, role_handle, 0, &to_role, + &entry); + if (err) + return err; + + rsbac_ta_list_lol_remove(ta_number, role_rc_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + role_rc_handle, + &from_role, + (void **) &role_array, + NULL); + if (count > 0) { + for (i = 0; i < count; i++) + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_rc_handle, 0, + &to_role, + &role_array[i], 0); + rsbac_kfree(role_array); + } + rsbac_ta_list_lol_remove(ta_number, role_adr_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + role_adr_handle, + &from_role, + (void **) &role_array, + NULL); + if (count > 0) { + for (i = 0; i < count; i++) + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_adr_handle, 0, + &to_role, + &role_array[i], 0); + rsbac_kfree(role_array); + } + rsbac_ta_list_lol_remove(ta_number, role_asr_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + role_asr_handle, + &from_role, + (void **) &role_array, + NULL); + if (count > 0) { + for (i = 0; i < count; i++) + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_asr_handle, 0, + &to_role, + &role_array[i], 0); + rsbac_kfree(role_array); + } + rsbac_ta_list_lol_remove(ta_number, role_dfdc_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + role_dfdc_handle, + &from_role, + (void **) &item_array, + NULL); + if (count > 0) { + char *tmp = item_array; + int size = + rsbac_list_lol_get_subitem_size(role_dfdc_handle); + + for (i = 0; i < count; i++) { + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_dfdc_handle, 0, + &to_role, tmp, + tmp + + sizeof + (rsbac_rc_role_id_t)); + tmp += size; + } + rsbac_kfree(item_array); + } + rsbac_ta_list_lol_remove(ta_number, role_tcfd_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + role_tcfd_handle, + &from_role, + (void **) &item_array, + NULL); + if (count > 0) { + char *tmp = item_array; + int size = + rsbac_list_lol_get_subitem_size(role_tcfd_handle); + + for (i = 0; i < count; i++) { + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcfd_handle, 0, + &to_role, tmp, + tmp + + sizeof + (rsbac_rc_role_id_t)); + tmp += size; + } + rsbac_kfree(item_array); + } + rsbac_ta_list_lol_remove(ta_number, role_tcdv_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + role_tcdv_handle, + &from_role, + (void **) &item_array, + NULL); + if (count > 0) { + char *tmp = item_array; + int size = + rsbac_list_lol_get_subitem_size(role_tcdv_handle); + + for (i = 0; i < count; i++) { + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcdv_handle, 0, + &to_role, tmp, + tmp + + sizeof + (rsbac_rc_role_id_t)); + tmp += size; + } + rsbac_kfree(item_array); + } + rsbac_ta_list_lol_remove(ta_number, role_tcus_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + role_tcus_handle, + &from_role, + (void **) &item_array, + NULL); + if (count > 0) { + char *tmp = item_array; + int size = + rsbac_list_lol_get_subitem_size(role_tcus_handle); + + for (i = 0; i < count; i++) { + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcus_handle, 0, + &to_role, tmp, + tmp + + sizeof + (rsbac_rc_role_id_t)); + tmp += size; + } + rsbac_kfree(item_array); + } + rsbac_ta_list_lol_remove(ta_number, role_tcpr_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + role_tcpr_handle, + &from_role, + (void **) &item_array, + NULL); + if (count > 0) { + char *tmp = item_array; + int size = + rsbac_list_lol_get_subitem_size(role_tcpr_handle); + + for (i = 0; i < count; i++) { + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcpr_handle, 0, + &to_role, tmp, + tmp + + sizeof + (rsbac_rc_role_id_t)); + tmp += size; + } + rsbac_kfree(item_array); + } + rsbac_ta_list_lol_remove(ta_number, role_tcip_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + role_tcip_handle, + &from_role, + (void **) &item_array, + NULL); + if (count > 0) { + char *tmp = item_array; + int size = + rsbac_list_lol_get_subitem_size(role_tcip_handle); + + for (i = 0; i < count; i++) { + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcip_handle, 0, + &to_role, tmp, + tmp + + sizeof + (rsbac_rc_role_id_t)); + tmp += size; + } + rsbac_kfree(item_array); + } + rsbac_ta_list_lol_remove(ta_number, role_tcsc_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + role_tcsc_handle, + &from_role, + (void **) &item_array, + NULL); + if (count > 0) { + char *tmp = item_array; + int size = + rsbac_list_lol_get_subitem_size(role_tcsc_handle); + + for (i = 0; i < count; i++) { + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcsc_handle, 0, + &to_role, tmp, + tmp + + sizeof + (rsbac_rc_role_id_t)); + tmp += size; + } + rsbac_kfree(item_array); + } + rsbac_ta_list_lol_remove(ta_number, role_tcgr_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + role_tcgr_handle, + &from_role, + (void **) &item_array, + NULL); + if (count > 0) { + char *tmp = item_array; + int size = + rsbac_list_lol_get_subitem_size(role_tcgr_handle); + + for (i = 0; i < count; i++) { + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcgr_handle, 0, + &to_role, tmp, + tmp + + sizeof + (rsbac_rc_role_id_t)); + tmp += size; + } + rsbac_kfree(item_array); + } + rsbac_ta_list_lol_remove(ta_number, role_tcnd_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + role_tcnd_handle, + &from_role, + (void **) &item_array, + NULL); + if (count > 0) { + char *tmp = item_array; + int size = + rsbac_list_lol_get_subitem_size(role_tcnd_handle); + + for (i = 0; i < count; i++) { + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcnd_handle, 0, + &to_role, tmp, + tmp + + sizeof + (rsbac_rc_role_id_t)); + tmp += size; + } + rsbac_kfree(item_array); + } + rsbac_ta_list_lol_remove(ta_number, role_tcnt_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + role_tcnt_handle, + &from_role, + (void **) &item_array, + NULL); + if (count > 0) { + char *tmp = item_array; + int size = + rsbac_list_lol_get_subitem_size(role_tcnt_handle); + + for (i = 0; i < count; i++) { + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcnt_handle, 0, + &to_role, tmp, + tmp + + sizeof + (rsbac_rc_role_id_t)); + tmp += size; + } + rsbac_kfree(item_array); + } + rsbac_ta_list_lol_remove(ta_number, role_tcno_handle, &to_role); + count = + rsbac_ta_list_lol_get_all_subitems_ttl(ta_number, + role_tcno_handle, + &from_role, + (void **) &item_array, + NULL); + if (count > 0) { + char *tmp = item_array; + int size = + rsbac_list_lol_get_subitem_size(role_tcno_handle); + + for (i = 0; i < count; i++) { + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcno_handle, 0, + &to_role, tmp, + tmp + + sizeof + (rsbac_rc_role_id_t)); + tmp += size; + } + rsbac_kfree(item_array); + } + return 0; +} + +int rsbac_rc_copy_type(rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + rsbac_rc_type_id_t from_type, + rsbac_rc_type_id_t to_type) +{ + rsbac_rc_role_id_t *role_array; + rsbac_list_handle_t i_type_handle = NULL; + rsbac_list_handle_t i_comp_handle = NULL; + struct rsbac_rc_type_fd_entry_t type_fd_entry; + char type_name[RSBAC_RC_NAME_LEN]; + long count; + rsbac_time_t ttl; + u_long i; + int err; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_rc_copy_type(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + if ((from_type > RC_type_max_value) + || (to_type > RC_type_max_value) + || (to_type == from_type) + ) + return (-RSBAC_EINVALIDTARGET); + + switch (target) { + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_FD: + i_type_handle = type_fd_handle; + i_comp_handle = role_tcfd_handle; + break; + case T_DEV: + i_type_handle = type_dev_handle; + i_comp_handle = role_tcdv_handle; + break; + case T_USER: + i_type_handle = type_user_handle; + i_comp_handle = role_tcus_handle; + break; + case T_PROCESS: + i_type_handle = type_process_handle; + i_comp_handle = role_tcpr_handle; + break; + case T_IPC: + i_type_handle = type_ipc_handle; + i_comp_handle = role_tcip_handle; + break; + case T_GROUP: + i_type_handle = type_group_handle; + i_comp_handle = role_tcgr_handle; + break; + case T_NETDEV: + i_type_handle = type_netdev_handle; + i_comp_handle = role_tcnd_handle; + break; + case T_NETTEMP: + i_type_handle = type_nettemp_handle; + i_comp_handle = role_tcnt_handle; + break; + case T_NETOBJ: + i_type_handle = type_netobj_handle; + i_comp_handle = role_tcno_handle; + break; + + default: + return -RSBAC_EINVALIDTARGET; + } + + /* copy */ + if (i_type_handle == type_fd_handle) { + err = + rsbac_ta_list_get_data_ttl(ta_number, i_type_handle, + &ttl, &from_type, + &type_fd_entry); + if (err) + return err; + err = + rsbac_ta_list_add_ttl(ta_number, i_type_handle, ttl, + &to_type, &type_fd_entry); + if (err) + return err; + } else { + err = + rsbac_ta_list_get_data_ttl(ta_number, i_type_handle, + NULL, &from_type, + &type_name); + if (err) + return err; + err = + rsbac_ta_list_add_ttl(ta_number, i_type_handle, 0, + &to_type, &type_name); + if (err) + return err; + } + + err = + rsbac_ta_list_lol_subremove_from_all(ta_number, i_comp_handle, + &to_type); + if (err) + return err; + + count = rsbac_ta_list_get_all_desc(ta_number, role_handle, + (void **) &role_array); + if (count > 0) { + rsbac_rc_rights_vector_t rights; + + for (i = 0; i < count; i++) { + err = rsbac_ta_list_lol_get_subdata_ttl(ta_number, + i_comp_handle, + &ttl, + &role_array + [i], + &from_type, + &rights); + if (!err) + err = + rsbac_ta_list_lol_subadd_ttl(ta_number, + i_comp_handle, + ttl, + &role_array + [i], + &to_type, + &rights); + } + rsbac_kfree(role_array); + } + return 0; +} + + +/* Getting values */ +int rsbac_rc_get_item(rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t tid, + union rsbac_rc_target_id_t subtid, + enum rsbac_rc_item_t item, + union rsbac_rc_item_value_t *value_p, + rsbac_time_t * ttl_p) +{ + int err = 0; + struct rsbac_rc_role_entry_t role_entry; + struct rsbac_rc_type_fd_entry_t type_fd_entry; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_rc_get_item(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_rc_get_item(): called from interrupt!\n"); + } + if (ttl_p) + *ttl_p = 0; + switch (target) { + case RT_ROLE: + if (tid.role > RC_role_max_value) + return (-RSBAC_EINVALIDTARGET); +/* + rsbac_pr_debug(ds_rc, "getting role item value\n"); +*/ + switch (item) { + case RI_role_comp: + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_rc_handle, + ttl_p, + &tid.role, + &subtid. + role, NULL)) + value_p->comp = TRUE; + else + value_p->comp = FALSE; + return 0; + case RI_admin_roles: + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_adr_handle, + ttl_p, + &tid.role, + &subtid. + role, NULL)) + value_p->comp = TRUE; + else + value_p->comp = FALSE; + return 0; + case RI_assign_roles: + if (!rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_asr_handle, + ttl_p, + &tid.role, + &subtid. + role, NULL)) + value_p->comp = TRUE; + else + value_p->comp = FALSE; + return 0; + case RI_type_comp_fd: + if (rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_tcfd_handle, + ttl_p, + &tid.role, + &subtid.type, + &value_p-> + rights)) { + value_p->rights = + RSBAC_RC_DEFAULT_RIGHTS_VECTOR; + if (ttl_p) + *ttl_p = 0; + } + return 0; + case RI_type_comp_dev: + if (rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_tcdv_handle, + ttl_p, + &tid.role, + &subtid.type, + &value_p-> + rights)) { + value_p->rights = + RSBAC_RC_DEFAULT_RIGHTS_VECTOR; + if (ttl_p) + *ttl_p = 0; + } + return 0; + case RI_type_comp_user: + if (rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_tcus_handle, + ttl_p, + &tid.role, + &subtid.type, + &value_p-> + rights)) { + value_p->rights = + RSBAC_RC_DEFAULT_RIGHTS_VECTOR; + if (ttl_p) + *ttl_p = 0; + } + return 0; + case RI_type_comp_process: + if (rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_tcpr_handle, + ttl_p, + &tid.role, + &subtid.type, + &value_p-> + rights)) { + value_p->rights = + RSBAC_RC_DEFAULT_RIGHTS_VECTOR; + if (ttl_p) + *ttl_p = 0; + } + return 0; + case RI_type_comp_ipc: + if (rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_tcip_handle, + ttl_p, + &tid.role, + &subtid.type, + &value_p-> + rights)) { + value_p->rights = + RSBAC_RC_DEFAULT_RIGHTS_VECTOR; + if (ttl_p) + *ttl_p = 0; + } + return 0; + case RI_type_comp_scd: + if (rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_tcsc_handle, + ttl_p, + &tid.role, + &subtid.type, + &value_p-> + rights)) { + value_p->rights = + RSBAC_RC_DEFAULT_RIGHTS_VECTOR; + if (ttl_p) + *ttl_p = 0; + } + return 0; + case RI_type_comp_group: + if (rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_tcgr_handle, + ttl_p, + &tid.role, + &subtid.type, + &value_p-> + rights)) { + value_p->rights = + RSBAC_RC_DEFAULT_RIGHTS_VECTOR; + if (ttl_p) + *ttl_p = 0; + } + return 0; + case RI_type_comp_netdev: + if (rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_tcnd_handle, + ttl_p, + &tid.role, + &subtid.type, + &value_p-> + rights)) { + value_p->rights = + RSBAC_RC_DEFAULT_RIGHTS_VECTOR; + if (ttl_p) + *ttl_p = 0; + } + return 0; + case RI_type_comp_nettemp: + if (rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_tcnt_handle, + ttl_p, + &tid.role, + &subtid.type, + &value_p-> + rights)) { + value_p->rights = + RSBAC_RC_DEFAULT_RIGHTS_VECTOR; + if (ttl_p) + *ttl_p = 0; + } + return 0; + case RI_type_comp_netobj: + if (rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_tcno_handle, + ttl_p, + &tid.role, + &subtid.type, + &value_p-> + rights)) { + value_p->rights = + RSBAC_RC_DEFAULT_RIGHTS_VECTOR; + if (ttl_p) + *ttl_p = 0; + } + return 0; + case RI_admin_type: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, NULL, + &tid.role, + &role_entry))) + value_p->admin_type = + role_entry.admin_type; + return err; + case RI_name: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, NULL, + &tid.role, + &role_entry))) { + strncpy(value_p->name, role_entry.name, + RSBAC_RC_NAME_LEN - 1); + value_p->name[RSBAC_RC_NAME_LEN - 1] = + (char) 0; + } + return err; + case RI_def_fd_create_type: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, NULL, + &tid.role, + &role_entry))) + value_p->type_id = + role_entry.def_fd_create_type; + return err; + case RI_def_fd_ind_create_type: + return rsbac_ta_list_lol_get_subdata_ttl(ta_number, + role_dfdc_handle, + ttl_p, + &tid.role, + &subtid. + type, + &value_p-> + type_id); + case RI_def_user_create_type: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, NULL, + &tid.role, + &role_entry))) + value_p->type_id = + role_entry.def_user_create_type; + return err; + case RI_def_process_create_type: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, NULL, + &tid.role, + &role_entry))) + value_p->type_id = + role_entry.def_process_create_type; + return err; + case RI_def_process_chown_type: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, NULL, + &tid.role, + &role_entry))) + value_p->type_id = + role_entry.def_process_chown_type; + return err; + case RI_def_process_execute_type: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, NULL, + &tid.role, + &role_entry))) + value_p->type_id = + role_entry.def_process_execute_type; + return err; + case RI_def_ipc_create_type: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, NULL, + &tid.role, + &role_entry))) + value_p->type_id = + role_entry.def_ipc_create_type; + return err; + case RI_def_group_create_type: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, NULL, + &tid.role, + &role_entry))) + value_p->type_id = + role_entry.def_group_create_type; + return err; + case RI_def_unixsock_create_type: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, NULL, + &tid.role, + &role_entry))) + value_p->type_id = + role_entry.def_unixsock_create_type; + return err; + case RI_boot_role: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, NULL, + &tid.role, + &role_entry))) + value_p->boot_role = role_entry.boot_role; + return err; + case RI_req_reauth: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, NULL, + &tid.role, + &role_entry))) + value_p->req_reauth = + role_entry.req_reauth; + return err; + default: + return -RSBAC_EINVALIDATTR; + } + /* return */ + return (err); + break; + + case RT_TYPE: + if (tid.type > RC_type_max_value) + return (-RSBAC_EINVALIDTARGET); +/* + rsbac_pr_debug(ds_rc, "getting type item value\n"); +*/ + switch (item) { + case RI_type_fd_name: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + type_fd_handle, + NULL, &tid.type, + &type_fd_entry))) { + strncpy(value_p->name, type_fd_entry.name, + RSBAC_RC_NAME_LEN - 1); + value_p->name[RSBAC_RC_NAME_LEN - 1] = + (char) 0; + } + return err; + case RI_type_fd_need_secdel: + if (! + (err = + rsbac_ta_list_get_data_ttl(ta_number, + type_fd_handle, + NULL, &tid.type, + &type_fd_entry))) { + value_p->need_secdel = + type_fd_entry.need_secdel; + } + return err; + case RI_type_dev_name: + return rsbac_ta_list_get_data_ttl(ta_number, + type_dev_handle, + NULL, &tid.type, + value_p->name); + case RI_type_ipc_name: + return rsbac_ta_list_get_data_ttl(ta_number, + type_ipc_handle, + NULL, &tid.type, + value_p->name); + case RI_type_user_name: + return rsbac_ta_list_get_data_ttl(ta_number, + type_user_handle, + NULL, &tid.type, + value_p->name); + case RI_type_process_name: + return rsbac_ta_list_get_data_ttl(ta_number, + type_process_handle, + NULL, &tid.type, + value_p->name); + case RI_type_group_name: + return rsbac_ta_list_get_data_ttl(ta_number, + type_group_handle, + NULL, &tid.type, + value_p->name); + case RI_type_netdev_name: + return rsbac_ta_list_get_data_ttl(ta_number, + type_netdev_handle, + NULL, &tid.type, + value_p->name); + case RI_type_nettemp_name: + return rsbac_ta_list_get_data_ttl(ta_number, + type_nettemp_handle, + NULL, &tid.type, + value_p->name); + case RI_type_netobj_name: + return rsbac_ta_list_get_data_ttl(ta_number, + type_netobj_handle, + NULL, &tid.type, + value_p->name); + case RI_type_scd_name: + { + char *tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if (!tmp) + err = -RSBAC_ENOMEM; + else { + get_rc_scd_type_name(tmp, + tid.type); + strncpy(value_p->name, tmp, + RSBAC_RC_NAME_LEN - 1); + value_p->name[RSBAC_RC_NAME_LEN - + 1] = (char) 0; + rsbac_kfree(tmp); + } + break; + } + default: + err = -RSBAC_EINVALIDATTR; + } + /* and return */ + return (err); + break; + + /* switch target: no valid target */ + default: + err = -RSBAC_EINVALIDTARGET; + } + return err; +} /* end of rsbac_rc_get_item() */ + +/* Checking role's compatibility */ +rsbac_boolean_t rsbac_rc_check_comp(rsbac_rc_role_id_t role, + union rsbac_rc_target_id_t subtid, + enum rsbac_rc_item_t item, + enum rsbac_rc_special_rights_t right) +{ + rsbac_rc_rights_vector_t rights_vector; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_rc_check_comp(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_rc_check_comp(): called from interrupt!\n"); + } + if (role > RC_role_max_value) + return FALSE; +/* + rsbac_pr_debug(ds_rc, "checking role compatibility\n"); +*/ + switch (item) { + case RI_role_comp: + return rsbac_list_lol_subexist(role_rc_handle, &role, + &subtid.role); + case RI_admin_roles: + return rsbac_list_lol_subexist(role_adr_handle, &role, + &subtid.role); + case RI_assign_roles: + return rsbac_list_lol_subexist(role_asr_handle, &role, + &subtid.role); + case RI_type_comp_fd: + if (!rsbac_list_lol_get_subdata + (role_tcfd_handle, &role, &subtid.type, &rights_vector) + && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right)) + ) + return TRUE; + else + return FALSE; + case RI_type_comp_dev: + if (!rsbac_list_lol_get_subdata + (role_tcdv_handle, &role, &subtid.type, &rights_vector) + && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right)) + ) + return TRUE; + else + return FALSE; + case RI_type_comp_user: + if (!rsbac_list_lol_get_subdata + (role_tcus_handle, &role, &subtid.type, &rights_vector) + && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right)) + ) + return TRUE; + else + return FALSE; + case RI_type_comp_process: + if (!rsbac_list_lol_get_subdata + (role_tcpr_handle, &role, &subtid.type, &rights_vector) + && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right)) + ) + return TRUE; + else + return FALSE; + case RI_type_comp_ipc: + if (!rsbac_list_lol_get_subdata + (role_tcip_handle, &role, &subtid.type, &rights_vector) + && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right)) + ) + return TRUE; + else + return FALSE; + case RI_type_comp_scd: + if (!rsbac_list_lol_get_subdata + (role_tcsc_handle, &role, &subtid.type, &rights_vector) + && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right)) + ) + return TRUE; + else + return FALSE; + case RI_type_comp_group: + if (!rsbac_list_lol_get_subdata + (role_tcgr_handle, &role, &subtid.type, &rights_vector) + && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right)) + ) + return TRUE; + else + return FALSE; + case RI_type_comp_netdev: + if (!rsbac_list_lol_get_subdata + (role_tcnd_handle, &role, &subtid.type, &rights_vector) + && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right)) + ) + return TRUE; + else + return FALSE; + case RI_type_comp_nettemp: + if (!rsbac_list_lol_get_subdata + (role_tcnt_handle, &role, &subtid.type, &rights_vector) + && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right)) + ) + return TRUE; + else + return FALSE; + case RI_type_comp_netobj: + if (!rsbac_list_lol_get_subdata + (role_tcno_handle, &role, &subtid.type, &rights_vector) + && (rights_vector & RSBAC_RC_RIGHTS_VECTOR(right)) + ) + return TRUE; + else + return FALSE; + + default: + rsbac_printk(KERN_WARNING "rsbac_rc_check_comp(): called for invalid item %u\n", + item); + return FALSE; + } +} /* end of rsbac_rc_check_comp() */ + +/* Get list of defined items. Returns number or negative error. + * item is to distinguish type targets, use RI_type_xx_name */ +int rsbac_rc_get_list(rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t tid, + enum rsbac_rc_item_t item, + __u32 ** array_pp, rsbac_time_t ** ttl_array_pp) +{ + int res; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_rc_get_list(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_rc_get_list(): called from interrupt!\n"); + } + if (ttl_array_pp) + *ttl_array_pp = NULL; + switch (target) { + case RT_ROLE: +/* + rsbac_pr_debug(ds_rc, "getting role list\n"); +*/ + switch (item) { + case RI_name: + if (array_pp) + return + rsbac_ta_list_get_all_desc(ta_number, + role_handle, + (void **) + array_pp); + else + return rsbac_ta_list_count(ta_number, + role_handle); + case RI_role_comp: + if (array_pp) + res = + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_rc_handle, &tid.role, + (void **) array_pp, ttl_array_pp); + else + res = + rsbac_ta_list_lol_subcount(ta_number, + role_rc_handle, + &tid.role); + if (res == -RSBAC_ENOTFOUND) + return 0; + else + return res; + case RI_admin_roles: + if (array_pp) + res = + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_adr_handle, &tid.role, + (void **) array_pp, ttl_array_pp); + else + res = + rsbac_ta_list_lol_subcount(ta_number, + role_adr_handle, + &tid.role); + if (res == -RSBAC_ENOTFOUND) + return 0; + else + return res; + case RI_assign_roles: + if (array_pp) + res = + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_asr_handle, &tid.role, + (void **) array_pp, ttl_array_pp); + else + res = + rsbac_ta_list_lol_subcount(ta_number, + role_asr_handle, + &tid.role); + if (res == -RSBAC_ENOTFOUND) + return 0; + else + return res; + case RI_def_fd_ind_create_type: + if (array_pp) + return + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_dfdc_handle, + &tid.role, (void **) array_pp, + ttl_array_pp); + else + return + rsbac_ta_list_lol_subcount(ta_number, + role_dfdc_handle, + &tid.role); + case RI_type_comp_fd: + if (array_pp) + return + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_tcfd_handle, + &tid.role, (void **) array_pp, + ttl_array_pp); + else + return + rsbac_ta_list_lol_subcount(ta_number, + role_tcfd_handle, + &tid.role); + case RI_type_comp_dev: + if (array_pp) + return + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_tcdv_handle, + &tid.role, (void **) array_pp, + ttl_array_pp); + else + return + rsbac_ta_list_lol_subcount(ta_number, + role_tcdv_handle, + &tid.role); + case RI_type_comp_user: + if (array_pp) + return + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_tcus_handle, + &tid.role, (void **) array_pp, + ttl_array_pp); + else + return + rsbac_ta_list_lol_subcount(ta_number, + role_tcus_handle, + &tid.role); + case RI_type_comp_process: + if (array_pp) + return + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_tcpr_handle, + &tid.role, (void **) array_pp, + ttl_array_pp); + else + return + rsbac_ta_list_lol_subcount(ta_number, + role_tcpr_handle, + &tid.role); + case RI_type_comp_ipc: + if (array_pp) + return + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_tcip_handle, + &tid.role, (void **) array_pp, + ttl_array_pp); + else + return + rsbac_ta_list_lol_subcount(ta_number, + role_tcip_handle, + &tid.role); + case RI_type_comp_scd: + if (array_pp) + return + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_tcsc_handle, + &tid.role, (void **) array_pp, + ttl_array_pp); + else + return + rsbac_ta_list_lol_subcount(ta_number, + role_tcsc_handle, + &tid.role); + case RI_type_comp_group: + if (array_pp) + return + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_tcgr_handle, + &tid.role, (void **) array_pp, + ttl_array_pp); + else + return + rsbac_ta_list_lol_subcount(ta_number, + role_tcgr_handle, + &tid.role); + case RI_type_comp_netdev: + if (array_pp) + return + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_tcnd_handle, + &tid.role, (void **) array_pp, + ttl_array_pp); + else + return + rsbac_ta_list_lol_subcount(ta_number, + role_tcnd_handle, + &tid.role); + case RI_type_comp_nettemp: + if (array_pp) + return + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_tcnt_handle, + &tid.role, (void **) array_pp, + ttl_array_pp); + else + return + rsbac_ta_list_lol_subcount(ta_number, + role_tcnt_handle, + &tid.role); + case RI_type_comp_netobj: + if (array_pp) + return + rsbac_ta_list_lol_get_all_subdesc_ttl + (ta_number, role_tcno_handle, + &tid.role, (void **) array_pp, + ttl_array_pp); + else + return + rsbac_ta_list_lol_subcount(ta_number, + role_tcno_handle, + &tid.role); + + default: + return -RSBAC_EINVALIDATTR; + } + + case RT_TYPE: +/* + rsbac_pr_debug(ds_rc, "getting type item value\n"); +*/ + switch (item) { + case RI_type_fd_name: + case RI_type_fd_need_secdel: + if (array_pp) + return + rsbac_ta_list_get_all_desc(ta_number, + type_fd_handle, + (void **) + array_pp); + else + return rsbac_ta_list_count(ta_number, + type_fd_handle); + case RI_type_dev_name: + if (array_pp) + return + rsbac_ta_list_get_all_desc(ta_number, + type_dev_handle, + (void **) + array_pp); + else + return rsbac_ta_list_count(ta_number, + type_dev_handle); + case RI_type_ipc_name: + if (array_pp) + return + rsbac_ta_list_get_all_desc(ta_number, + type_ipc_handle, + (void **) + array_pp); + else + return rsbac_ta_list_count(ta_number, + type_ipc_handle); + case RI_type_user_name: + if (array_pp) + return + rsbac_ta_list_get_all_desc(ta_number, + type_user_handle, + (void **) + array_pp); + else + return rsbac_ta_list_count(ta_number, + type_user_handle); + case RI_type_process_name: + if (array_pp) + return + rsbac_ta_list_get_all_desc(ta_number, + type_process_handle, + (void **) + array_pp); + else + return rsbac_ta_list_count(ta_number, + type_process_handle); + case RI_type_group_name: + if (array_pp) + return + rsbac_ta_list_get_all_desc(ta_number, + type_group_handle, + (void **) + array_pp); + else + return rsbac_ta_list_count(ta_number, + type_group_handle); + case RI_type_netdev_name: + if (array_pp) + return + rsbac_ta_list_get_all_desc(ta_number, + type_netdev_handle, + (void **) + array_pp); + else + return rsbac_ta_list_count(ta_number, + type_netdev_handle); + case RI_type_nettemp_name: + if (array_pp) + return + rsbac_ta_list_get_all_desc(ta_number, + type_nettemp_handle, + (void **) + array_pp); + else + return rsbac_ta_list_count(ta_number, + type_nettemp_handle); + case RI_type_netobj_name: + if (array_pp) + return + rsbac_ta_list_get_all_desc(ta_number, + type_netobj_handle, + (void **) + array_pp); + else + return rsbac_ta_list_count(ta_number, + type_netobj_handle); + + default: + return -RSBAC_EINVALIDATTR; + } + + default: + return -RSBAC_EINVALIDTARGET; + } +} /* end of rsbac_rc_get_list() */ + + +/* Setting values */ +int rsbac_rc_set_item(rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t tid, + union rsbac_rc_target_id_t subtid, + enum rsbac_rc_item_t item, + union rsbac_rc_item_value_t value, rsbac_time_t ttl) +{ + int err = 0; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_rc_set_item(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + if (in_interrupt()) { + rsbac_printk(KERN_WARNING "rsbac_rc_set_item(): called from interrupt!\n"); + } + switch (target) { + case RT_ROLE: + if (tid.role > RC_role_max_value) + return (-RSBAC_EINVALIDTARGET); + if ((item != RI_name) + && !rsbac_ta_list_exist(ta_number, role_handle, + &tid.role) + ) + return (-RSBAC_EINVALIDTARGET); + rsbac_pr_debug(ds_rc, "Setting role item value\n"); + switch (item) { + case RI_role_comp: + if (value.comp) { + return + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_rc_handle, + ttl, + &tid.role, + &subtid. + role, + NULL); + } else { + rsbac_ta_list_lol_subremove(ta_number, + role_rc_handle, + &tid.role, + &subtid.role); + return 0; + } + case RI_admin_roles: + if (value.comp) { + return + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_adr_handle, + ttl, + &tid.role, + &subtid. + role, + NULL); + } else { + rsbac_ta_list_lol_subremove(ta_number, + role_adr_handle, + &tid.role, + &subtid.role); + return 0; + } + case RI_assign_roles: + if (value.comp) { + return + rsbac_ta_list_lol_subadd_ttl(ta_number, + role_asr_handle, + ttl, + &tid.role, + &subtid. + role, + NULL); + } else { + rsbac_ta_list_lol_subremove(ta_number, + role_asr_handle, + &tid.role, + &subtid.role); + return 0; + } + case RI_type_comp_fd: + if (!rsbac_ta_list_exist + (ta_number, type_fd_handle, &subtid.type)) + return -RSBAC_EINVALIDVALUE; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcfd_handle, + ttl, + &tid.role, + &subtid.type, + &value.rights); + case RI_type_comp_dev: + if (!rsbac_ta_list_exist + (ta_number, type_dev_handle, &subtid.type)) + return -RSBAC_EINVALIDVALUE; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcdv_handle, + ttl, + &tid.role, + &subtid.type, + &value.rights); + case RI_type_comp_user: + if (!rsbac_ta_list_exist + (ta_number, type_user_handle, &subtid.type)) + return -RSBAC_EINVALIDVALUE; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcus_handle, + ttl, + &tid.role, + &subtid.type, + &value.rights); + case RI_type_comp_process: + if (!rsbac_ta_list_exist + (ta_number, type_process_handle, &subtid.type)) + return -RSBAC_EINVALIDVALUE; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcpr_handle, + ttl, + &tid.role, + &subtid.type, + &value.rights); + case RI_type_comp_ipc: + if (!rsbac_ta_list_exist + (ta_number, type_ipc_handle, &subtid.type)) + return -RSBAC_EINVALIDVALUE; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcip_handle, + ttl, + &tid.role, + &subtid.type, + &value.rights); + case RI_type_comp_scd: + if ((subtid.type >= ST_none) + && (subtid.type < RST_min) + ) + return -RSBAC_EINVALIDVALUE; + if (subtid.type >= RST_none) + return -RSBAC_EINVALIDVALUE; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcsc_handle, + ttl, + &tid.role, + &subtid.type, + &value.rights); + case RI_type_comp_group: + if (!rsbac_ta_list_exist + (ta_number, type_group_handle, &subtid.type)) + return -RSBAC_EINVALIDVALUE; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcgr_handle, + ttl, + &tid.role, + &subtid.type, + &value.rights); + case RI_type_comp_netdev: + if (!rsbac_ta_list_exist + (ta_number, type_netdev_handle, &subtid.type)) + return -RSBAC_EINVALIDVALUE; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcnd_handle, + ttl, + &tid.role, + &subtid.type, + &value.rights); + case RI_type_comp_nettemp: + if (!rsbac_ta_list_exist + (ta_number, type_nettemp_handle, &subtid.type)) + return -RSBAC_EINVALIDVALUE; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcnt_handle, + ttl, + &tid.role, + &subtid.type, + &value.rights); + case RI_type_comp_netobj: + if (!rsbac_ta_list_exist + (ta_number, type_netobj_handle, &subtid.type)) + return -RSBAC_EINVALIDVALUE; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + role_tcno_handle, + ttl, + &tid.role, + &subtid.type, + &value.rights); + case RI_admin_type: + { + struct rsbac_rc_role_entry_t entry; + + err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, + NULL, + &tid.role, + &entry); + if (err) + return err; + entry.admin_type = value.admin_type; + return rsbac_ta_list_add_ttl(ta_number, + role_handle, + 0, &tid.role, + &entry); + } + case RI_name: + { + struct rsbac_rc_role_entry_t entry; + + /* no empty names */ + if (!value.name[0]) + return -RSBAC_EINVALIDVALUE; + /* create, if necessary, and set name */ + memset(&entry, 0, + sizeof(struct + rsbac_rc_role_entry_t)); + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, + NULL, &tid.role, + &entry); + strncpy(entry.name, value.name, + RSBAC_RC_NAME_LEN - 1); + entry.name[RSBAC_RC_NAME_LEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, + role_handle, + 0, &tid.role, + &entry); + } + case RI_remove_role: + if (!tid.role) + return -RSBAC_EINVALIDVALUE; + /* remove role compat. */ + rsbac_ta_list_lol_remove(ta_number, role_rc_handle, + &tid.role); + /* remove from other roles' role compat */ + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_rc_handle, + &tid.role); + + /* remove admin roles */ + rsbac_ta_list_lol_remove(ta_number, + role_adr_handle, + &tid.role); + /* remove from other roles' admin roles */ + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_adr_handle, + &tid.role); + + /* remove assign roles */ + rsbac_ta_list_lol_remove(ta_number, + role_asr_handle, + &tid.role); + /* remove from other roles' assign roles */ + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_asr_handle, + &tid.role); + + /* remove def_fd_ind_create_type */ + rsbac_ta_list_lol_remove(ta_number, + role_dfdc_handle, + &tid.role); + + /* remove type compatibilities */ + rsbac_ta_list_lol_remove(ta_number, + role_tcfd_handle, + &tid.role); + rsbac_ta_list_lol_remove(ta_number, + role_tcdv_handle, + &tid.role); + rsbac_ta_list_lol_remove(ta_number, + role_tcus_handle, + &tid.role); + rsbac_ta_list_lol_remove(ta_number, + role_tcpr_handle, + &tid.role); + rsbac_ta_list_lol_remove(ta_number, + role_tcip_handle, + &tid.role); + rsbac_ta_list_lol_remove(ta_number, + role_tcsc_handle, + &tid.role); + rsbac_ta_list_lol_remove(ta_number, + role_tcgr_handle, + &tid.role); + rsbac_ta_list_lol_remove(ta_number, + role_tcnd_handle, + &tid.role); + rsbac_ta_list_lol_remove(ta_number, + role_tcnt_handle, + &tid.role); + rsbac_ta_list_lol_remove(ta_number, + role_tcno_handle, + &tid.role); + +#ifdef CONFIG_RSBAC_ACL + /* remove ACL entries */ + { + struct rsbac_acl_entry_desc_t desc; + + desc.subj_type = ACLS_ROLE; + desc.subj_id = tid.role; + rsbac_acl_remove_subject(ta_number, desc); + } +#endif + + return rsbac_ta_list_remove(ta_number, role_handle, + &tid.role); + + case RI_def_fd_create_type: + { + struct rsbac_rc_role_entry_t entry; + + if ((value.type_id <= RC_type_max_value) + && !rsbac_ta_list_exist(ta_number, + type_fd_handle, + &value.type_id) + ) + return -RSBAC_EINVALIDVALUE; + if ((value.type_id > RC_type_max_value) + && (value.type_id < + RC_type_min_special) + ) + return -RSBAC_EINVALIDVALUE; + err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, + NULL, + &tid.role, + &entry); + if (err) + return err; + entry.def_fd_create_type = value.type_id; + return rsbac_ta_list_add_ttl(ta_number, + role_handle, + 0, &tid.role, + &entry); + } + case RI_def_fd_ind_create_type: + if ((value.type_id <= RC_type_max_value) + && !rsbac_ta_list_exist(ta_number, + type_fd_handle, + &value.type_id) + ) + return -RSBAC_EINVALIDVALUE; + if ((value.type_id > RC_type_max_value) + && (value.type_id < RC_type_min_special) + ) + return -RSBAC_EINVALIDVALUE; + return rsbac_ta_list_lol_subadd_ttl(ta_number, + role_dfdc_handle, + ttl, + &tid.role, + &subtid.type, + &value. + type_id); + case RI_def_fd_ind_create_type_remove: + return rsbac_ta_list_lol_subremove(ta_number, + role_dfdc_handle, + &tid.role, + &subtid.type); + + case RI_def_user_create_type: + { + struct rsbac_rc_role_entry_t entry; + + if ((value.type_id <= RC_type_max_value) + && !rsbac_ta_list_exist(ta_number, + type_user_handle, + &value.type_id) + ) + return -RSBAC_EINVALIDVALUE; + if ((value.type_id > RC_type_max_value) + && (value.type_id < + RC_type_min_special) + ) + return -RSBAC_EINVALIDVALUE; + err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, + NULL, + &tid.role, + &entry); + if (err) + return err; + entry.def_user_create_type = value.type_id; + return rsbac_ta_list_add_ttl(ta_number, + role_handle, + 0, &tid.role, + &entry); + } + case RI_def_process_create_type: + { + struct rsbac_rc_role_entry_t entry; + + if ((value.type_id <= RC_type_max_value) + && !rsbac_ta_list_exist(ta_number, + type_process_handle, + &value.type_id) + ) + return -RSBAC_EINVALIDVALUE; + if ((value.type_id > RC_type_max_value) + && (value.type_id < + RC_type_min_special) + ) + return -RSBAC_EINVALIDVALUE; + err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, + NULL, + &tid.role, + &entry); + if (err) + return err; + entry.def_process_create_type = + value.type_id; + return rsbac_ta_list_add_ttl(ta_number, + role_handle, + 0, &tid.role, + &entry); + } + case RI_def_process_chown_type: + { + struct rsbac_rc_role_entry_t entry; + + if ((value.type_id <= RC_type_max_value) + && !rsbac_ta_list_exist(ta_number, + type_process_handle, + &value.type_id) + ) + return -RSBAC_EINVALIDVALUE; + if ((value.type_id > RC_type_max_value) + && (value.type_id < + RC_type_min_special) + ) + return -RSBAC_EINVALIDVALUE; + err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, + NULL, + &tid.role, + &entry); + if (err) + return err; + entry.def_process_chown_type = + value.type_id; + return rsbac_ta_list_add_ttl(ta_number, + role_handle, + 0, &tid.role, + &entry); + } + case RI_def_process_execute_type: + { + struct rsbac_rc_role_entry_t entry; + + if ((value.type_id <= RC_type_max_value) + && !rsbac_ta_list_exist(ta_number, + type_process_handle, + &value.type_id) + ) + return -RSBAC_EINVALIDVALUE; + if ((value.type_id > RC_type_max_value) + && (value.type_id < + RC_type_min_special) + ) + return -RSBAC_EINVALIDVALUE; + err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, + NULL, + &tid.role, + &entry); + if (err) + return err; + entry.def_process_execute_type = + value.type_id; + return rsbac_ta_list_add_ttl(ta_number, + role_handle, + 0, &tid.role, + &entry); + } + case RI_def_ipc_create_type: + { + struct rsbac_rc_role_entry_t entry; + + if ((value.type_id <= RC_type_max_value) + && !rsbac_ta_list_exist(ta_number, + type_ipc_handle, + &value.type_id) + ) + return -RSBAC_EINVALIDVALUE; + if ((value.type_id > RC_type_max_value) + && (value.type_id < + RC_type_min_special) + ) + return -RSBAC_EINVALIDVALUE; + err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, + NULL, + &tid.role, + &entry); + if (err) + return err; + entry.def_ipc_create_type = value.type_id; + return rsbac_ta_list_add_ttl(ta_number, + role_handle, + 0, &tid.role, + &entry); + } + case RI_def_group_create_type: + { + struct rsbac_rc_role_entry_t entry; + + if ((value.type_id <= RC_type_max_value) + && !rsbac_ta_list_exist(ta_number, + type_group_handle, + &value.type_id) + ) + return -RSBAC_EINVALIDVALUE; + if ((value.type_id > RC_type_max_value) + && (value.type_id < + RC_type_min_special) + ) + return -RSBAC_EINVALIDVALUE; + err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, + NULL, + &tid.role, + &entry); + if (err) + return err; + entry.def_group_create_type = + value.type_id; + return rsbac_ta_list_add_ttl(ta_number, + role_handle, + 0, &tid.role, + &entry); + } + case RI_def_unixsock_create_type: + { + struct rsbac_rc_role_entry_t entry; + + if ((value.type_id <= RC_type_max_value) + && !rsbac_ta_list_exist(ta_number, + type_fd_handle, + &value.type_id) + ) + return -RSBAC_EINVALIDVALUE; + if ((value.type_id > RC_type_max_value) + && (value.type_id < + RC_type_min_special) + ) + return -RSBAC_EINVALIDVALUE; + err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, + NULL, + &tid.role, + &entry); + if (err) + return err; + entry.def_unixsock_create_type = + value.type_id; + return rsbac_ta_list_add_ttl(ta_number, + role_handle, + 0, &tid.role, + &entry); + } + case RI_boot_role: + { + struct rsbac_rc_role_entry_t entry; + + err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, + NULL, + &tid.role, + &entry); + if (err) + return err; + entry.boot_role = value.boot_role; + return rsbac_ta_list_add_ttl(ta_number, + role_handle, + 0, &tid.role, + &entry); + } + case RI_req_reauth: + { + struct rsbac_rc_role_entry_t entry; + + err = + rsbac_ta_list_get_data_ttl(ta_number, + role_handle, + NULL, + &tid.role, + &entry); + if (err) + return err; + entry.req_reauth = value.req_reauth; +// printk(KERN_WARNING "entry %u value %u\n", +// entry.req_reauth, value.req_reauth); + return rsbac_ta_list_add_ttl(ta_number, + role_handle, + 0, &tid.role, + &entry); + } + + default: + return -RSBAC_EINVALIDATTR; + } + + case RT_TYPE: + if (tid.type > RC_type_max_value) + return (-RSBAC_EINVALIDTARGET); + rsbac_pr_debug(ds_rc, "Setting type item value\n"); + switch (item) { + case RI_type_fd_name: + { + struct rsbac_rc_type_fd_entry_t entry; + + /* no empty names */ + if (!value.name[0]) + return -RSBAC_EINVALIDVALUE; + /* create, if necessary, and set name */ + memset(&entry, 0, + sizeof(struct + rsbac_rc_type_fd_entry_t)); + rsbac_ta_list_get_data_ttl(ta_number, + type_fd_handle, + NULL, &tid.type, + &entry); + strncpy(entry.name, value.name, + RSBAC_RC_NAME_LEN - 1); + entry.name[RSBAC_RC_NAME_LEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, + type_fd_handle, + 0, &tid.type, + &entry); + } + case RI_type_fd_need_secdel: + { + struct rsbac_rc_type_fd_entry_t entry; + + err = + rsbac_ta_list_get_data_ttl(ta_number, + type_fd_handle, + NULL, + &tid.type, + &entry); + if (err) + return err; + entry.need_secdel = value.need_secdel; + return rsbac_ta_list_add_ttl(ta_number, + type_fd_handle, + 0, &tid.type, + &entry); + } + case RI_type_dev_name: + /* no empty names */ + if (!value.name[0]) + return -RSBAC_EINVALIDVALUE; + /* create, if necessary, and set name */ + value.name[RSBAC_RC_NAME_LEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, + type_dev_handle, 0, + &tid.type, + &value.name); + case RI_type_ipc_name: + /* no empty names */ + if (!value.name[0]) + return -RSBAC_EINVALIDVALUE; + /* create, if necessary, and set name */ + value.name[RSBAC_RC_NAME_LEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, + type_ipc_handle, 0, + &tid.type, + &value.name); + case RI_type_user_name: + /* no empty names */ + if (!value.name[0]) + return -RSBAC_EINVALIDVALUE; + /* create, if necessary, and set name */ + value.name[RSBAC_RC_NAME_LEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, + type_user_handle, 0, + &tid.type, + &value.name); + case RI_type_process_name: + /* no empty names */ + if (!value.name[0]) + return -RSBAC_EINVALIDVALUE; + /* create, if necessary, and set name */ + value.name[RSBAC_RC_NAME_LEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, + type_process_handle, + 0, &tid.type, + &value.name); + case RI_type_group_name: + /* no empty names */ + if (!value.name[0]) + return -RSBAC_EINVALIDVALUE; + /* create, if necessary, and set name */ + value.name[RSBAC_RC_NAME_LEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, + type_group_handle, 0, + &tid.type, + &value.name); + case RI_type_netdev_name: + /* no empty names */ + if (!value.name[0]) + return -RSBAC_EINVALIDVALUE; + /* create, if necessary, and set name */ + value.name[RSBAC_RC_NAME_LEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, + type_netdev_handle, 0, + &tid.type, + &value.name); + case RI_type_nettemp_name: + /* no empty names */ + if (!value.name[0]) + return -RSBAC_EINVALIDVALUE; + /* create, if necessary, and set name */ + value.name[RSBAC_RC_NAME_LEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, + type_nettemp_handle, + 0, &tid.type, + &value.name); + case RI_type_netobj_name: + /* no empty names */ + if (!value.name[0]) + return -RSBAC_EINVALIDVALUE; + /* create, if necessary, and set name */ + value.name[RSBAC_RC_NAME_LEN - 1] = 0; + return rsbac_ta_list_add_ttl(ta_number, + type_netobj_handle, 0, + &tid.type, + &value.name); + + case RI_type_fd_remove: + if (!tid.type) + return -RSBAC_EINVALIDVALUE; + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_tcfd_handle, + &tid.type); + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_dfdc_handle, + &tid.type); + return rsbac_ta_list_remove(ta_number, + type_fd_handle, + &tid.type); + case RI_type_dev_remove: + if (!tid.type) + return -RSBAC_EINVALIDVALUE; + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_tcdv_handle, + &tid.type); + return rsbac_ta_list_remove(ta_number, + type_dev_handle, + &tid.type); + case RI_type_user_remove: + if (!tid.type) + return -RSBAC_EINVALIDVALUE; + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_tcus_handle, + &tid.type); + return rsbac_ta_list_remove(ta_number, + type_user_handle, + &tid.type); + case RI_type_process_remove: + if (!tid.type) + return -RSBAC_EINVALIDVALUE; + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_tcpr_handle, + &tid.type); + return rsbac_ta_list_remove(ta_number, + type_process_handle, + &tid.type); + case RI_type_ipc_remove: + if (!tid.type) + return -RSBAC_EINVALIDVALUE; + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_tcip_handle, + &tid.type); + return rsbac_ta_list_remove(ta_number, + type_ipc_handle, + &tid.type); + case RI_type_group_remove: + if (!tid.type) + return -RSBAC_EINVALIDVALUE; + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_tcgr_handle, + &tid.type); + return rsbac_ta_list_remove(ta_number, + type_group_handle, + &tid.type); + case RI_type_netdev_remove: + if (!tid.type) + return -RSBAC_EINVALIDVALUE; + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_tcnd_handle, + &tid.type); + return rsbac_ta_list_remove(ta_number, + type_netdev_handle, + &tid.type); + case RI_type_nettemp_remove: + if (!tid.type) + return -RSBAC_EINVALIDVALUE; + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_tcnt_handle, + &tid.type); + return rsbac_ta_list_remove(ta_number, + type_nettemp_handle, + &tid.type); + case RI_type_netobj_remove: + if (!tid.type) + return -RSBAC_EINVALIDVALUE; + rsbac_ta_list_lol_subremove_from_all(ta_number, + role_tcno_handle, + &tid.type); + return rsbac_ta_list_remove(ta_number, + type_netobj_handle, + &tid.type); + + default: + return -RSBAC_EINVALIDATTR; + } + + /* switch target: no valid target */ + default: + return -RSBAC_EINVALIDTARGET; + } +} diff --git a/rsbac/data_structures/um_data_structures.c b/rsbac/data_structures/um_data_structures.c new file mode 100644 index 000000000000..7023a73e360b --- /dev/null +++ b/rsbac/data_structures/um_data_structures.c @@ -0,0 +1,2479 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of User Management data structures */ +/* Author and (c) 1999-2017: Amon Ott */ +/* */ +/* Last modified: 11/Jan/2017 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_RSBAC_UM_DIGEST +#include +#include +#endif +#include +#include + +/************************************************************************** */ +/* Global Variables */ +/************************************************************************** */ + +static rsbac_list_handle_t user_handle; +static rsbac_list_handle_t group_handle; +#ifdef CONFIG_RSBAC_UM_PWHISTORY +static rsbac_list_handle_t user_pwhistory_handle; +#endif +#ifdef CONFIG_RSBAC_UM_ONETIME +static rsbac_list_handle_t onetime_handle; +#endif +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +static rsbac_list_handle_t uid_cache_handle; +static rsbac_list_handle_t gid_cache_handle; +u_long uid_cache_hits = 0; +u_long uid_cache_misses = 0; +u_long gid_cache_hits = 0; +u_long gid_cache_misses = 0; +#endif +#define EXTRA_ROOM 20 + +/**************************************************/ +/* Declarations of external functions */ +/**************************************************/ + +/**************************************************/ +/* Declarations of internal functions */ +/**************************************************/ + +/************************************************* */ +/* Internal Help functions */ +/************************************************* */ + +static u_int nr_user_hash_bits = RSBAC_UM_NR_USER_LIST_HASH_BITS; +static u_int nr_group_hash_bits = RSBAC_UM_NR_GROUP_LIST_HASH_BITS; + +#ifdef CONFIG_RSBAC_UM_PWHISTORY +static u_int nr_user_pwhistory_hash_bits = RSBAC_UM_NR_USER_PWHISTORY_LIST_HASH_BITS; +#endif + +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +static u_int nr_uid_cache_hash_bits = RSBAC_UM_NR_NAME_CACHE_LIST_HASH_BITS; +static u_int nr_gid_cache_hash_bits = RSBAC_UM_NR_NAME_CACHE_LIST_HASH_BITS; +#endif + +static int user_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_um_user_entry_t * new_aci = new_data; + struct rsbac_um_old_user_entry_t * old_aci = old_data; + + memcpy(&new_aci->name, &old_aci->name, RSBAC_UM_OLD_NAME_LEN); + memcpy(&new_aci->pass, &old_aci->pass, RSBAC_UM_PASS_LEN); + memcpy(&new_aci->fullname, &old_aci->fullname, RSBAC_UM_OLD_FULLNAME_LEN); + memcpy(&new_aci->homedir, &old_aci->homedir, RSBAC_UM_OLD_HOMEDIR_LEN); + memcpy(&new_aci->shell, &old_aci->shell, RSBAC_UM_OLD_SHELL_LEN); + new_aci->group = old_aci->group; + new_aci->lastchange = old_aci->lastchange; + new_aci->minchange = old_aci->minchange; + new_aci->maxchange = old_aci->maxchange; + new_aci->warnchange = old_aci->warnchange; + new_aci->inactive = old_aci->inactive; + new_aci->expire = old_aci->expire; + *((rsbac_uid_t *)new_desc) = *((rsbac_uid_t *)old_desc); + return 0; +} + +static int user_old_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_um_user_entry_t * new_aci = new_data; + struct rsbac_um_old_user_entry_t * old_aci = old_data; + + memcpy(&new_aci->name, &old_aci->name, RSBAC_UM_OLD_NAME_LEN); + memcpy(&new_aci->pass, &old_aci->pass, RSBAC_UM_PASS_LEN); + memcpy(&new_aci->fullname, &old_aci->fullname, RSBAC_UM_OLD_FULLNAME_LEN); + memcpy(&new_aci->homedir, &old_aci->homedir, RSBAC_UM_OLD_HOMEDIR_LEN); + memcpy(&new_aci->shell, &old_aci->shell, RSBAC_UM_OLD_SHELL_LEN); + new_aci->group = old_aci->group; + new_aci->lastchange = old_aci->lastchange; + new_aci->minchange = old_aci->minchange; + new_aci->maxchange = old_aci->maxchange; + new_aci->warnchange = old_aci->warnchange; + new_aci->inactive = old_aci->inactive; + new_aci->expire = old_aci->expire; + *((rsbac_uid_t *)new_desc) = *((rsbac_old_uid_t *)old_desc); + return 0; +} + +rsbac_list_conv_function_t *user_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_UM_USER_OLD_LIST_VERSION: + return user_conv; + case RSBAC_UM_USER_OLD_OLD_LIST_VERSION: + return user_old_conv; + default: + return NULL; + } +} + +static int user_subconv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + *((rsbac_gid_num_t *)new_desc) = *((rsbac_gid_num_t *)old_desc); + return 0; +} + +static int user_old_subconv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + *((rsbac_gid_num_t *)new_desc) = *((rsbac_old_gid_t *)old_desc); + return 0; +} + +rsbac_list_conv_function_t *user_get_subconv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_UM_USER_OLD_LIST_VERSION: + return user_subconv; + case RSBAC_UM_USER_OLD_OLD_LIST_VERSION: + return user_old_subconv; + default: + return NULL; + } +} + +static int group_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_um_group_entry_t * new_aci = new_data; + struct rsbac_um_old_group_entry_t * old_aci = old_data; + + memcpy(&new_aci->name, &old_aci->name, RSBAC_UM_OLD_NAME_LEN); + memcpy(&new_aci->pass, &old_aci->pass, RSBAC_UM_PASS_LEN); + *((rsbac_gid_t *)new_desc) = *((rsbac_gid_t *)old_desc); + return 0; +} + +static int group_old_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + struct rsbac_um_group_entry_t * new_aci = new_data; + struct rsbac_um_old_group_entry_t * old_aci = old_data; + + memcpy(&new_aci->name, &old_aci->name, RSBAC_UM_OLD_NAME_LEN); + memcpy(&new_aci->pass, &old_aci->pass, RSBAC_UM_PASS_LEN); + *((rsbac_gid_t *)new_desc) = *((rsbac_old_gid_t *)old_desc); + return 0; +} + +rsbac_list_conv_function_t *group_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_UM_GROUP_OLD_LIST_VERSION: + return group_conv; + case RSBAC_UM_GROUP_OLD_OLD_LIST_VERSION: + return group_old_conv; + default: + return NULL; + } +} + +static int user_pwh_conv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + memcpy(new_data, old_data, sizeof(__u8)); + *((rsbac_uid_t *) new_desc) = *((rsbac_old_uid_t *) old_desc); + return 0; +} + +rsbac_list_conv_function_t *user_pwh_get_conv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_UM_USER_PWHISTORY_OLD_LIST_VERSION: + return user_pwh_conv; + default: + return NULL; + } +} + +static int user_pwh_subconv(void *old_desc, + void *old_data, void *new_desc, void *new_data) +{ + memcpy(new_desc, old_desc, sizeof(__u32)); + memcpy(new_data, old_data, RSBAC_UM_PASS_LEN); + return 0; +} + +rsbac_list_conv_function_t *user_pwh_get_subconv(rsbac_version_t old_version) +{ + switch (old_version) { + case RSBAC_UM_USER_PWHISTORY_OLD_LIST_VERSION: + return user_pwh_subconv; + default: + return NULL; + } +} + +#ifdef CONFIG_RSBAC_UM_VIRTUAL +static int vset_selector(void *desc, void * param) +{ + if (RSBAC_UID_SET(*((rsbac_uid_t *) desc)) == *((rsbac_um_set_t *) param)) + return TRUE; + else + return FALSE; +} +#endif + +#if defined(CONFIG_RSBAC_PROC) +static int +stats_um_proc_show(struct seq_file *m, void *v) +{ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "stats_um_proc_info(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + rsbac_pr_debug(aef_um, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + seq_printf(m, "UM Status\n---------\n"); + seq_printf(m, + "%lu user items with sum of %lu group memberships, %lu group items\n", + rsbac_list_lol_count(user_handle), rsbac_list_lol_all_subcount(user_handle), rsbac_list_count(group_handle)); +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + seq_printf(m, + "user name cache: %lu cache items, %lu hits, %lu misses, hm-ratio %lu\n", + rsbac_list_count(uid_cache_handle), uid_cache_hits, uid_cache_misses, uid_cache_misses ? uid_cache_hits / uid_cache_misses : 0); + seq_printf(m, + "group name cache: %lu cache items, %lu hits, %lu misses, hm-ratio %lu\n", + rsbac_list_count(gid_cache_handle), gid_cache_hits, gid_cache_misses, gid_cache_misses ? gid_cache_hits / gid_cache_misses : 0); + seq_printf(m, + "name cache ttl is %u\n", rsbac_um_name_cache_ttl); + if (rsbac_um_name_cache_disable) + seq_printf(m, + "name cache is disabled!\n"); +#endif + return 0; +} + +static int stats_um_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, stats_um_proc_show, NULL); +} + +static const struct file_operations stats_um_proc_fops = { + .owner = THIS_MODULE, + .open = stats_um_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *stats_um; + +#endif /* CONFIG_PROC_FS && CONFIG_RSBAC_PROC */ + +static int name_compare(void *data1, void *data2) +{ + struct rsbac_um_user_entry_t *entry_p = data1; + char *name = data2; + + if (!entry_p || !name) + return 1; + + return strcmp(entry_p->name, name); +} + +static int group_name_compare(void *data1, void *data2) +{ + struct rsbac_um_group_entry_t *entry_p = data1; + char *name = data2; + + if (!entry_p || !name) + return 1; + + return strcmp(entry_p->name, name); +} + +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +#ifdef CONFIG_RSBAC_UM_VIRTUAL +static int name_cache_compare(void *data1, void *data2) +{ + struct rsbac_um_name_cache_desc_t *desc1_p = data1; + struct rsbac_um_name_cache_desc_t *desc2_p = data2; + + if (!desc1_p || !desc2_p) + return 1; + + if (desc1_p->vset < desc2_p->vset) + return -1; + else if (desc1_p->vset > desc2_p->vset) + return 1; + else + return strcmp(desc1_p->name, desc2_p->name); +} +#else +static int name_cache_compare(void *data1, void *data2) +{ + return strcmp((char *) data1, (char *) data2); +} +#endif + +u_int rsbac_list_hash_name_cache(void * desc, __u8 hash_bits) +{ + u_int hash = 0; + char * p = desc; + + while (*p) { + hash += *p; + p++; + } + return hash_32(hash, rsbac_min(hash_bits, 32)); +} +#endif + +/************************************************* */ +/* Init functions */ +/************************************************* */ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac/error.h. */ + +/************************************************************************** */ +/* Initialization of all MAC data structures. After this call, all MAC */ +/* data is kept in memory for performance reasons, but is written to disk */ +/* on every change. */ + +/* Because there can be no access to aci data structures before init, */ +/* rsbac_init_mac() will initialize all rw-spinlocks to unlocked. */ + +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_init_um(void) +#else +int __init rsbac_init_um(void) +#endif +{ + int err = 0; + struct rsbac_list_info_t *list_info_p; + struct rsbac_list_lol_info_t *lol_info_p; + + if (rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_init_um(): RSBAC already initialized\n"); + return (-RSBAC_EREINIT); + } + + /* set rw-spinlocks to unlocked status and init data structures */ + rsbac_printk(KERN_INFO "rsbac_init_um(): Initializing RSBAC: User Management subsystem\n"); + + list_info_p = rsbac_kmalloc_unlocked(sizeof(*list_info_p)); + if (!list_info_p) { + return -ENOMEM; + } + lol_info_p = rsbac_kmalloc_unlocked(sizeof(*lol_info_p)); + if (!lol_info_p) { + rsbac_kfree(list_info_p); + return -ENOMEM; + } + + lol_info_p->version = RSBAC_UM_USER_LIST_VERSION; + lol_info_p->key = RSBAC_UM_USER_LIST_KEY; + lol_info_p->desc_size = sizeof(rsbac_uid_t); + lol_info_p->data_size = sizeof(struct rsbac_um_user_entry_t); + lol_info_p->subdesc_size = sizeof(rsbac_gid_num_t); + lol_info_p->subdata_size = 0; + lol_info_p->max_age = 0; + nr_user_hash_bits = RSBAC_UM_NR_USER_LIST_HASH_BITS; + + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &user_handle, lol_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_AUTO_HASH_RESIZE | + RSBAC_LIST_OWN_SLAB, + NULL, NULL, + user_get_conv, + user_get_subconv, + NULL, NULL, + RSBAC_UM_USER_LIST_NAME, + RSBAC_AUTO_DEV, + nr_user_hash_bits, + rsbac_list_hash_uid, + RSBAC_UM_OLD_USER_LIST_NAME); + if (err) { + char *tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_um(): Registering user list of lists %s failed with error %s\n", + RSBAC_UM_USER_LIST_NAME, get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } + + list_info_p->version = RSBAC_UM_GROUP_LIST_VERSION; + list_info_p->key = RSBAC_UM_GROUP_LIST_KEY; + list_info_p->desc_size = sizeof(rsbac_gid_t); + list_info_p->data_size = sizeof(struct rsbac_um_group_entry_t); + list_info_p->max_age = 0; + nr_group_hash_bits = RSBAC_UM_NR_GROUP_LIST_HASH_BITS; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &group_handle, list_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_REPLICATE | + RSBAC_LIST_AUTO_HASH_RESIZE | + RSBAC_LIST_OWN_SLAB, + NULL, + group_get_conv, + NULL, RSBAC_UM_GROUP_LIST_NAME, + RSBAC_AUTO_DEV, + nr_group_hash_bits, + rsbac_list_hash_gid, + RSBAC_UM_OLD_GROUP_LIST_NAME); + if (err) { + char *tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_um(): Registering group list %s failed with error %s\n", + RSBAC_UM_GROUP_LIST_NAME, get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } + +#ifdef CONFIG_RSBAC_UM_PWHISTORY + { + __u8 def_max_history = CONFIG_RSBAC_UM_PWHISTORY_MAX; + + lol_info_p->version = RSBAC_UM_USER_PWHISTORY_LIST_VERSION; + lol_info_p->key = RSBAC_UM_USER_PWHISTORY_LIST_KEY; + lol_info_p->desc_size = sizeof(rsbac_uid_t); + lol_info_p->data_size = sizeof(__u8); + lol_info_p->subdesc_size = sizeof(__u32); + lol_info_p->subdata_size = RSBAC_UM_PASS_LEN; + lol_info_p->max_age = 0; + nr_user_pwhistory_hash_bits = RSBAC_UM_NR_USER_LIST_HASH_BITS; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &user_pwhistory_handle, + lol_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_AUTO_HASH_RESIZE, + NULL, NULL, + user_pwh_get_conv, user_pwh_get_subconv, + &def_max_history, NULL, + RSBAC_UM_USER_PWHISTORY_LIST_NAME, + RSBAC_AUTO_DEV, + nr_user_pwhistory_hash_bits, + rsbac_list_hash_uid, + RSBAC_UM_OLD_USER_PWHISTORY_LIST_NAME); + if (err) { + char *tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_um(): Registering user password history list of lists %s failed with error %s\n", + RSBAC_UM_USER_PWHISTORY_LIST_NAME, + get_error_name(tmp, + err)); + rsbac_kfree(tmp); + } + } + } +#endif + +#ifdef CONFIG_RSBAC_UM_ONETIME + { + lol_info_p->version = RSBAC_UM_ONETIME_LIST_VERSION; + lol_info_p->key = RSBAC_UM_ONETIME_LIST_KEY; + lol_info_p->desc_size = sizeof(rsbac_uid_t); + lol_info_p->data_size = 0; + lol_info_p->subdesc_size = RSBAC_UM_PASS_LEN; + lol_info_p->subdata_size = 0; + lol_info_p->max_age = 0; + err = rsbac_list_lol_register_hashed(RSBAC_LIST_VERSION, + &onetime_handle, + lol_info_p, +#ifdef CONFIG_RSBAC_DEV_USER_BACKUP + RSBAC_LIST_BACKUP | +#endif + RSBAC_LIST_PERSIST | + RSBAC_LIST_DEF_DATA | + RSBAC_LIST_AUTO_HASH_RESIZE | + RSBAC_LIST_OWN_SLAB, + NULL, NULL, + NULL, NULL, /* conv */ + NULL, NULL, + RSBAC_UM_ONETIME_LIST_NAME, + RSBAC_AUTO_DEV, + 1, + rsbac_list_hash_uid, + NULL); + if (err) { + char *tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_um(): Registering user password one-time list of lists %s failed with error %s\n", + RSBAC_UM_USER_PWHISTORY_LIST_NAME, + get_error_name(tmp, + err)); + rsbac_kfree(tmp); + } + } else { + rsbac_list_lol_max_items(onetime_handle, + RSBAC_UM_ONETIME_LIST_KEY, + RSBAC_LIST_MAX_NR_ITEMS, + CONFIG_RSBAC_UM_ONETIME_MAX); + } + } +#endif + +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + list_info_p->version = RSBAC_UM_NAME_CACHE_LIST_VERSION; + list_info_p->key = RSBAC_UM_UID_CACHE_LIST_KEY; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + list_info_p->desc_size = sizeof(struct rsbac_um_name_cache_desc_t); +#else + list_info_p->desc_size = RSBAC_UM_NAME_LEN; +#endif + list_info_p->data_size = sizeof(rsbac_uid_t); + list_info_p->max_age = 0; + nr_uid_cache_hash_bits = RSBAC_UM_NR_NAME_CACHE_LIST_HASH_BITS; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &uid_cache_handle, list_info_p, + RSBAC_LIST_AUTO_HASH_RESIZE | + RSBAC_LIST_OWN_SLAB, + name_cache_compare, + NULL, + NULL, RSBAC_UM_UID_CACHE_LIST_NAME, + RSBAC_AUTO_DEV, + nr_uid_cache_hash_bits, + rsbac_list_hash_name_cache, + NULL); + if (err) { + char *tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_um(): Registering user name cache list %s failed with error %s\n", + RSBAC_UM_UID_CACHE_LIST_NAME, get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } + + list_info_p->version = RSBAC_UM_NAME_CACHE_LIST_VERSION; + list_info_p->key = RSBAC_UM_GID_CACHE_LIST_KEY; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + list_info_p->desc_size = sizeof(struct rsbac_um_name_cache_desc_t); +#else + list_info_p->desc_size = RSBAC_UM_NAME_LEN; +#endif + list_info_p->data_size = sizeof(rsbac_gid_t); + list_info_p->max_age = 0; + nr_gid_cache_hash_bits = RSBAC_UM_NR_NAME_CACHE_LIST_HASH_BITS; + err = rsbac_list_register_hashed(RSBAC_LIST_VERSION, + &gid_cache_handle, list_info_p, + RSBAC_LIST_AUTO_HASH_RESIZE | + RSBAC_LIST_OWN_SLAB, + name_cache_compare, + NULL, + NULL, RSBAC_UM_GID_CACHE_LIST_NAME, + RSBAC_AUTO_DEV, + nr_gid_cache_hash_bits, + rsbac_list_hash_name_cache, + NULL); + if (err) { + char *tmp = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + + if (tmp) { + rsbac_printk(KERN_WARNING "rsbac_init_um(): Registering group name cache list %s failed with error %s\n", + RSBAC_UM_GID_CACHE_LIST_NAME, get_error_name(tmp, err)); + rsbac_kfree(tmp); + } + } +#endif + +#if defined(CONFIG_RSBAC_PROC) + stats_um = proc_create("stats_um", S_IFREG | S_IRUGO, + proc_rsbac_root_p, &stats_um_proc_fops); +#endif + + rsbac_pr_debug(ds_um, "Ready.\n"); + rsbac_kfree(list_info_p); + rsbac_kfree(lol_info_p); + return err; +} + +/***************************************************/ +/* We also need some status information... */ + +int rsbac_stats_um(void) +{ + u_long user_count; + u_long group_count; + u_long member_count; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_stats_um(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + rsbac_pr_debug(aef_um, "calling ADF\n"); + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, rsbac_attribute_value)) { + return -EPERM; + } + + user_count = rsbac_list_lol_count(user_handle); + member_count = rsbac_list_lol_all_subcount(user_handle); + group_count = rsbac_list_count(group_handle); + rsbac_printk(KERN_INFO "UM Status\n---------\n"); + + rsbac_printk(KERN_INFO "%lu user items with sum of %lu group memberships, %lu group items\n", + user_count, member_count, group_count); + return 0; +} + +/************************************************* */ +/* Access functions */ +/************************************************* */ + +/* Trying to access a never created or removed user entry returns an error! */ +#ifndef offset_in_page +#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) +#endif + +static inline void new_salt(__u32 * salt_p) +{ + *salt_p = 0; + while (!*salt_p) + get_random_bytes(salt_p, sizeof(*salt_p)); +} + +int rsbac_um_hash(char *pass, __u32 salt) +{ +#ifdef CONFIG_RSBAC_UM_DIGEST + char *buffer; + struct crypto_shash *tfm; + u_int len; + u_int plen; + int err = 0; + + plen = strlen(pass); + len = rsbac_max(plen + sizeof(salt), RSBAC_UM_PASS_LEN); + + if (!crypto_has_alg("sha1", 0, 0)) { + rsbac_printk(KERN_WARNING "rsbac_um_hash(): User management configured for crypto API with SHA1, but SHA1 is not available!\n"); + return -RSBAC_ENOTFOUND; + } + tfm = crypto_alloc_shash("sha1", 0, 0); + if (!tfm || IS_ERR(tfm)) { + rsbac_printk(KERN_WARNING "pid %u(%s): rsbac_um_hash(): Could not allocate tfm for SHA1, error %i!\n", + current->pid, current->comm, PTR_ERR(tfm)); + return -RSBAC_ENOTFOUND; + } + + buffer = rsbac_kmalloc_unlocked(len); + if (!buffer) { + crypto_free_shash(tfm); + return -RSBAC_ENOMEM; + } + memset(buffer, 0, len); + memcpy(buffer, &salt, sizeof(salt)); + memcpy(buffer + sizeof(salt), pass, plen); + + { + SHASH_DESC_ON_STACK(shash, tfm); + u32 *ctx = (u32 *)shash_desc_ctx(shash); + shash->tfm = tfm; + shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP; + *ctx = salt; + + err = crypto_shash_init(shash); + if (err) { + rsbac_printk(KERN_WARNING "pid %u(%s): rsbac_um_hash(): crypto_shash_init() failed with error %u!\n", + current->pid, current->comm, err); + goto out; + } + err = crypto_shash_update(shash, buffer, sizeof(salt) + plen); + if (err) { + rsbac_printk(KERN_WARNING "pid %u(%s): rsbac_um_hash(): crypto_shash_update() failed with error %u!\n", + current->pid, current->comm, err); + goto out; + } + err = crypto_shash_final(shash, pass); + if (err) { + rsbac_printk(KERN_WARNING "pid %u(%s): rsbac_um_hash(): crypto_shash_final() failed with error %u!\n", + current->pid, current->comm, err); +// goto out; + } + } + +out: + crypto_free_shash(tfm); + rsbac_kfree(buffer); + + return err; +#else + /* no crypto: just zero rest of string to allow comparizon */ + u_int len; + + len = strlen(pass); + if (len < RSBAC_UM_PASS_LEN) + memset(pass + len, 0, RSBAC_UM_PASS_LEN - len); + return 0; +#endif +} + +int rsbac_um_get_uid(rsbac_list_ta_number_t ta_number, + char *name, + rsbac_uid_t * uid_p) +{ + int err; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + rsbac_um_set_t vset; +#endif +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + rsbac_time_t ttl; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + struct rsbac_um_name_cache_desc_t cache_desc; +#endif +#endif + + if (!name || !uid_p) + return -RSBAC_EINVALIDPOINTER; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + vset = RSBAC_UID_SET(*uid_p); + if (vset == RSBAC_UM_VIRTUAL_KEEP) { + char * p = name; + + while (*p && (*p != '/')) + p++; + if (*p) { + *p = 0; + err = rsbac_get_vset_num(name, &vset); + if (err) + return err; + p++; + name = p; + if (vset == RSBAC_UM_VIRTUAL_KEEP) + vset = rsbac_get_vset(); + } else + vset = rsbac_get_vset(); + } + if (!strcmp(name, "ALL")) { + *uid_p = RSBAC_GEN_UID(vset, RSBAC_ALL_USERS); + return 0; + } +#endif + +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + if (!rsbac_um_name_cache_disable) { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (vset != RSBAC_UM_VIRTUAL_ALL) + cache_desc.vset = vset; + else + cache_desc.vset = 0; + memcpy(cache_desc.name, name, RSBAC_UM_NAME_LEN); + if (!rsbac_ta_list_get_data_ttl(ta_number, + uid_cache_handle, + &ttl, &cache_desc, uid_p)) { + rsbac_pr_debug(aef_um, "pid %u(%s): user %u/%u (%s) found in name cache with ttl %u\n", + current->pid, current->comm, RSBAC_UID_SET(*uid_p), RSBAC_UID_NUM(*uid_p), cache_desc.name, ttl); + uid_cache_hits++; + return 0; + } +#else + if (!rsbac_ta_list_get_data_ttl(ta_number, + uid_cache_handle, + &ttl, name, uid_p)) { + rsbac_pr_debug(aef_um, "pid %u(%s): user %u (%s) found in name cache with ttl %u\n", + current->pid, current->comm, RSBAC_UID_NUM(*uid_p), name, ttl); + uid_cache_hits++; + return 0; + } +#endif + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (vset != RSBAC_UM_VIRTUAL_ALL) + err = rsbac_ta_list_lol_get_desc_selector_ttl(ta_number, + user_handle, +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + &ttl, +#else + NULL, +#endif + uid_p, + name, + name_compare, + vset_selector, + &vset); + else +#endif + err = rsbac_ta_list_lol_get_desc_ttl(ta_number, + user_handle, +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + &ttl, +#else + NULL, +#endif + uid_p, + name, + name_compare); + + if (!err) { +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + if (!rsbac_um_name_cache_disable) { + if (ttl > 0) + ttl = rsbac_min(ttl, rsbac_um_name_cache_ttl); + else + ttl = rsbac_um_name_cache_ttl; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (vset != RSBAC_UM_VIRTUAL_ALL) + cache_desc.vset = vset; + else + cache_desc.vset = 0; + memcpy(cache_desc.name, name, RSBAC_UM_NAME_LEN); + rsbac_ta_list_add_ttl(ta_number, + uid_cache_handle, + ttl, + &cache_desc, uid_p); + rsbac_pr_debug(aef_um, "pid %u(%s): user %u/%u (%s) added to name cache with ttl %u\n", + current->pid, current->comm, RSBAC_UID_SET(*uid_p), RSBAC_UID_NUM(*uid_p), cache_desc.name, ttl); + uid_cache_misses++; +#else + rsbac_ta_list_add_ttl(ta_number, + uid_cache_handle, + ttl, + name, uid_p); + rsbac_pr_debug(aef_um, "pid %u(%s): user %u (%s) added to name cache with ttl %u\n", + current->pid, current->comm, RSBAC_UID_NUM(*uid_p), name, ttl); + uid_cache_misses++; +#endif + } +#endif + + return 0; + } else + return -RSBAC_ENOTFOUND; +} + +int rsbac_um_get_gid(rsbac_list_ta_number_t ta_number, + char *name, rsbac_gid_t * gid_p) +{ + int err; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + rsbac_um_set_t vset; +#endif +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + rsbac_time_t ttl; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + struct rsbac_um_name_cache_desc_t cache_desc; +#endif +#endif + + if (!name || !gid_p) + return -RSBAC_EINVALIDPOINTER; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + vset = RSBAC_GID_SET(*gid_p); + if (vset == RSBAC_UM_VIRTUAL_KEEP) { + char * p = name; + + while (*p && (*p != '/')) + p++; + if (*p) { + *p = 0; + err = rsbac_get_vset_num(name, &vset); + if (err) + return err; + p++; + name = p; + if (vset == RSBAC_UM_VIRTUAL_KEEP) + vset = rsbac_get_vset(); + } else + vset = rsbac_get_vset(); + } + if (!strcmp(name, "ALL")) { + *gid_p = RSBAC_GEN_GID(vset, RSBAC_ALL_GROUPS); + return 0; + } +#endif + +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + if (!rsbac_um_name_cache_disable) { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (vset != RSBAC_UM_VIRTUAL_ALL) + cache_desc.vset = vset; + else + cache_desc.vset = 0; + memcpy(cache_desc.name, name, RSBAC_UM_NAME_LEN); + if (!rsbac_ta_list_get_data_ttl(ta_number, + gid_cache_handle, + &ttl, &cache_desc, gid_p)) { + rsbac_pr_debug(aef_um, "pid %u(%s): group %u/%u (%s) found in name cache with ttl %u\n", + current->pid, current->comm, RSBAC_GID_SET(*gid_p), RSBAC_GID_NUM(*gid_p), cache_desc.name, ttl); + gid_cache_hits++; + return 0; + } +#else + if (!rsbac_ta_list_get_data_ttl(ta_number, + gid_cache_handle, + &ttl, name, gid_p)) { + rsbac_pr_debug(aef_um, "pid %u(%s): group %u (%s) found in name cache with ttl %u\n", + current->pid, current->comm, RSBAC_GID_NUM(*gid_p), name, ttl); + gid_cache_hits++; + return 0; + } +#endif + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (vset != RSBAC_UM_VIRTUAL_ALL) + err = rsbac_ta_list_get_desc_selector_ttl(ta_number, + group_handle, +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + &ttl, +#else + NULL, +#endif + gid_p, + name, + group_name_compare, + vset_selector, + &vset); + else +#endif + err = rsbac_ta_list_get_desc_ttl(ta_number, + group_handle, +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + &ttl, +#else + NULL, +#endif + gid_p, + name, group_name_compare); + + if (!err) { +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + if (!rsbac_um_name_cache_disable) { + if (ttl > 0) + ttl = rsbac_min(ttl, rsbac_um_name_cache_ttl); + else + ttl = rsbac_um_name_cache_ttl; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (vset != RSBAC_UM_VIRTUAL_ALL) + cache_desc.vset = vset; + else + cache_desc.vset = 0; + memcpy(cache_desc.name, name, RSBAC_UM_NAME_LEN); + rsbac_ta_list_add_ttl(ta_number, + gid_cache_handle, + ttl, + &cache_desc, gid_p); + rsbac_pr_debug(aef_um, "pid %u(%s): group %u/%u (%s) added to name cache with ttl %u\n", + current->pid, current->comm, RSBAC_GID_SET(*gid_p), RSBAC_GID_NUM(*gid_p), cache_desc.name, ttl); + gid_cache_misses++; +#else + rsbac_ta_list_add_ttl(ta_number, + gid_cache_handle, + ttl, + name, gid_p); + rsbac_pr_debug(aef_um, "pid %u(%s): group %u (%s) added to name cache with ttl %u\n", + current->pid, current->comm, RSBAC_GID_NUM(*gid_p), name, ttl); + gid_cache_misses++; +#endif + } +#endif + + return 0; + } else + return -RSBAC_ENOTFOUND; +} + +int rsbac_um_add_user(rsbac_list_ta_number_t ta_number, + rsbac_uid_t * user_p, + struct rsbac_um_user_entry_t *entry_p, + char *pass, rsbac_time_t ttl) +{ + int err; + rsbac_uid_t user; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_um_add_user(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + if (!entry_p || !user_p) + return -RSBAC_EINVALIDPOINTER; + user = *user_p; +#ifdef CONFIG_RSBAC_UM_EXCL + if (!rsbac_um_no_excl) { + rsbac_gid_t gid = RSBAC_GEN_GID(RSBAC_UID_SET(user), + entry_p->group); + if (!rsbac_ta_list_exist(ta_number, + group_handle, + &gid)) { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(gid)) + rsbac_printk(KERN_INFO "rsbac_um_add_user(): gid %u/%u not known to RSBAC User Management!\n", + RSBAC_GID_SET(gid), entry_p->group); + else +#endif + rsbac_printk(KERN_INFO "rsbac_um_add_user(): gid %u not known to RSBAC User Management!\n", + entry_p->group); + return -RSBAC_EINVALIDVALUE; + } + } +#endif + if (RSBAC_UID_NUM(user) == RSBAC_NO_USER) { + user = RSBAC_GEN_UID(RSBAC_UID_SET(user), + CONFIG_RSBAC_UM_USER_MIN); + while (rsbac_ta_list_lol_exist + (ta_number, user_handle, &user)) + user++; + } else + if (rsbac_ta_list_lol_exist + (ta_number, user_handle, &user)) + return -RSBAC_EEXISTS; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(user)) + rsbac_pr_debug(aef_um, "pid %u(%s): adding user %u/%u\n", + current->pid, current->comm, + RSBAC_UID_SET(user), RSBAC_UID_NUM(user)); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): adding user %u\n", + current->pid, current->comm, RSBAC_UID_NUM(user)); + if (pass) { + __u32 salt; + + new_salt(&salt); + err = rsbac_um_hash(pass, salt); + if (err) + return err; + memcpy(entry_p->pass, &salt, sizeof(salt)); + memcpy(entry_p->pass + sizeof(salt), pass, + RSBAC_UM_PASS_LEN - sizeof(salt)); + } else + memset(entry_p->pass, 0, RSBAC_UM_PASS_LEN); + err = + rsbac_ta_list_lol_add_ttl(ta_number, + user_handle, ttl, + &user, entry_p); + if (!err) + *user_p = user; + return err; +} + +int rsbac_um_add_group(rsbac_list_ta_number_t ta_number, + rsbac_gid_t * group_p, + struct rsbac_um_group_entry_t *entry_p, + char *pass, rsbac_time_t ttl) +{ + int err; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_um_add_group(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + if (!entry_p || !group_p) + return -RSBAC_EINVALIDPOINTER; + if (RSBAC_GID_NUM(*group_p) == RSBAC_NO_USER) { + *group_p = RSBAC_GEN_GID(RSBAC_GID_SET(*group_p), CONFIG_RSBAC_UM_GROUP_MIN); + while (rsbac_ta_list_exist + (ta_number, group_handle, + group_p)) + (*group_p)++; + } else + if (rsbac_ta_list_exist + (ta_number, group_handle, group_p)) + return -RSBAC_EEXISTS; + if (RSBAC_GID_SET(*group_p)) + rsbac_pr_debug(aef_um, "pid %u(%s): adding group %u/%u\n", + current->pid, current->comm, + RSBAC_GID_SET(*group_p), RSBAC_GID_NUM(*group_p)); + else + rsbac_pr_debug(aef_um, "pid %u(%s): adding group %u\n", + current->pid, current->comm, RSBAC_GID_NUM(*group_p)); + if (pass) { + __u32 salt; + + new_salt(&salt); + err = rsbac_um_hash(pass, salt); + if (err) + return err; + memcpy(entry_p->pass, &salt, sizeof(salt)); + memcpy(entry_p->pass + sizeof(salt), pass, + RSBAC_UM_PASS_LEN - sizeof(salt)); + } else + memset(entry_p->pass, 0, RSBAC_UM_PASS_LEN); + return rsbac_ta_list_add_ttl(ta_number, + group_handle, + ttl, group_p, entry_p); +} + +int rsbac_um_add_gm(rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, rsbac_gid_num_t group, rsbac_time_t ttl) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_um_add_gm(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } +#ifdef CONFIG_RSBAC_UM_EXCL + if (!rsbac_um_no_excl) { + rsbac_gid_t gid = RSBAC_GEN_GID(RSBAC_UID_SET(user), + group); + + if (!rsbac_ta_list_exist + (ta_number, user_handle, &user)) { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(user)) + rsbac_printk(KERN_INFO "rsbac_um_add_gm(): uid %u/%u not known to RSBAC User Management!\n", + RSBAC_UID_SET(user), RSBAC_UID_NUM(user)); + else +#endif + rsbac_printk(KERN_INFO "rsbac_um_add_gm(): uid %u not known to RSBAC User Management!\n", + RSBAC_UID_SET(user)); + return -RSBAC_ENOTFOUND; + } + if (!rsbac_ta_list_exist + (ta_number, group_handle, &gid)) { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(gid)) + rsbac_printk(KERN_INFO "rsbac_um_add_gm(): gid %u/%u not known to RSBAC User Management!\n", + RSBAC_GID_SET(gid), group); + else +#endif + rsbac_printk(KERN_INFO "rsbac_um_add_gm(): gid %u not known to RSBAC User Management!\n", + group); + return -RSBAC_ENOTFOUND; + } + } +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): adding user %u group %u\n", + current->pid, current->comm, user, group); + return rsbac_ta_list_lol_subadd_ttl(ta_number, + user_handle, + ttl, &user, &group, NULL); +} + +int rsbac_um_mod_user(rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + enum rsbac_um_mod_t mod, + union rsbac_um_mod_data_t *data_p) +{ + int err; + struct rsbac_um_user_entry_t *entry_p; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_um_mod_user(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + if (!data_p && (mod != UM_pass) + ) + return -RSBAC_EINVALIDPOINTER; + if (!rsbac_ta_list_lol_exist + (ta_number, user_handle, &user)) + return -RSBAC_ENOTFOUND; + + entry_p = rsbac_kmalloc_unlocked(sizeof(*entry_p)); + if (!entry_p) + return -RSBAC_ENOMEM; + err = + rsbac_ta_list_lol_get_data_ttl(ta_number, + user_handle, + NULL, &user, entry_p); + if (err) { + rsbac_kfree(entry_p); + return err; + } + rsbac_pr_debug(aef_um, "pid %u(%s): modifying user %u with mod %u\n", + current->pid, current->comm, user, mod); + switch (mod) { + case UM_name: + { + rsbac_uid_t tmp_user = user; +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +#ifdef CONFIG_RSBAC_UM_VIRTUAL + struct rsbac_um_name_cache_desc_t cache_desc; +#endif +#endif + + if (!rsbac_um_get_uid + (ta_number, data_p->string, &tmp_user) + && (tmp_user != user) + ) + return -RSBAC_EEXISTS; + strncpy(entry_p->name, data_p->string, + RSBAC_UM_NAME_LEN); + entry_p->name[RSBAC_UM_NAME_LEN - 1] = 0; +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +#ifdef CONFIG_RSBAC_UM_VIRTUAL + cache_desc.vset = RSBAC_UID_SET(user); + memcpy(cache_desc.name, entry_p->name, RSBAC_UM_NAME_LEN); + rsbac_ta_list_remove(ta_number, + uid_cache_handle, + &cache_desc); +#else + rsbac_ta_list_remove(ta_number, + uid_cache_handle, + entry_p->name); +#endif +#endif + } + break; + + case UM_pass: + if (data_p) { + __u32 salt; + + new_salt(&salt); + err = rsbac_um_hash(data_p->string, salt); + if (err) { + rsbac_kfree(entry_p); + return err; + } + memcpy(entry_p->pass, &salt, sizeof(salt)); + memcpy(entry_p->pass + sizeof(salt), + data_p->string, + RSBAC_UM_PASS_LEN - sizeof(salt)); + } else + memset(entry_p->pass, 0, RSBAC_UM_PASS_LEN); + entry_p->lastchange = RSBAC_CURRENT_TIME / 86400; + break; + + case UM_cryptpass: + memcpy(entry_p->pass, data_p->string, RSBAC_UM_PASS_LEN); + break; + + case UM_fullname: + strncpy(entry_p->fullname, data_p->string, + RSBAC_UM_FULLNAME_LEN); + entry_p->fullname[RSBAC_UM_FULLNAME_LEN - 1] = 0; + break; + + case UM_homedir: + strncpy(entry_p->homedir, data_p->string, + RSBAC_UM_HOMEDIR_LEN); + entry_p->homedir[RSBAC_UM_HOMEDIR_LEN - 1] = 0; + break; + + case UM_shell: + strncpy(entry_p->shell, data_p->string, + RSBAC_UM_SHELL_LEN); + entry_p->shell[RSBAC_UM_SHELL_LEN - 1] = 0; + break; + + case UM_group: +#ifdef CONFIG_RSBAC_UM_EXCL + { + rsbac_gid_t gid = RSBAC_GEN_GID(RSBAC_UID_SET(user), + data_p->group); + if (!rsbac_um_no_excl + && !rsbac_ta_list_exist(ta_number, + group_handle, + &gid)) { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(gid)) + rsbac_printk(KERN_INFO "rsbac_um_mod_user(): gid %u/%u not known to RSBAC User Management!\n", + RSBAC_GID_SET(gid), RSBAC_GID_NUM(gid)); + else +#endif + rsbac_printk(KERN_INFO "rsbac_um_mod_user(): gid %u not known to RSBAC User Management!\n", + RSBAC_GID_NUM(gid)); + rsbac_kfree(entry_p); + return -RSBAC_EINVALIDVALUE; + } + } +#endif + entry_p->group = data_p->group; + break; + + case UM_lastchange: + entry_p->lastchange = data_p->days; + break; + + case UM_minchange: + entry_p->minchange = data_p->days; + break; + + case UM_maxchange: + entry_p->maxchange = data_p->days; + break; + + case UM_warnchange: + entry_p->warnchange = data_p->days; + break; + + case UM_inactive: + entry_p->inactive = data_p->days; + break; + + case UM_expire: + entry_p->expire = data_p->days; + break; + + case UM_ttl: + err = + rsbac_ta_list_lol_add_ttl(ta_number, + user_handle, + data_p->ttl, &user, entry_p); + rsbac_kfree(entry_p); + return err; + + default: + rsbac_kfree(entry_p); + return -RSBAC_EINVALIDREQUEST; + } + + err = rsbac_ta_list_lol_add_ttl(ta_number, + user_handle, + RSBAC_LIST_TTL_KEEP, &user, entry_p); + rsbac_kfree(entry_p); + return err; +} + +int rsbac_um_mod_group(rsbac_list_ta_number_t ta_number, + rsbac_uid_t group, + enum rsbac_um_mod_t mod, + union rsbac_um_mod_data_t *data_p) +{ + int err; + struct rsbac_um_group_entry_t *entry_p; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_um_mod_group(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + if (!data_p && (mod != UM_pass) + ) + return -RSBAC_EINVALIDPOINTER; + if (!rsbac_ta_list_exist + (ta_number, group_handle, &group)) + return -RSBAC_ENOTFOUND; + + entry_p = rsbac_kmalloc_unlocked(sizeof(*entry_p)); + if (!entry_p) + return -RSBAC_ENOMEM; + err = + rsbac_ta_list_get_data_ttl(ta_number, + group_handle, + NULL, &group, entry_p); + if (err) { + rsbac_kfree(entry_p); + return err; + } + rsbac_pr_debug(aef_um, "pid %u(%s): modifying group %u\n", + current->pid, current->comm, group); + switch (mod) { + case UM_name: + { + rsbac_gid_t tmp_group = group; +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +#ifdef CONFIG_RSBAC_UM_VIRTUAL + struct rsbac_um_name_cache_desc_t cache_desc; +#endif +#endif + + if (!rsbac_um_get_gid + (ta_number, data_p->string, &tmp_group) + && (tmp_group != group) + ) + return -RSBAC_EEXISTS; + strncpy(entry_p->name, data_p->string, + RSBAC_UM_NAME_LEN); + entry_p->name[RSBAC_UM_NAME_LEN - 1] = 0; +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +#ifdef CONFIG_RSBAC_UM_VIRTUAL + cache_desc.vset = RSBAC_GID_SET(group); + memcpy(cache_desc.name, entry_p->name, RSBAC_UM_NAME_LEN); + rsbac_ta_list_remove(ta_number, + gid_cache_handle, + &cache_desc); +#else + rsbac_ta_list_remove(ta_number, + gid_cache_handle, + entry_p->name); +#endif +#endif + } + break; + + case UM_pass: + if (data_p) { + __u32 salt; + + new_salt(&salt); + err = rsbac_um_hash(data_p->string, salt); + if (err) { + rsbac_kfree(entry_p); + return err; + } + memcpy(entry_p->pass, &salt, sizeof(salt)); + memcpy(entry_p->pass + sizeof(salt), + data_p->string, + RSBAC_UM_PASS_LEN - sizeof(salt)); + } else + memset(entry_p->pass, 0, RSBAC_UM_PASS_LEN); + break; + + case UM_cryptpass: + memcpy(entry_p->pass, data_p->string, RSBAC_UM_PASS_LEN); + break; + + case UM_ttl: + err = + rsbac_ta_list_add_ttl(ta_number, + group_handle, + data_p->ttl, &group, entry_p); + rsbac_kfree(entry_p); + return err; + + default: + rsbac_kfree(entry_p); + return -RSBAC_EINVALIDREQUEST; + } + + err = + rsbac_ta_list_add_ttl(ta_number, + group_handle, + RSBAC_LIST_TTL_KEEP, &group, entry_p); + rsbac_kfree(entry_p); + return err; +} + +int rsbac_um_get_user_item(rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + enum rsbac_um_mod_t mod, + union rsbac_um_mod_data_t *data_p) +{ + int err; + struct rsbac_um_user_entry_t *entry_p; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_um_get_user_item(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + if (!data_p) + return -RSBAC_EINVALIDPOINTER; + if (!rsbac_ta_list_lol_exist + (ta_number, user_handle, &user)) + return -RSBAC_ENOTFOUND; + if (mod == UM_ttl) + return rsbac_ta_list_lol_get_data_ttl(ta_number, + user_handle, + &data_p->ttl, &user, + NULL); + + entry_p = rsbac_kmalloc_unlocked(sizeof(*entry_p)); + if (!entry_p) + return -RSBAC_ENOMEM; + err = + rsbac_ta_list_lol_get_data_ttl(ta_number, + user_handle, + NULL, &user, entry_p); + if (err) { + rsbac_kfree(entry_p); + return err; + } + switch (mod) { + case UM_name: + strcpy(data_p->string, entry_p->name); + break; + + case UM_pass: + memcpy(data_p->string, entry_p->pass, RSBAC_UM_PASS_LEN); + break; + + case UM_fullname: + strcpy(data_p->string, entry_p->fullname); + break; + + case UM_homedir: + strcpy(data_p->string, entry_p->homedir); + break; + + case UM_shell: + strcpy(data_p->string, entry_p->shell); + break; + + case UM_group: + data_p->group = entry_p->group; + break; + + case UM_lastchange: + data_p->days = entry_p->lastchange; + break; + + case UM_minchange: + data_p->days = entry_p->minchange; + break; + + case UM_maxchange: + data_p->days = entry_p->maxchange; + break; + + case UM_warnchange: + data_p->days = entry_p->warnchange; + break; + + case UM_inactive: + data_p->days = entry_p->inactive; + break; + + case UM_expire: + data_p->days = entry_p->expire; + break; + + default: + rsbac_kfree(entry_p); + return -RSBAC_EINVALIDREQUEST; + } + + rsbac_kfree(entry_p); + return 0; +} + +int rsbac_um_get_group_item(rsbac_list_ta_number_t ta_number, + rsbac_gid_t group, + enum rsbac_um_mod_t mod, + union rsbac_um_mod_data_t *data_p) +{ + int err; + struct rsbac_um_group_entry_t *entry_p; + + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_um_get_group_item(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + if (!data_p) + return -RSBAC_EINVALIDPOINTER; + if (!rsbac_ta_list_exist + (ta_number, group_handle, &group)) + return -RSBAC_ENOTFOUND; + if (mod == UM_ttl) + return rsbac_ta_list_get_data_ttl(ta_number, + group_handle, + &data_p->ttl, &group, + NULL); + + entry_p = rsbac_kmalloc_unlocked(sizeof(*entry_p)); + if (!entry_p) + return -RSBAC_ENOMEM; + err = + rsbac_ta_list_get_data_ttl(ta_number, + group_handle, + NULL, &group, entry_p); + if (err) { + rsbac_kfree(entry_p); + return err; + } + switch (mod) { + case UM_name: + strcpy(data_p->string, entry_p->name); + break; + + case UM_pass: + memcpy(data_p->string, entry_p->pass, RSBAC_UM_PASS_LEN); + break; + + default: + rsbac_kfree(entry_p); + return -RSBAC_EINVALIDREQUEST; + } + + rsbac_kfree(entry_p); + return 0; +} + +int rsbac_um_user_exists(rsbac_list_ta_number_t ta_number, + rsbac_uid_t user) +{ + return rsbac_ta_list_lol_exist(ta_number, + user_handle, + &user); +} + +int rsbac_um_group_exists(rsbac_list_ta_number_t ta_number, + rsbac_gid_t group) +{ + return rsbac_ta_list_exist(ta_number, + group_handle, + &group); +} + +int rsbac_um_remove_user(rsbac_list_ta_number_t ta_number, + rsbac_uid_t user) +{ + int err; +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + struct rsbac_um_user_entry_t entry; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + struct rsbac_um_name_cache_desc_t cache_desc; +#else + char cache_name[RSBAC_UM_NAME_LEN]; +#endif +#endif + + if (!rsbac_ta_list_lol_exist + (ta_number, user_handle, &user)) + return -RSBAC_ENOTFOUND; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(user)) + rsbac_pr_debug(aef_um, "pid %u(%s): removing user %u/%u\n", + current->pid, current->comm, RSBAC_UID_SET(user), RSBAC_UID_NUM(user)); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): removing user %u\n", + current->pid, current->comm, RSBAC_UID_NUM(user)); + +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + if (rsbac_ta_list_lol_get_data_ttl(ta_number, + user_handle, + NULL, + &user, + &entry)) { + entry.name[0] = 0; + } +#endif + + err = rsbac_ta_list_lol_remove(ta_number, + user_handle, + &user); +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (entry.name[0]) { + cache_desc.vset = RSBAC_UID_SET(user); + strncpy(cache_desc.name, entry.name, RSBAC_UM_NAME_LEN); + cache_desc.name[RSBAC_UM_NAME_LEN - 1] = 0; + rsbac_pr_debug(aef_um, "pid %u(%s): removing user %u/%u (%s) name cache entry\n", + current->pid, current->comm, RSBAC_UID_SET(user), RSBAC_UID_NUM(user), cache_desc.name); + rsbac_ta_list_remove(ta_number, + uid_cache_handle, + &cache_desc); + } +#else + if (entry.name[0]) { + strncpy(cache_name, entry.name, RSBAC_UM_NAME_LEN); + cache_name[RSBAC_UM_NAME_LEN - 1] = 0; + rsbac_pr_debug(aef_um, "pid %u(%s): removing user %u (%s) name cache entry\n", + current->pid, current->comm, RSBAC_UID_NUM(user), cache_name); + rsbac_ta_list_remove(ta_number, + uid_cache_handle, + cache_name); + } +#endif +#endif + + return err; +} + +int rsbac_um_remove_group(rsbac_list_ta_number_t ta_number, + rsbac_gid_t group) +{ + int err; + rsbac_gid_num_t group_num; +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + struct rsbac_um_group_entry_t entry; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + struct rsbac_um_name_cache_desc_t cache_desc; +#else + char cache_name[RSBAC_UM_NAME_LEN]; +#endif +#endif + + if (!rsbac_ta_list_exist + (ta_number, group_handle, &group)) + return -RSBAC_ENOTFOUND; + group_num = RSBAC_GID_NUM(group); +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(group)) + rsbac_pr_debug(aef_um, "pid %u(%s): removing group %u/%u\n", + current->pid, current->comm, RSBAC_GID_SET(group), group_num); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): removing group %u\n", + current->pid, current->comm, group_num); + +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + if (rsbac_ta_list_get_data_ttl(ta_number, + group_handle, + NULL, + &group, + &entry)) { + entry.name[0] = 0; + } +#endif + + rsbac_ta_list_lol_subremove_from_all(ta_number, + user_handle, + &group_num); + err = rsbac_ta_list_remove(ta_number, + group_handle, + &group); + +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (entry.name[0]) { + cache_desc.vset = RSBAC_GID_SET(group); + strncpy(cache_desc.name, entry.name, RSBAC_UM_NAME_LEN); + cache_desc.name[RSBAC_UM_NAME_LEN - 1] = 0; + rsbac_pr_debug(aef_um, "pid %u(%s): removing group %u/%u (%s) name cache entry\n", + current->pid, current->comm, RSBAC_GID_SET(group), RSBAC_GID_NUM(group), cache_desc.name); + rsbac_ta_list_remove(ta_number, + gid_cache_handle, + &cache_desc); + } +#else + if (entry.name[0]) { + strncpy(cache_name, entry.name, RSBAC_UM_NAME_LEN); + cache_name[RSBAC_UM_NAME_LEN - 1] = 0; + rsbac_pr_debug(aef_um, "pid %u(%s): removing group %u (%s) name cache entry\n", + current->pid, current->comm, RSBAC_GID_NUM(group), cache_name); + rsbac_ta_list_remove(ta_number, + gid_cache_handle, + cache_name); + } +#endif +#endif + + return err; +} + +int rsbac_um_remove_gm(rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, rsbac_gid_num_t group) +{ + if (!rsbac_is_initialized()) { + rsbac_printk(KERN_WARNING "rsbac_um_remove_gm(): RSBAC not initialized\n"); + return (-RSBAC_ENOTINITIALIZED); + } + rsbac_pr_debug(aef_um, "pid %u(%s): removing user %u group %u\n", + current->pid, current->comm, user, group); + return rsbac_ta_list_lol_subremove(ta_number, + user_handle, + &user, &group); +} + +int rsbac_um_get_user_entry(rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + struct rsbac_um_user_entry_t *entry_p, + rsbac_time_t * ttl_p) +{ + return rsbac_ta_list_lol_get_data_ttl(ta_number, + user_handle, + ttl_p, &user, entry_p); +} + +int rsbac_um_get_next_user(rsbac_list_ta_number_t ta_number, + rsbac_uid_t old_user, rsbac_uid_t * next_user_p) +{ + rsbac_uid_t *old_user_p; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + rsbac_um_set_t vset; +#endif + + if (old_user == RSBAC_NO_USER) + old_user_p = NULL; + else + old_user_p = &old_user; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + vset = RSBAC_UID_SET(old_user); + if (vset != RSBAC_UM_VIRTUAL_ALL) + return rsbac_ta_list_lol_get_next_desc_selector(ta_number, + user_handle, + old_user_p, + next_user_p, + vset_selector, + &vset); + else +#endif + return rsbac_ta_list_lol_get_next_desc(ta_number, + user_handle, + old_user_p, + next_user_p); +} + +int rsbac_um_get_user_list(rsbac_list_ta_number_t ta_number, + rsbac_um_set_t vset, + rsbac_uid_t ** list_pp) +{ + if(!list_pp) + return rsbac_ta_list_lol_count(ta_number, user_handle); + else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (vset != RSBAC_UM_VIRTUAL_ALL) + return rsbac_ta_list_lol_get_all_desc_selector( + ta_number, + user_handle, + (void **) list_pp, + vset_selector, + &vset); + else +#endif + return rsbac_ta_list_lol_get_all_desc(ta_number, + user_handle, + (void **) list_pp); + } +} + +int rsbac_um_get_gm_list(rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, rsbac_gid_num_t ** list_pp) +{ + if (!list_pp) + return rsbac_ta_list_lol_subcount(ta_number, + user_handle, + &user); + else + return rsbac_ta_list_lol_get_all_subdesc_ttl(ta_number, + user_handle, + &user, + (void **) list_pp, + NULL); +} + +int rsbac_um_get_gm_user_list( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t group, + rsbac_uid_num_t ** list_pp) + { + int j; + long all_count = 0; + long copy_count = 0; + long tmp_count; + rsbac_uid_t * tmp_list_p; + rsbac_uid_num_t * collect_list_p; + rsbac_uid_num_t * p; + rsbac_um_set_t gid_set; + rsbac_gid_num_t gid_num; + +#ifdef CONFIG_RSBAC_UM_EXCL + if(!rsbac_um_no_excl && !rsbac_ta_list_exist(ta_number, group_handle, &group)) + { + return -RSBAC_ENOTFOUND; + } +#endif + all_count = rsbac_ta_list_lol_count(ta_number, user_handle); + if(!list_pp || (all_count <= 0)) + return all_count; + + /* provide some extra room in case new groups have been added during this function run */ + all_count += EXTRA_ROOM; + collect_list_p = rsbac_kmalloc_unlocked(all_count * sizeof(rsbac_uid_num_t)); + if(!collect_list_p) + return -RSBAC_ENOMEM; + p = collect_list_p; + tmp_count = rsbac_ta_list_lol_get_all_desc(ta_number, user_handle, (void *) &tmp_list_p); + if(tmp_count > 0) + { + gid_set = RSBAC_GID_SET(group); + gid_num = RSBAC_GID_NUM(group); + for(j=0; jpid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): checking password for user %u\n", + current->pid, current->comm, RSBAC_UID_NUM(uid)); + /* check whether account or password has expired */ + curdays = RSBAC_CURRENT_TIME / 86400; + if ((curdays > entry_p->expire) && (entry_p->expire != -1) + && (entry_p->expire != 0) && (entry_p->lastchange != 0)) { + err = -RSBAC_EEXPIRED; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_pr_debug(aef_um, "pid %u(%s): account for user %u/%u has expired\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): account for user %u has expired\n", + current->pid, current->comm, RSBAC_UID_NUM(uid)); + goto out_free; + } + if ((curdays > + (entry_p->lastchange + entry_p->maxchange + + entry_p->inactive)) + && (entry_p->maxchange != -1) + && (entry_p->maxchange) + && (entry_p->inactive != -1) + && (entry_p->inactive) + && (entry_p->lastchange) + ) { + err = -RSBAC_EEXPIRED; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_pr_debug(aef_um, "pid %u(%s): password for user %u/%u has expired\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): password for user %u has expired\n", + current->pid, current->comm, RSBAC_UID_NUM(uid)); + goto out_free; + } + +/* rsbac_um_hash destroys old pass, so make a copy */ + pass_copy = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if (!pass_copy) { + err = -RSBAC_ENOMEM; + goto out_free; + } + strncpy(pass_copy, pass, RSBAC_MAXNAMELEN); + pass_copy[RSBAC_MAXNAMELEN - 1] = 0; + salt = *((__u32 *) entry_p->pass); + if ( !salt + || rsbac_um_hash(pass_copy, salt) + || memcmp (pass_copy, entry_p->pass + sizeof(salt), + RSBAC_UM_PASS_LEN - sizeof(salt))) { +#ifdef CONFIG_RSBAC_UM_ONETIME + rsbac_um_password_t * pw_array; + int count; + + count = rsbac_list_lol_get_all_subdesc(onetime_handle, + &uid, (void **) &pw_array); + if (count > 0) { + u_int i; + + rsbac_pr_debug(aef_um, "pid %u(%s): check %u one-time passwords for user %u/%u\n", + current->pid, current->comm, count, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + err = -EPERM; + for (i=0; ipid, current->comm, i, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + rsbac_list_lol_subremove(onetime_handle, + &uid, pw_array[i]); + err = 0; + break; + } + } + rsbac_kfree(pw_array); + } else +#endif + err = -EPERM; + } else + err = 0; + + rsbac_kfree(pass_copy); +out_free: + rsbac_kfree(entry_p); + if (err) + ssleep(1); + return err; +} + +int rsbac_um_good_pass(rsbac_uid_t uid, char *pass) +{ +#ifdef CONFIG_RSBAC_UM_NON_ALPHA + char *p; +#endif +#ifdef CONFIG_RSBAC_UM_PWHISTORY + int i; + long count; + char *hist_pass; + char *tmp; + __u8 *pwhistory_array; + __u32 salt; +#endif + + if (!pass) + return -RSBAC_EINVALIDPOINTER; + if (strlen(pass) < CONFIG_RSBAC_UM_MIN_PASS_LEN) + return -RSBAC_EWEAKPASSWORD; + +#ifdef CONFIG_RSBAC_UM_NON_ALPHA + p = pass; + while (*p && (((*p >= 'a') + && (*p <= 'z') + ) + || ((*p >= 'A') + && (*p <= 'Z') + ) + ) + ) + p++; + if (!(*p)) + return -RSBAC_EWEAKPASSWORD; +#endif + +#ifdef CONFIG_RSBAC_UM_PWHISTORY + count = rsbac_ta_list_lol_get_all_subdata(0, + user_pwhistory_handle, + &uid, + (void **) &pwhistory_array); + if (count > 0) { + tmp = + rsbac_kmalloc_unlocked(rsbac_max + (strlen(pass), RSBAC_UM_PASS_LEN)); + hist_pass = pwhistory_array; + + for (i = 0; i < count; i++) { + salt = *((__u32 *) hist_pass); + memcpy(tmp, pass, + rsbac_max(strlen(pass), RSBAC_UM_PASS_LEN)); + rsbac_um_hash(tmp, salt); + + if (memcmp + (tmp, hist_pass + sizeof(salt), + RSBAC_UM_PASS_LEN - sizeof(salt)) == 0) { + rsbac_kfree(tmp); + rsbac_kfree(pwhistory_array); + return -RSBAC_EWEAKPASSWORD; + } + hist_pass += RSBAC_UM_PASS_LEN; + } + rsbac_kfree(tmp); + rsbac_kfree(pwhistory_array); + } +#endif + + return 0; +} + +#ifdef CONFIG_RSBAC_UM_ONETIME +int rsbac_um_add_onetime(rsbac_uid_t uid, char *pass, rsbac_time_t ttl) +{ + int err; + __u32 salt; + char pass_entry[RSBAC_UM_PASS_LEN]; + + if (!pass) + return -RSBAC_EINVALIDPOINTER; + + if (RSBAC_UID_SET(uid)) + rsbac_pr_debug(aef_um, "pid %u(%s): add one-time password for user %u/%u with ttl %lu\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid), ttl); + else + rsbac_pr_debug(aef_um, "pid %u(%s): add one-time password for user %u with ttl %lu\n", + current->pid, current->comm, RSBAC_UID_NUM(uid), ttl); + new_salt(&salt); + err = rsbac_um_hash(pass, salt); + if (err) + return err; + memcpy(pass_entry, &salt, sizeof(salt)); + memcpy(pass_entry + sizeof(salt), pass, + RSBAC_UM_PASS_LEN - sizeof(salt)); + + return rsbac_list_lol_subadd_ttl(onetime_handle, ttl, &uid, pass_entry, NULL); +} + +int rsbac_um_remove_all_onetime(rsbac_uid_t uid) +{ + rsbac_pr_debug(aef_um, "pid %u(%s): remove all one-time passwords for user %u/%u\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + return rsbac_list_lol_subremove_all(onetime_handle, &uid); +} + +int rsbac_um_count_onetime(rsbac_uid_t uid) +{ + int err; + + rsbac_pr_debug(aef_um, "pid %u(%s): counting one-time passwords for user %u/%u\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + err = rsbac_list_lol_subcount(onetime_handle, &uid); + if (err == -RSBAC_ENOTFOUND) + err = 0; + return err; +} +#endif + +int rsbac_um_set_pass(rsbac_uid_t uid, char *pass) +{ + int err; + struct rsbac_um_user_entry_t *entry_p; + __u32 salt; + + entry_p = rsbac_kmalloc_unlocked(sizeof(*entry_p)); + if (!entry_p) + return -RSBAC_ENOMEM; + err = + rsbac_ta_list_lol_get_data_ttl(0, user_handle, + NULL, &uid, entry_p); + if (err) + goto out_free; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_pr_debug(aef_um, "pid %u(%s): setting password for user %u/%u\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): setting password for user %u\n", + current->pid, current->comm, RSBAC_UID_NUM(uid)); + if (pass) { +#ifdef CONFIG_RSBAC_UM_PWHISTORY + __u32 max_index = 0; + __u8 max_history = CONFIG_RSBAC_UM_PWHISTORY_MAX; + long count; +#endif + new_salt(&salt); + err = rsbac_um_hash(pass, salt); + if (err) + goto out_free; + memcpy(entry_p->pass, &salt, sizeof(salt)); + memcpy(entry_p->pass + sizeof(salt), pass, + RSBAC_UM_PASS_LEN - sizeof(salt)); +#ifdef CONFIG_RSBAC_UM_PWHISTORY + rsbac_list_lol_get_data(user_pwhistory_handle, + &uid, + &max_history); + if (max_history > 0) { + rsbac_ta_list_lol_get_max_subdesc(0, + user_pwhistory_handle, + &uid, + &max_index); + max_index++; + + if (max_index != 0) + rsbac_list_lol_subadd(user_pwhistory_handle, + &uid, &max_index, + entry_p->pass); + else { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_printk(KERN_WARNING "rsbac_um_set_pass(): maximum password history index reached for user %u/%u, password will not be stored!\n", + RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_printk(KERN_WARNING "rsbac_um_set_pass(): maximum password history index reached for user %u, password will not be stored!\n", + RSBAC_UID_NUM(uid)); + } + count = + rsbac_list_lol_subcount(user_pwhistory_handle, + &uid); + if (count > max_history) + rsbac_ta_list_lol_subremove_count(0, + user_pwhistory_handle, + &uid, + (count - max_history)); + } +#endif + } else + memset(entry_p->pass, 0, RSBAC_UM_PASS_LEN); + entry_p->lastchange = RSBAC_CURRENT_TIME / 86400; + err = rsbac_ta_list_lol_add_ttl(0, user_handle, + 0, &uid, entry_p); + + out_free: + rsbac_kfree(entry_p); + return err; +} + +int rsbac_um_set_group_pass(rsbac_gid_t gid, char *pass) +{ + int err; + struct rsbac_um_group_entry_t *entry_p; + __u32 salt; + + entry_p = rsbac_kmalloc_unlocked(sizeof(*entry_p)); + if (!entry_p) + return -RSBAC_ENOMEM; + err = rsbac_ta_list_get_data_ttl(0, group_handle, + NULL, &gid, entry_p); + if (err) + goto out_free; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_GID_SET(gid)) + rsbac_pr_debug(aef_um, "pid %u(%s): setting password for group %u/%u\n", + current->pid, current->comm, RSBAC_GID_SET(gid), RSBAC_GID_NUM(gid)); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): setting password for group %u\n", + current->pid, current->comm, RSBAC_GID_NUM(gid)); + if (pass) { + new_salt(&salt); + err = rsbac_um_hash(pass, salt); + if (err) + goto out_free; + memcpy(entry_p->pass, &salt, sizeof(salt)); + memcpy(entry_p->pass + sizeof(salt), pass, + RSBAC_UM_PASS_LEN - sizeof(salt)); + } else + memset(entry_p->pass, 0, RSBAC_UM_PASS_LEN); + err = + rsbac_ta_list_add_ttl(0, group_handle, 0, + &gid, entry_p); + + out_free: + rsbac_kfree(entry_p); + return err; +} + +int rsbac_um_check_account(rsbac_uid_t uid) +{ + int err; + struct rsbac_um_user_entry_t *entry_p; + u_long curdays; + + entry_p = rsbac_kmalloc_unlocked(sizeof(*entry_p)); + if (!entry_p) + return -RSBAC_ENOMEM; + err = + rsbac_ta_list_lol_get_data_ttl(0, user_handle, + NULL, &uid, entry_p); + if (err) + goto out_free; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_pr_debug(aef_um, "pid %u(%s): checking account for user %u/%u\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): checking account for user %u\n", + current->pid, current->comm, RSBAC_UID_NUM(uid)); + /* check whether account or password has expired */ + curdays = RSBAC_CURRENT_TIME / 86400; + if (*((__u32 *) entry_p->pass) + && !entry_p->lastchange) { + err = -RSBAC_EMUSTCHANGE; + rsbac_pr_debug(aef_um, "pid %u(%s): user %u must change password, " + "lastchange = 0\n", current->pid, current->comm, uid); + goto out_free; + } + if ((curdays > entry_p->expire) + && (entry_p->expire != -1) + && (entry_p->expire) + ) { + err = -RSBAC_EEXPIRED; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_pr_debug(aef_um, "pid %u(%s): account for user %u/%u has expired\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): account for user %u has expired\n", + current->pid, current->comm, RSBAC_UID_NUM(uid)); + goto out_free; + } + if ((curdays > + (entry_p->lastchange + entry_p->maxchange + + entry_p->inactive)) + && (entry_p->maxchange != -1) + && (entry_p->maxchange) + && (entry_p->inactive != -1) + && (entry_p->inactive) + ) { + err = -RSBAC_EEXPIRED; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_pr_debug(aef_um, "pid %u(%s): password for user %u/%u has expired\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): password for user %u has expired\n", + current->pid, current->comm, RSBAC_UID_NUM(uid)); + goto out_free; + } + if (((entry_p->lastchange + entry_p->maxchange) < curdays) + && entry_p->maxchange && (entry_p->maxchange != -1) + ) { + err = -RSBAC_EMUSTCHANGE; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_pr_debug(aef_um, "pid %u(%s): user %u/%u must change password, " + "lastchange too old\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): user %u must change password, " + "lastchange too old\n", + current->pid, current->comm, RSBAC_UID_NUM(uid)); + goto out_free; + } + if ((curdays > + (entry_p->lastchange + entry_p->maxchange - + entry_p->warnchange)) + && (entry_p->maxchange != -1) + && (entry_p->warnchange != -1) + && entry_p->maxchange && entry_p->warnchange) { + err = (entry_p->lastchange + entry_p->maxchange) - curdays; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_pr_debug(aef_um, "pid %u(%s): user %u/%u password will expire in %u days\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid), err); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): user %u password will expire in %u days\n", + current->pid, current->comm, RSBAC_UID_NUM(uid), err); + } else + err = 0; + + out_free: + rsbac_kfree(entry_p); + return err; +} + +#ifdef CONFIG_RSBAC_UM_PWHISTORY +int rsbac_um_get_max_history(rsbac_list_ta_number_t ta_number, rsbac_uid_t uid) +{ + int err; + __u8 max_history; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_pr_debug(aef_um, "pid %u(%s): getting max_history for user %u/%u\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): getting max_history for user %u\n", + current->pid, current->comm, RSBAC_UID_NUM(uid)); + err = rsbac_ta_list_lol_get_data_ttl(ta_number, user_pwhistory_handle, + NULL, + &uid, + &max_history); + if (err) + return err; + else + return max_history; +} + +int rsbac_um_set_max_history(rsbac_list_ta_number_t ta_number, rsbac_uid_t uid, __u8 max_history) +{ + int err; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_pr_debug(aef_um, "pid %u(%s): setting max_history for user %u/%u to %u\n", + current->pid, current->comm, RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid), max_history); + else +#endif + rsbac_pr_debug(aef_um, "pid %u(%s): setting max_history for user %u to %u\n", + current->pid, current->comm, RSBAC_UID_NUM(uid), max_history); + err = rsbac_ta_list_lol_add_ttl(ta_number, user_pwhistory_handle, + 0, + &uid, + &max_history); + if (err) + return err; + if (max_history > 0) { + long count; + + count = rsbac_ta_list_lol_subcount(ta_number, + user_pwhistory_handle, + &uid); + if (count > max_history) + rsbac_ta_list_lol_subremove_count(ta_number, + user_pwhistory_handle, + &uid, + (count - max_history)); + } else { + rsbac_ta_list_lol_subremove_all(ta_number, + user_pwhistory_handle, + &uid); + } + return 0; +} +#endif diff --git a/rsbac/help/Makefile b/rsbac/help/Makefile new file mode 100644 index 000000000000..265e6a9886cd --- /dev/null +++ b/rsbac/help/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for the Rule Set Based Access Control helpers. +# +# Author and (c) 1999-2012 Amon Ott +obj-y := syscalls.o helpers.o getname.o debug.o rkmem.o net_getname.o +#lsm.o + +obj-$(CONFIG_RSBAC_RC) += rc_getname.o +obj-$(CONFIG_RSBAC_ACL) += acl_getname.o +obj-$(CONFIG_RSBAC_PAX) += pax_getname.o +obj-$(CONFIG_RSBAC_CAP_LOG_MISSING) += cap_getname.o +obj-$(CONFIG_RSBAC_JAIL_LOG_MISSING) += jail_getname.o +obj-$(CONFIG_RSBAC_NET_OBJ) += net_helpers.o diff --git a/rsbac/help/acl_getname.c b/rsbac/help/acl_getname.c new file mode 100644 index 000000000000..e1d810eaaefb --- /dev/null +++ b/rsbac/help/acl_getname.c @@ -0,0 +1,185 @@ +/************************************ */ +/* Rule Set Based Access Control */ +/* */ +/* Author and (c) 1999-2013: Amon Ott */ +/* */ +/* Getname functions for ACL module */ +/* Last modified: 27/Nov/2013 */ +/************************************ */ + +#include +#include +#include +#include +#include + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +static char acl_subject_type_list[ACLS_NONE+1][6] = { + "USER", + "ROLE", + "GROUP", + "NONE" }; + +static char acl_group_syscall_list[ACLGS_none+1][18] = { + "add_group", + "change_group", + "remove_group", + "get_group_entry", + "list_groups", + "add_member", + "remove_member", + "get_user_groups", + "get_group_members", + "none" }; + +static char acl_scd_type_list[AST_none-32+1][20] = { + "auth_administration", + "udf_administration", + "none" }; + +static char acl_special_right_list[ACLR_NONE-32+1][20] = { + "FORWARD", + "ACCESS_CONTROL", + "SUPERVISOR", + "NONE" }; + +/*****************************************/ + +char * get_acl_subject_type_name(char * name, + enum rsbac_acl_subject_type_t value) + { + if(!name) + return(NULL); + if(value > ACLS_NONE) + strcpy(name, "ERROR!"); + else + strcpy(name, acl_subject_type_list[value]); + return(name); + }; + +#ifndef __KERNEL__ +enum rsbac_acl_subject_type_t get_acl_subject_type_nr(const char * name) + { + enum rsbac_acl_subject_type_t i; + + if(!name) + return(ACLS_NONE); + for (i = 0; i < ACLS_NONE; i++) + { + if (!strcmp(name, acl_subject_type_list[i])) + { + return(i); + } + } + return(ACLS_NONE); + }; +#endif + +char * get_acl_group_syscall_name(char * name, + enum rsbac_acl_group_syscall_type_t value) + { + if(!name) + return(NULL); + if(value > ACLGS_none) + strcpy(name, "ERROR!"); + else + strcpy(name, acl_group_syscall_list[value]); + return(name); + }; + +#ifndef __KERNEL__ +enum rsbac_acl_group_syscall_type_t get_acl_group_syscall_nr(const char * name) + { + enum rsbac_acl_group_syscall_type_t i; + + if(!name) + return(ACLGS_none); + for (i = 0; i < ACLGS_none; i++) + { + if (!strcmp(name, acl_group_syscall_list[i])) + { + return(i); + } + } + return(ACLGS_none); + }; +#endif + +char * get_acl_scd_type_name(char * name, + enum rsbac_acl_scd_type_t value) + { + if(!name) + return(NULL); + if(value < AST_min) + { + return(get_scd_type_name(name, value)); + } + value -= AST_min; + if(value > AST_none) + { + strcpy(name, "ERROR!"); + return(name); + } + strcpy(name, acl_scd_type_list[value]); + return(name); + }; + +#ifndef __KERNEL__ +enum rsbac_acl_scd_type_t get_acl_scd_type_nr(const char * name) + { + enum rsbac_acl_scd_type_t i; + + if(!name) + return(AST_none); + for (i = 0; i < AST_none-32; i++) + { + if (!strcmp(name, acl_scd_type_list[i])) + { + return(i+32); + } + } + return(get_scd_type_nr(name)); + }; +#endif + +char * get_acl_special_right_name(char * name, + enum rsbac_acl_special_rights_t value) + { + if(!name) + return(NULL); + if(value < RSBAC_ACL_SPECIAL_RIGHT_BASE) + { + return(get_request_name(name, value)); + } + value -= RSBAC_ACL_SPECIAL_RIGHT_BASE; + if(value > ACLR_NONE) + { + strcpy(name, "ERROR!"); + return(name); + } + strcpy(name, acl_special_right_list[value]); + return(name); + }; + +#ifndef __KERNEL__ +enum rsbac_acl_special_rights_t get_acl_special_right_nr(const char * name) + { + enum rsbac_acl_special_rights_t i; + + if(!name) + return(ACLR_NONE); + for (i = 0; i < (ACLR_NONE - RSBAC_ACL_SPECIAL_RIGHT_BASE); i++) + { + if (!strcmp(name, acl_special_right_list[i])) + { + return(i + RSBAC_ACL_SPECIAL_RIGHT_BASE); + } + } + return(get_request_nr(name)); + }; +#endif diff --git a/rsbac/help/cap_getname.c b/rsbac/help/cap_getname.c new file mode 100644 index 000000000000..25bb67c16c58 --- /dev/null +++ b/rsbac/help/cap_getname.c @@ -0,0 +1,442 @@ +/********************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2017: */ +/* Amon Ott */ +/* Getname functions for CAP module */ +/* Last modified: 21/Mar/2017 */ +/********************************** */ + +#include +#include +#include +#include +#include + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#include +#else +#include +#endif + +/*****************************************/ + +#ifdef CONFIG_RSBAC_CAP_LEARN_TA +rsbac_list_ta_number_t cap_learn_ta = CONFIG_RSBAC_CAP_LEARN_TA; +#else +#define cap_learn_ta 0 +#endif + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_CAP_LOG_MISSING) || defined(CONFIG_RSBAC_CAP_LEARN) +void rsbac_cap_log_missing_cap(int cap) + { + char * tmp; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + +#ifdef CONFIG_RSBAC_CAP_LEARN_TA + if (!rsbac_list_ta_exist(cap_learn_ta)) + rsbac_list_ta_begin(CONFIG_RSBAC_LIST_TRANS_MAX_TTL, + &cap_learn_ta, + RSBAC_ALL_USERS, + RSBAC_CAP_LEARN_TA_NAME, + NULL); +#endif + i_tid.process = task_pid(current); + if (rsbac_ta_get_attr(cap_learn_ta, + SW_CAP, + T_PROCESS, + i_tid, + A_max_caps_user, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_cap_log_missing_cap()", A_max_caps_user); + } + else + { + if(cap < 32) + { + if(!(i_attr_val1.max_caps_user.cap[0] & (1 << cap))) + { +#if defined(CONFIG_RSBAC_CAP_LEARN) + if (rsbac_cap_learn) + { + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if(tmp) + { + get_cap_name(tmp, cap); + rsbac_printk(KERN_INFO + "capable(): pid %u(%s), uid %u: add missing user max_cap %s to transaction %u!\n", + current->pid, current->comm, + __kuid_val(current_uid()), + tmp, + cap_learn_ta); + rsbac_kfree(tmp); + } + i_attr_val1.max_caps_user.cap[0] |= (1 << cap); + if (rsbac_ta_set_attr(cap_learn_ta, + SW_CAP, + T_PROCESS, + i_tid, + A_max_caps_user, + i_attr_val1)) + { + rsbac_pr_set_error (A_max_caps_user); + } + i_tid.user = __kuid_val(current_uid()); + if (rsbac_ta_get_attr(cap_learn_ta, + SW_CAP, + T_USER, + i_tid, + A_max_caps, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_max_caps); + } + else + { + struct cred *override_cred; + + i_attr_val1.max_caps.cap[0] |= (1 << cap); + if (rsbac_ta_set_attr(cap_learn_ta, + SW_CAP, + T_USER, + i_tid, + A_max_caps, + i_attr_val1)) + { + rsbac_pr_set_error (A_max_caps); + } + /* set effective cap for process */ + override_cred = prepare_creds(); + if (override_cred) + { + override_cred->cap_effective.cap[0] |= (1 << cap); + commit_creds(override_cred); + } + } + } + else +#endif + if(rsbac_cap_log_missing) + { + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if(tmp) + { + get_cap_name(tmp, cap); + rsbac_printk(KERN_DEBUG + "capable(): pid %u(%s), uid %u: missing user max_cap %s!\n", + current->pid, current->comm, + __kuid_val(current_uid()), + tmp); + rsbac_kfree(tmp); + } + } + } + } + else + { + if(!(i_attr_val1.max_caps_user.cap[1] & (1 << (cap - 32)))) + { +#if defined(CONFIG_RSBAC_CAP_LEARN) + if (rsbac_cap_learn) + { + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if(tmp) + { + get_cap_name(tmp, cap); + rsbac_printk(KERN_INFO + "capable(): pid %u(%s), uid %u: add missing user max_cap %s to transaction %u!\n", + current->pid, current->comm, + __kuid_val(current_uid()), + tmp, + cap_learn_ta); + rsbac_kfree(tmp); + } + i_attr_val1.max_caps_user.cap[1] |= (1 << (cap - 32)); + if (rsbac_ta_set_attr(cap_learn_ta, + SW_CAP, + T_PROCESS, + i_tid, + A_max_caps_user, + i_attr_val1)) { + rsbac_ds_set_error ("rsbac_adf_set_attr_cap()", + A_max_caps_user); + } + i_tid.user = __kuid_val(current_uid()); + if (rsbac_ta_get_attr(cap_learn_ta, + SW_CAP, + T_USER, + i_tid, + A_max_caps, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_max_caps); + } + else + { + struct cred *override_cred; + + i_attr_val1.max_caps.cap[1] |= (1 << (cap - 32)); + if (rsbac_ta_set_attr(cap_learn_ta, + SW_CAP, + T_USER, + i_tid, + A_max_caps, + i_attr_val1)) + { + rsbac_pr_set_error (A_max_caps); + } + /* set effective cap for process */ + override_cred = prepare_creds(); + if (override_cred) + { + override_cred->cap_effective.cap[1] |= (1 << (cap - 32)); + commit_creds(override_cred); + } + } + } + else +#endif + if(rsbac_cap_log_missing) + { + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if(tmp) + { + get_cap_name(tmp, cap); + rsbac_printk(KERN_DEBUG + "capable(): pid %u(%s), uid %u: missing user max_cap %s!\n", + current->pid, current->comm, + __kuid_val(current_uid()), + tmp); + rsbac_kfree(tmp); + } + } + } + } + } + + + if (rsbac_ta_get_attr(cap_learn_ta, + SW_CAP, + T_PROCESS, + i_tid, + A_max_caps_program, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_max_caps_program); + } + else + { + if(cap < 32) + { + if(!(i_attr_val1.max_caps_program.cap[0] & (1 << cap))) + { +#if defined(CONFIG_RSBAC_CAP_LEARN) + if (rsbac_cap_learn) + { + struct file *file_p; + + i_attr_val1.max_caps_program.cap[0] |= (1 << cap); + if (rsbac_ta_set_attr(cap_learn_ta, + SW_CAP, + T_PROCESS, + i_tid, + A_max_caps_program, + i_attr_val1)) { + rsbac_pr_set_error (A_max_caps_program); + } + file_p = get_task_exe_file(current); + if (file_p && file_p->f_path.dentry && file_p->f_path.dentry->d_inode) { + i_tid.file.device = file_p->f_path.dentry->d_sb->s_dev; + i_tid.file.inode = file_p->f_path.dentry->d_inode->i_ino; + i_tid.file.dentry_p = file_p->f_path.dentry; + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if(tmp) + { + char * target_id_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); +#else + target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); +#endif + if(target_id_name) + { + get_cap_name(tmp, cap); + rsbac_printk(KERN_INFO + "capable(): pid %u(%s), uid %u: add missing program max_cap %s to FILE %s to transaction %u!\n", + current->pid, current->comm, + __kuid_val(current_uid()), + tmp, + get_target_name(NULL, T_FILE, target_id_name, i_tid), + cap_learn_ta); + rsbac_kfree(target_id_name); + } + rsbac_kfree(tmp); + } + if (rsbac_ta_get_attr(cap_learn_ta, + SW_CAP, + T_FILE, + i_tid, + A_max_caps, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_max_caps); + } + else + { + struct cred *override_cred; + + i_attr_val1.max_caps.cap[0] |= (1 << cap); + if (rsbac_ta_set_attr(cap_learn_ta, + SW_CAP, + T_FILE, + i_tid, + A_max_caps, + i_attr_val1)) + { + rsbac_pr_set_error (A_max_caps); + } + /* set effective cap for process */ + override_cred = prepare_creds(); + if (override_cred) + { + override_cred->cap_effective.cap[0] |= (1 << cap); + commit_creds(override_cred); + } + } + } + } + else +#endif + if(rsbac_cap_log_missing) + { + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if(tmp) + { + get_cap_name(tmp, cap); + rsbac_printk(KERN_DEBUG + "capable(): pid %u(%s), uid %u: missing program max_cap %s!\n", + current->pid, current->comm, + __kuid_val(current_uid()), + tmp); + rsbac_kfree(tmp); + } + } + } + } + else + { + if(!(i_attr_val1.max_caps_program.cap[1] & (1 << (cap - 32)))) + { +#if defined(CONFIG_RSBAC_CAP_LEARN) + if (rsbac_cap_learn) + { + struct file *file_p; + + i_attr_val1.max_caps_program.cap[1] |= (1 << (cap - 32)); + if (rsbac_ta_set_attr(cap_learn_ta, + SW_CAP, + T_PROCESS, + i_tid, + A_max_caps_program, + i_attr_val1)) { + rsbac_pr_set_error (A_max_caps_program); + } + file_p = get_task_exe_file(current); + if (file_p && file_p->f_path.dentry && file_p->f_path.dentry->d_inode) { + i_tid.file.device = file_p->f_path.dentry->d_sb->s_dev; + i_tid.file.inode = file_p->f_path.dentry->d_inode->i_ino; + i_tid.file.dentry_p = file_p->f_path.dentry; + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if(tmp) + { + char * target_id_name; + +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + target_id_name = rsbac_kmalloc_unlocked(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); +#else + target_id_name = rsbac_kmalloc_unlocked(2 * RSBAC_MAXNAMELEN); +#endif + if(target_id_name) + { + get_cap_name(tmp, cap); + rsbac_printk(KERN_INFO + "capable(): pid %u(%s), uid %u: add missing program max_cap %s to FILE %s to transaction %u!\n", + current->pid, current->comm, + __kuid_val(current_uid()), + tmp, + get_target_name(NULL, T_FILE, target_id_name, i_tid), + cap_learn_ta); + rsbac_kfree(target_id_name); + } + rsbac_kfree(tmp); + } + if (rsbac_ta_get_attr(cap_learn_ta, + SW_CAP, + T_FILE, + i_tid, + A_max_caps, + &i_attr_val1, + FALSE)) + { + rsbac_pr_get_error(A_max_caps); + } + else + { + struct cred *override_cred; + + i_attr_val1.max_caps.cap[1] |= (1 << (cap - 32)); + if (rsbac_ta_set_attr(cap_learn_ta, + SW_CAP, + T_FILE, + i_tid, + A_max_caps, + i_attr_val1)) + { + rsbac_pr_set_error (A_max_caps); + } + /* set effective cap for process */ + override_cred = prepare_creds(); + if (override_cred) + { + override_cred->cap_effective.cap[1] |= (1 << (cap - 32)); + commit_creds(override_cred); + } + } + } + } + else +#endif + if(rsbac_cap_log_missing) + { + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if(tmp) + { + get_cap_name(tmp, cap); + rsbac_printk(KERN_DEBUG + "capable(): pid %u(%s), uid %u: missing program max_cap %s!\n", + current->pid, current->comm, + __kuid_val(current_uid()), + tmp); + rsbac_kfree(tmp); + } + } + } + } + } + } +#endif +#endif diff --git a/rsbac/help/debug.c b/rsbac/help/debug.c new file mode 100644 index 000000000000..30d966194b70 --- /dev/null +++ b/rsbac/help/debug.c @@ -0,0 +1,4886 @@ +/******************************************* */ +/* Rule Set Based Access Control */ +/* */ +/* Author and (c) 1999-2016: */ +/* Amon Ott */ +/* */ +/* Debug and logging functions for all parts */ +/* */ +/* Last modified: 01/Aug/2016 */ +/******************************************* */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_RSBAC_DAZ) +#include +#endif +#if defined(CONFIG_RSBAC_UDF) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern u_int rsbac_list_rcu_rate; + +unsigned long int rsbac_flags; + +/* Boolean debug switch for NO_WRITE (global) */ +int rsbac_debug_no_write = 0; + +static rsbac_boolean_t debug_initialized = FALSE; + +#ifdef CONFIG_RSBAC_FD_CACHE +rsbac_time_t rsbac_fd_cache_ttl = CONFIG_RSBAC_FD_CACHE_TTL; +u_int rsbac_fd_cache_disable = 0; +u_int rsbac_fd_cache_fuse = 0; +u_int rsbac_fd_cache_ceph = 0; +#endif + +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +rsbac_time_t rsbac_um_name_cache_ttl = CONFIG_RSBAC_UM_NAME_CACHE_TTL; +u_int rsbac_um_name_cache_disable = 0; +#endif + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +rsbac_time_t rsbac_list_check_interval = CONFIG_RSBAC_LIST_CHECK_INTERVAL; +#endif + +#ifdef CONFIG_RSBAC_DEBUG +/* Boolean debug switch for data structures */ +int rsbac_debug_ds = 0; + +/* Boolean debug switch for writing of data structures */ +int rsbac_debug_write = 0; + +/* Boolean debug switch for AEF */ +EXPORT_SYMBOL(rsbac_debug_aef); +int rsbac_debug_aef = 0; + +/* Boolean debug switch for stack debugging */ +int rsbac_debug_stack = 0; + +/* Boolean debug switch for generic lists */ +int rsbac_debug_lists = 0; + +#ifdef CONFIG_RSBAC_MPROTECT +int rsbac_debug_mprotect = 0; +#endif + + +#ifdef CONFIG_RSBAC_NET +int rsbac_debug_ds_net = 0; +int rsbac_debug_adf_net = 0; +int rsbac_debug_aef_net = 0; +#endif + +#if defined(CONFIG_RSBAC_MAC) +/* Boolean debug switch for MAC data structures */ +int rsbac_debug_ds_mac = 0; +/* Boolean debug switch for MAC syscalls / AEF */ +int rsbac_debug_aef_mac = 0; +/* Boolean debug switch for MAC decisions / ADF */ +int rsbac_debug_adf_mac = 0; +#endif + +#if defined(CONFIG_RSBAC_DAZ) +/* Boolean debug switch for DAZ decisions / ADF */ +int rsbac_debug_adf_daz = 0; +#endif + +#if defined(CONFIG_RSBAC_RC) +/* Boolean debug switch for RC data structures */ +int rsbac_debug_ds_rc = 0; +/* Boolean debug switch for RC syscalls / AEF */ +int rsbac_debug_aef_rc = 0; +/* Boolean debug switch for RC decisions / ADF */ +int rsbac_debug_adf_rc = 0; +#endif + +#if defined(CONFIG_RSBAC_AUTH) +/* Boolean debug switch for AUTH data structures */ +int rsbac_debug_ds_auth = 0; +/* Boolean debug switch for AUTH syscalls / AEF */ +int rsbac_debug_aef_auth = 0; +/* Boolean debug switch for AUTH decisions / ADF */ +int rsbac_debug_adf_auth = 0; +#endif + +#if defined(CONFIG_RSBAC_REG) +/* Boolean debug switch for REG */ +int rsbac_debug_reg = 0; +#endif + +#if defined(CONFIG_RSBAC_ACL) +/* Boolean debug switch for ACL data structures */ +int rsbac_debug_ds_acl = 0; +/* Boolean debug switch for ACL syscalls / AEF */ +int rsbac_debug_aef_acl = 0; +/* Boolean debug switch for ACL decisions / ADF */ +int rsbac_debug_adf_acl = 0; +#endif + +#if defined(CONFIG_RSBAC_JAIL) +/* Boolean debug switch for JAIL syscalls / AEF */ +int rsbac_debug_aef_jail = 0; +/* Boolean debug switch for JAIL decisions / ADF */ +int rsbac_debug_adf_jail = 0; +#endif + +#if defined(CONFIG_RSBAC_PAX) +/* Boolean debug switch for PAX decisions / ADF */ +int rsbac_debug_adf_pax = 0; +#endif + +#if defined(CONFIG_RSBAC_UDF) +/* Boolean debug switch for UDF decisions / ADF */ +int rsbac_debug_adf_udf = 0; +#endif + +#if defined(CONFIG_RSBAC_UM) +/* Boolean debug switch for UM data structures */ +int rsbac_debug_ds_um = 0; +/* Boolean debug switch for UM syscalls / AEF */ +int rsbac_debug_aef_um = 0; +/* Boolean debug switch for UM decisions / ADF */ +int rsbac_debug_adf_um = 0; +#endif + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +int rsbac_debug_auto = 0; +#endif + +#ifdef CONFIG_RSBAC_FD_CACHE +int rsbac_debug_fdcache = 0; +#endif + + +#endif /* DEBUG */ + +#if defined(CONFIG_RSBAC_UM_EXCL) +int rsbac_um_no_excl = 0; +#endif + +#if defined(CONFIG_RSBAC_RC_LEARN) +int rsbac_rc_learn = 0; +#endif + +#if defined(CONFIG_RSBAC_AUTH) +/* Boolean switch for AUTH init: set may_setuid for /bin/login */ +int rsbac_auth_enable_login = 0; +#if defined(CONFIG_RSBAC_AUTH_LEARN) +int rsbac_auth_learn = 0; +#endif +#endif + +#if defined(CONFIG_RSBAC_CAP_LEARN) +int rsbac_cap_learn = 0; +#endif + +#if defined(CONFIG_RSBAC_ACL_LEARN) +int rsbac_acl_learn_fd = 0; +#endif + +/* Suppress default list creation for complete restore */ +int rsbac_no_defaults = 0; + +static rsbac_list_handle_t log_levels_handle = NULL; + +#ifdef CONFIG_RSBAC_SOFTMODE +/* Boolean switch for RSBAC soft mode */ +int rsbac_softmode = 0; +int rsbac_softmode_prohibit = 0; +#ifdef CONFIG_RSBAC_SOFTMODE_IND +int rsbac_ind_softmode[SW_NONE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +#endif +#endif + +int rsbac_list_recover = 0; +int rsbac_list_noread = 0; +/* If number of items per hashed list is bigger than this and flag + RSBAC_LIST_AUTO_HASH_RESIZE is set for the list, rehash */ +u_int rsbac_list_auto_rehash_trigger = CONFIG_RSBAC_LIST_AUTO_REHASH_TRIGGER; + +#ifdef CONFIG_RSBAC_FREEZE +int rsbac_freeze = 0; +#endif + +#if defined(CONFIG_RSBAC_CAP_PROC_HIDE) +int rsbac_cap_process_hiding = 0; +#endif +#ifdef CONFIG_RSBAC_CAP_LOG_MISSING +int rsbac_cap_log_missing = 0; +#endif +#ifdef CONFIG_RSBAC_JAIL_LOG_MISSING +int rsbac_jail_log_missing = 0; +#endif + +static u_int log_seq = 0; + +/* Boolean switch for no syslog option*/ +#ifdef CONFIG_RSBAC_RMSG_NOSYSLOG +int rsbac_nosyslog = 0; +#endif + +#ifdef CONFIG_RSBAC_SYSLOG_RATE +static u_int rsbac_syslog_rate = CONFIG_RSBAC_SYSLOG_RATE_DEF; +static u_int syslog_count = 0; +#endif + +/* Boolean switch for delayed init option*/ +#ifdef CONFIG_RSBAC_INIT_DELAY +int rsbac_no_delay_init = 0; +kdev_t rsbac_delayed_root = RSBAC_MKDEV(0,0); +#endif + +/* Array of Boolean debug switches for ADF */ +int rsbac_debug_adf_default = 1; +rsbac_log_entry_t rsbac_log_levels[R_NONE+1]; + +rsbac_boolean_t rsbac_debug_adf_dirty = FALSE; + +/* variables for rsbac_logging */ +#if defined(CONFIG_RSBAC_RMSG) +#include +#include +DECLARE_WAIT_QUEUE_HEAD(rlog_wait); +struct rsbac_log_list_head_t log_list_head = {NULL, NULL, 0, 0}; +static u_int rsbac_rmsg_maxentries = CONFIG_RSBAC_RMSG_MAXENTRIES; +#if defined(CONFIG_RSBAC_LOG_REMOTE) +struct rsbac_log_list_head_t remote_log_list_head = {NULL, NULL, 0, 0}; +static DECLARE_WAIT_QUEUE_HEAD(rsbaclogd_wait); +static u_int rsbac_log_remote_maxentries = CONFIG_RSBAC_LOG_REMOTE_MAXENTRIES; +#ifndef CONFIG_RSBAC_LOG_REMOTE_SYNC +u_int rsbac_log_remote_interval = CONFIG_RSBAC_LOG_INTERVAL; +#endif +rsbac_pid_t rsbaclogd_pid = NULL; +static __u16 rsbac_log_remote_port = 0; +static __u32 rsbac_log_remote_addr = 0; +static char rsbac_log_remote_addr_string[RSBAC_MAXNAMELEN] = CONFIG_RSBAC_LOG_REMOTE_ADDR; +#endif + +#endif /* RMSG */ + +#ifdef CONFIG_RSBAC_SYSLOG_RATE +static struct timer_list rsbac_syslog_rate_timer; +#endif + +void rsbac_adf_log_switch(rsbac_adf_request_int_t request, + enum rsbac_target_t target, + rsbac_enum_t value) + { + if( (request < R_NONE) + && (target <= T_NONE) + && (value <= LL_full) + ) + { + rsbac_log_levels[request][target] = value; + if(log_levels_handle) + rsbac_list_add(log_levels_handle, &request, rsbac_log_levels[request]); + } + }; + +int rsbac_get_adf_log(rsbac_adf_request_int_t request, + enum rsbac_target_t target, + u_int * value_p) + { + if( (request < R_NONE) + && (target <= T_NONE) + ) + { + *value_p = rsbac_log_levels[request][target]; + return 0; + } + else + return -RSBAC_EINVALIDVALUE; + } + +static int R_INIT rsbac_flags_setup(char * line) +{ + rsbac_flags = simple_strtoul(line, NULL, 0); + rsbac_flags_set(rsbac_flags); + return 1; +} +__setup("rsbac_flags=", rsbac_flags_setup); + +// module_param(rsbac_no_defaults, bool, S_IRUGO); + static int R_INIT no_defaults_setup(char *line) + { + rsbac_no_defaults = 1; + return 1; + } +__setup("rsbac_no_defaults", no_defaults_setup); + + #if defined(CONFIG_RSBAC_UM_EXCL) + static int R_INIT um_no_excl_setup(char *line) + { + rsbac_um_no_excl = 1; + return 1; + } + __setup("rsbac_um_no_excl", um_no_excl_setup); + #endif + #if defined(CONFIG_RSBAC_DAZ_CACHE) + /* RSBAC: DAZ - set cache ttl */ +// module_param(rsbac_daz_ttl, +// int, +// S_IRUGO); + static int R_INIT daz_ttl_setup(char *line) + { + rsbac_daz_set_ttl(simple_strtoul(line, NULL, 0)); + return 1; + } + __setup("rsbac_daz_ttl=", daz_ttl_setup); + #endif + #if defined(CONFIG_RSBAC_UDF_CACHE) + /* RSBAC: UDF - set cache ttl */ +// module_param(rsbac_udf_ttl, +// int, +// S_IRUGO); + static int R_INIT udf_ttl_setup(char *line) + { + rsbac_udf_set_ttl(simple_strtoul(line, NULL, 0)); + return 1; + } + __setup("rsbac_udf_ttl=", udf_ttl_setup); + #endif + #if defined(CONFIG_RSBAC_RC_LEARN) + static int R_INIT rc_learn_setup(char *line) + { + rsbac_rc_learn = 1; + rsbac_debug_adf_rc = 1; + return 1; + } + __setup("rsbac_rc_learn", rc_learn_setup); + #endif + #if defined(CONFIG_RSBAC_AUTH) + /* RSBAC: AUTH - set auth_may_setuid for /bin/login? */ +// module_param(rsbac_auth_enable_login, int, S_IRUGO); + static int R_INIT auth_enable_login_setup(char *line) + { + rsbac_auth_enable_login = 1; + return 1; + } + __setup("rsbac_auth_enable_login", auth_enable_login_setup); + #if defined(CONFIG_RSBAC_AUTH_LEARN) + static int R_INIT auth_learn_setup(char *line) + { + rsbac_auth_learn = 1; + return 1; + } + __setup("rsbac_auth_learn", auth_learn_setup); + #endif + #endif + #if defined(CONFIG_RSBAC_CAP_LEARN) + static int R_INIT cap_learn_setup(char *line) + { + rsbac_cap_learn = 1; + return 1; + } + __setup("rsbac_cap_learn", cap_learn_setup); + #endif + #if defined(CONFIG_RSBAC_ACL_LEARN) + /* learn all target types */ + static int R_INIT acl_learn_setup(char *line) + { + rsbac_acl_learn_fd = 1; + return 1; + } + __setup("rsbac_acl_learn", acl_learn_setup); + static int R_INIT acl_learn_fd_setup(char *line) + { + rsbac_acl_learn_fd = 1; + return 1; + } + __setup("rsbac_acl_learn_fd", acl_learn_fd_setup); + #endif + #if defined(CONFIG_RSBAC_RC_LEARN) || defined(CONFIG_RSBAC_AUTH_LEARN) || defined(CONFIG_RSBAC_ACL_LEARN) || defined(CONFIG_RSBAC_CAP_LEARN) + static int R_INIT learn_all_setup(char *line) + { + #if defined(CONFIG_RSBAC_RC_LEARN) + rsbac_rc_learn = 1; + rsbac_debug_adf_rc = 1; + #endif + #if defined(CONFIG_RSBAC_AUTH_LEARN) + rsbac_auth_learn = 1; + #endif + #if defined(CONFIG_RSBAC_ACL_LEARN) + rsbac_acl_learn_fd = 1; + #endif + #if defined(CONFIG_RSBAC_CAP_LEARN) + rsbac_cap_learn = 1; + #endif + return 1; + } + __setup("rsbac_learn_all", learn_all_setup); + #endif + + #if defined(CONFIG_RSBAC_SOFTMODE) + /* RSBAC: softmode on? */ +// module_param(rsbac_softmode_once, bool, S_IRUGO); +// module_param(rsbac_softmode, bool, S_IRUGO); + static int R_INIT softmode_setup(char *line) + { + rsbac_softmode = 1; + return 1; + } + __setup("rsbac_softmode", softmode_setup); + static int R_INIT softmode_once_setup(char *line) + { + rsbac_softmode = 1; + rsbac_softmode_prohibit = 1; + return 1; + } + __setup("rsbac_softmode_once", softmode_once_setup); +// module_param(rsbac_softmode_never, bool, S_IRUGO); + static int R_INIT softmode_never_setup(char *line) + { + rsbac_softmode_prohibit = 1; + return 1; + } + __setup("rsbac_softmode_never", softmode_never_setup); + + #if defined(CONFIG_RSBAC_SOFTMODE_IND) + /* RSBAC: softmode on for a module? */ +// module_param_named(rsbac_softmode_mac, rsbac_ind_softmode[MAC], bool, S_IRUGO); + static int R_INIT softmode_mac_setup(char *line) + { + rsbac_ind_softmode[SW_MAC] = 1; + return 1; + } + __setup("rsbac_softmode_mac", softmode_mac_setup); +// module_param_named(rsbac_softmode_daz, rsbac_ind_softmode[SW_DAZ], bool, S_IRUGO); + static int R_INIT softmode_daz_setup(char *line) + { + rsbac_ind_softmode[SW_DAZ] = 1; + return 1; + } + __setup("rsbac_softmode_daz", softmode_daz_setup); +// module_param_named(rsbac_softmode_ff, rsbac_ind_softmode[SW_FF], bool, S_IRUGO); + static int R_INIT softmode_ff_setup(char *line) + { + rsbac_ind_softmode[SW_FF] = 1; + return 1; + } + __setup("rsbac_softmode_ff", softmode_ff_setup); +// module_param_named(rsbac_softmode_rc, rsbac_ind_softmode[SW_RC], bool, S_IRUGO); + static int R_INIT softmode_rc_setup(char *line) + { + rsbac_ind_softmode[SW_RC] = 1; + return 1; + } + __setup("rsbac_softmode_rc", softmode_rc_setup); +// module_param_named(rsbac_softmode_auth, rsbac_ind_softmode[SW_AUTH], bool, S_IRUGO); + static int R_INIT softmode_auth_setup(char *line) + { + rsbac_ind_softmode[SW_AUTH] = 1; + return 1; + } + __setup("rsbac_softmode_auth", softmode_auth_setup); +// module_param_named(rsbac_softmode_reg, rsbac_ind_softmode[SW_REG], bool, S_IRUGO); + static int R_INIT softmode_reg_setup(char *line) + { + rsbac_ind_softmode[SW_REG] = 1; + return 1; + } + __setup("rsbac_softmode_reg", softmode_reg_setup); +// module_param_named(rsbac_softmode_acl, rsbac_ind_softmode[SW_ACL], bool, S_IRUGO); + static int R_INIT softmode_acl_setup(char *line) + { + rsbac_ind_softmode[SW_ACL] = 1; + return 1; + } + __setup("rsbac_softmode_acl", softmode_acl_setup); +// module_param_named(rsbac_softmode_cap, rsbac_ind_softmode[SW_CAP], bool, S_IRUGO); + static int R_INIT softmode_cap_setup(char *line) + { + rsbac_ind_softmode[SW_CAP] = 1; + return 1; + } + __setup("rsbac_softmode_cap", softmode_cap_setup); +// module_param_named(rsbac_softmode_jail, rsbac_ind_softmode[SW_JAIL], bool, S_IRUGO); + static int R_INIT softmode_jail_setup(char *line) + { + rsbac_ind_softmode[SW_JAIL] = 1; + return 1; + } + __setup("rsbac_softmode_jail", softmode_jail_setup); +// module_param_named(rsbac_softmode_res, rsbac_ind_softmode[SW_RES], bool, S_IRUGO); + static int R_INIT softmode_res_setup(char *line) + { + rsbac_ind_softmode[SW_RES] = 1; + return 1; + } + __setup("rsbac_softmode_res", softmode_res_setup); +// module_param_named(rsbac_softmode_udf, rsbac_ind_softmode[SW_UDF], bool, S_IRUGO); + static int R_INIT softmode_udf_setup(char *line) + { + rsbac_ind_softmode[SW_UDF] = 1; + return 1; + } + __setup("rsbac_softmode_udf", softmode_udf_setup); +// module_param_named(rsbac_softmode_mprotect, rsbac_ind_softmode[SW_MPROTECT], bool, S_IRUGO); + static int R_INIT softmode_mprotect_setup(char *line) + { + rsbac_ind_softmode[SW_MPROTECT] = 1; + return 1; + } + __setup("rsbac_softmode_mprotect", softmode_mprotect_setup); + #endif + #endif + + #if defined(CONFIG_RSBAC_CAP_PROC_HIDE) + /* RSBAC: hide processes? */ +// module_param(rsbac_cap_process_hiding, bool, S_IRUGO); + static int R_INIT cap_process_hiding_setup(char *line) + { + rsbac_cap_process_hiding = 1; + return 1; + } + __setup("rsbac_cap_process_hiding", cap_process_hiding_setup); + #endif + #ifdef CONFIG_RSBAC_CAP_LOG_MISSING + /* RSBAC: log missing caps? */ +// module_param(rsbac_cap_log_missing, bool, S_IRUGO); + static int R_INIT cap_log_missing_setup(char *line) + { + rsbac_cap_log_missing = 1; + return 1; + } + __setup("rsbac_cap_log_missing", cap_log_missing_setup); + #endif + #ifdef CONFIG_RSBAC_JAIL_LOG_MISSING + /* RSBAC: log missing jail caps? */ +// module_param(rsbac_jail_log_missing, bool, S_IRUGO); + static int R_INIT jail_log_missing_setup(char *line) + { + rsbac_jail_log_missing = 1; + return 1; + } + __setup("rsbac_jail_log_missing", jail_log_missing_setup); + #endif + #if defined(CONFIG_RSBAC_FREEZE) + /* RSBAC: freeze config? */ +// module_param(rsbac_freeze, bool, S_IRUGO); + static int R_INIT freeze_setup(char *line) + { + rsbac_freeze = 1; + return 1; + } + __setup("rsbac_freeze", freeze_setup); + #endif + /* RSBAC: recover lists? */ +// module_param(rsbac_list_recover, bool, S_IRUGO); + static int R_INIT list_recover_setup(char *line) + { + rsbac_list_recover = 1; + return 1; + } + __setup("rsbac_list_recover", list_recover_setup); + /* RSBAC: do not load lists? might be needed for correct recover? */ +// module_param(rsbac_list_noread, bool, S_IRUGO); + static int R_INIT list_noread_setup(char *line) + { + rsbac_list_noread = 1; + return 1; + } + __setup("rsbac_list_noread", list_noread_setup); + static int R_INIT list_rcu_rate_setup(char *line) + { + rsbac_list_rcu_rate = simple_strtoul(line, NULL, 0); + if (rsbac_list_rcu_rate > 1000) + rsbac_list_rcu_rate = 1000; + return 1; + } + __setup("rsbac_list_rcu_rate=", list_rcu_rate_setup); + static int R_INIT list_auto_rehash_trigger_setup(char *line) + { + rsbac_list_auto_rehash_trigger = simple_strtoul(line, NULL, 0); + if (rsbac_list_auto_rehash_trigger < 4) + rsbac_list_auto_rehash_trigger = 4; + return 1; + } + __setup("rsbac_list_auto_rehash_trigger=", list_auto_rehash_trigger_setup); + + #ifdef CONFIG_RSBAC_RMSG_NOSYSLOG +// module_param(rsbac_nosyslog, bool, S_IRUGO); + static int R_INIT nosyslog_setup(char *line) + { + rsbac_nosyslog = 1; + return 1; + } + __setup("rsbac_nosyslog", nosyslog_setup); +// module_param_named(rsbac_no_syslog, rsbac_nosyslog, bool, S_IRUGO); + static int R_INIT no_syslog_setup(char *line) + { + rsbac_nosyslog = 1; + return 1; + } + __setup("rsbac_no_syslog", no_syslog_setup); + #endif + #if defined(CONFIG_RSBAC_RMSG) + static int R_INIT rmsg_maxentries_setup(char *line) + { + rsbac_rmsg_maxentries = simple_strtoul(line, NULL, 0); + return 1; + } + __setup("rsbac_rmsg_maxentries=", rmsg_maxentries_setup); + #endif + #if defined(CONFIG_RSBAC_LOG_REMOTE) +// module_param_string(rsbac_log_remote_addr, +// rsbac_log_remote_addr_string, +// sizeof(rsbac_log_remote_addr_string), +// S_IRUGO); + static int R_INIT log_remote_addr_setup(char *line) + { + strncpy(rsbac_log_remote_addr_string, line, RSBAC_MAXNAMELEN - 1); + rsbac_log_remote_addr_string[RSBAC_MAXNAMELEN - 1]=0; + return 1; + } + __setup("rsbac_log_remote_addr=", log_remote_addr_setup); +// module_param(rsbac_log_remote_port, +// int, +// S_IRUGO); + static int R_INIT log_remote_port_setup(char *line) + { + __u16 tmp_port; + + tmp_port = simple_strtoul(line, NULL, 0); + rsbac_log_remote_port = htons(tmp_port); + return 1; + } + __setup("rsbac_log_remote_port=", log_remote_port_setup); + static int R_INIT log_remote_maxentries_setup(char *line) + { + rsbac_log_remote_maxentries = simple_strtoul(line, NULL, 0); + return 1; + } + __setup("rsbac_log_remote_maxentries=", log_remote_maxentries_setup); + #endif + #ifdef CONFIG_RSBAC_INIT_DELAY +// module_param(rsbac_no_delay_init, bool, S_IRUGO); + static int R_INIT no_delay_init_setup(char *line) + { + rsbac_no_delay_init = 1; + return 1; + } + __setup("rsbac_no_delay_init", no_delay_init_setup); +// module_param_named(rsbac_no_init_delay, rsbac_no_delay_init, bool, S_IRUGO); + static int R_INIT no_init_delay_setup(char *line) + { + rsbac_no_delay_init = 1; + return 1; + } + __setup("rsbac_no_init_delay", no_init_delay_setup); + char rsbac_delayed_root_str[20] = ""; +// module_param_string(rsbac_delayed_root, +// rsbac_delayed_root_str, +// sizeof(rsbac_delayed_root_str), +// S_IRUGO); + static int R_INIT delayed_root_setup(char *line) + { + strncpy(rsbac_delayed_root_str, line, 19); + rsbac_delayed_root_str[19]=0; + return 1; + } + __setup("rsbac_delayed_root=", delayed_root_setup); + #endif + #ifdef CONFIG_RSBAC_SYSLOG_RATE +// module_param(rsbac_syslog_rate, +// int, +// S_IRUGO); + static int R_INIT syslog_rate_setup(char *line) + { + rsbac_syslog_rate = simple_strtoul(line, NULL, 0); + return 1; + } + __setup("rsbac_syslog_rate=", syslog_rate_setup); + #endif +#ifdef CONFIG_RSBAC_FD_CACHE +// module_param(rsbac_fd_cache_ttl, +// int, +// S_IRUGO); + static int R_INIT fd_cache_ttl_setup(char *line) + { + rsbac_fd_cache_ttl = simple_strtoul(line, NULL, 0); + return 1; + } + __setup("rsbac_fd_cache_ttl=", fd_cache_ttl_setup); +// module_param(rsbac_fd_cache_disable, bool, S_IRUGO); + static int R_INIT fd_cache_disable_setup(char *line) + { + rsbac_fd_cache_disable = 1; + return 1; + } + __setup("rsbac_fd_cache_disable", fd_cache_disable_setup); +// module_param(rsbac_fd_cache_fuse, bool, S_IRUGO); + static int R_INIT fd_cache_fuse_setup(char *line) + { + rsbac_fd_cache_fuse = 1; + return 1; + } + __setup("rsbac_fd_cache_fuse", fd_cache_fuse_setup); +// module_param(rsbac_fd_cache_ceph, bool, S_IRUGO); + static int R_INIT fd_cache_ceph_setup(char *line) + { + rsbac_fd_cache_ceph = 1; + return 1; + } + __setup("rsbac_fd_cache_ceph", fd_cache_ceph_setup); +#endif +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +// module_param(rsbac_um_name_cache_ttl, +// int, +// S_IRUGO); + static int R_INIT um_name_cache_ttl_setup(char *line) + { + rsbac_um_name_cache_ttl = simple_strtoul(line, NULL, 0); + return 1; + } + __setup("rsbac_um_name_cache_ttl=", um_name_cache_ttl_setup); +// module_param(rsbac_um_name_cache_disable, bool, S_IRUGO); + static int R_INIT um_name_cache_disable_setup(char *line) + { + rsbac_um_name_cache_disable = 1; + return 1; + } + __setup("rsbac_um_name_cache_disable", um_name_cache_disable_setup); +#endif +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +// module_param(rsbac_list_check_interval, +// int, +// S_IRUGO); + static int R_INIT list_check_interval_setup(char *line) + { + rsbac_list_check_interval = simple_strtoul(line, NULL, 0); + return 1; + } + __setup("rsbac_list_check_interval=", list_check_interval_setup); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + #ifdef CONFIG_RSBAC_NET + /* RSBAC: debug for net data structures? */ +// module_param(rsbac_debug_ds_net, bool, S_IRUGO); + static int R_INIT debug_ds_net_setup(char *line) + { + rsbac_debug_ds_net = 1; + return 1; + } + __setup("rsbac_debug_ds_net", debug_ds_net_setup); + /* RSBAC: debug for net syscalls/AEF? */ +// module_param(rsbac_debug_aef_net, bool, S_IRUGO); + static int R_INIT debug_aef_net_setup(char *line) + { + rsbac_debug_aef_net = 1; + return 1; + } + __setup("rsbac_debug_aef_net", debug_aef_net_setup); + /* RSBAC: debug for net decisions/ADF? */ +// module_param(rsbac_debug_adf_net, bool, S_IRUGO); + static int R_INIT debug_adf_net_setup(char *line) + { + rsbac_debug_adf_net = 1; + return 1; + } + __setup("rsbac_debug_adf_net", debug_adf_net_setup); + #endif + + #if defined(CONFIG_RSBAC_MAC) +// module_param(rsbac_debug_ds_mac, bool, S_IRUGO); + static int R_INIT debug_ds_mac_setup(char *line) + { + rsbac_debug_ds_mac = 1; + return 1; + } + __setup("rsbac_debug_ds_mac", debug_ds_mac_setup); +// module_param(rsbac_debug_aef_mac, bool, S_IRUGO); + static int R_INIT debug_aef_mac_setup(char *line) + { + rsbac_debug_aef_mac = 1; + return 1; + } + __setup("rsbac_debug_aef_mac", debug_aef_mac_setup); +// module_param(rsbac_debug_adf_mac, bool, S_IRUGO); + static int R_INIT debug_adf_mac_setup(char *line) + { + rsbac_debug_adf_mac = 1; + return 1; + } + __setup("rsbac_debug_adf_mac", debug_adf_mac_setup); + #if defined(CONFIG_RSBAC_SWITCH_MAC) && defined(RSBAC_SWITCH_BOOT_OFF) +// module_param(rsbac_switch_off_mac, bool, S_IRUGO); + static int R_INIT switch_off_mac_setup(char *line) + { + rsbac_switch_mac = 0; + return 1; + } + __setup("rsbac_switch_off_mac", switch_off_mac_setup); + #endif + #endif + #if defined(CONFIG_RSBAC_DAZ) +// module_param(rsbac_debug_adf_daz, bool, S_IRUGO); + static int R_INIT debug_adf_daz_setup(char *line) + { + rsbac_debug_adf_daz = 1; + return 1; + } + __setup("rsbac_debug_adf_daz", debug_adf_daz_setup); + #if defined(CONFIG_RSBAC_SWITCH_DAZ) && defined(RSBAC_SWITCH_BOOT_OFF) +// module_param(rsbac_switch_off_mac, bool, S_IRUGO); + static int R_INIT switch_off_daz_setup(char *line) + { + rsbac_switch_daz = 0; + return 1; + } + __setup("rsbac_switch_off_daz", switch_off_daz_setup); + #endif + #endif + #if defined(CONFIG_RSBAC_RC) +// module_param(rsbac_debug_ds_rc, bool, S_IRUGO); + static int R_INIT debug_ds_rc_setup(char *line) + { + rsbac_debug_ds_rc = 1; + return 1; + } + __setup("rsbac_debug_ds_rc", debug_ds_rc_setup); +// module_param(rsbac_debug_aef_rc, bool, S_IRUGO); + static int R_INIT debug_aef_rc_setup(char *line) + { + rsbac_debug_aef_rc = 1; + return 1; + } + __setup("rsbac_debug_aef_rc", debug_aef_rc_setup); +// module_param(rsbac_debug_adf_rc, bool, S_IRUGO); + static int R_INIT debug_adf_rc_setup(char *line) + { + rsbac_debug_adf_rc = 1; + return 1; + } + __setup("rsbac_debug_adf_rc", debug_adf_rc_setup); + #if defined(CONFIG_RSBAC_SWITCH_RC) && defined(RSBAC_SWITCH_BOOT_OFF) +// module_param(rsbac_switch_off_rc, bool, S_IRUGO); + static int R_INIT switch_off_rc_setup(char *line) + { + rsbac_switch_rc = 0; + return 1; + } + __setup("rsbac_switch_off_rc", switch_off_rc_setup); + #endif + #endif + #if defined(CONFIG_RSBAC_AUTH) +// module_param(rsbac_debug_ds_auth, bool, S_IRUGO); + static int R_INIT debug_ds_auth_setup(char *line) + { + rsbac_debug_ds_auth = 1; + return 1; + } + __setup("rsbac_debug_ds_auth", debug_ds_auth_setup); +// module_param(rsbac_debug_aef_auth, bool, S_IRUGO); + static int R_INIT debug_aef_auth_setup(char *line) + { + rsbac_debug_aef_auth = 1; + return 1; + } + __setup("rsbac_debug_aef_auth", debug_aef_auth_setup); +// module_param(rsbac_debug_adf_auth, bool, S_IRUGO); + static int R_INIT debug_adf_auth_setup(char *line) + { + rsbac_debug_adf_auth = 1; + return 1; + } + __setup("rsbac_debug_adf_auth", debug_adf_auth_setup); + #if defined(CONFIG_RSBAC_SWITCH_AUTH) && defined(RSBAC_SWITCH_BOOT_OFF) +// module_param(rsbac_switch_off_auth, bool, S_IRUGO); + static int R_INIT switch_off_auth_setup(char *line) + { + rsbac_switch_auth = 0; + return 1; + } + __setup("rsbac_switch_off_auth", switch_off_auth_setup); + #endif + #endif + #if defined(CONFIG_RSBAC_REG) +// module_param(rsbac_debug_reg, bool, S_IRUGO); + static int R_INIT debug_reg_setup(char *line) + { + rsbac_debug_reg = 1; + return 1; + } + __setup("rsbac_debug_reg", debug_reg_setup); + #endif + #if defined(CONFIG_RSBAC_ACL) +// module_param(rsbac_debug_ds_acl, bool, S_IRUGO); + static int R_INIT debug_ds_acl_setup(char *line) + { + rsbac_debug_ds_acl = 1; + return 1; + } + __setup("rsbac_debug_ds_acl", debug_ds_acl_setup); +// module_param(rsbac_debug_aef_acl, bool, S_IRUGO); + static int R_INIT debug_aef_acl_setup(char *line) + { + rsbac_debug_aef_acl = 1; + return 1; + } + __setup("rsbac_debug_aef_acl", debug_aef_acl_setup); +// module_param(rsbac_debug_adf_acl, bool, S_IRUGO); + static int R_INIT debug_adf_acl_setup(char *line) + { + rsbac_debug_adf_acl = 1; + return 1; + } + __setup("rsbac_debug_adf_acl", debug_adf_acl_setup); + #if defined(CONFIG_RSBAC_SWITCH_ACL) && defined(RSBAC_SWITCH_BOOT_OFF) +// module_param(rsbac_switch_off_acl, bool, S_IRUGO); + static int R_INIT switch_off_acl_setup(char *line) + { + rsbac_switch_acl = 0; + return 1; + } + __setup("rsbac_switch_off_acl", switch_off_acl_setup); + #endif + #endif + #if defined(CONFIG_RSBAC_JAIL) +// module_param(rsbac_debug_aef_jail, bool, S_IRUGO); + static int R_INIT debug_aef_jail_setup(char *line) + { + rsbac_debug_aef_jail = 1; + return 1; + } + __setup("rsbac_debug_aef_jail", debug_aef_jail_setup); +// module_param(rsbac_debug_adf_jail, bool, S_IRUGO); + static int R_INIT debug_adf_jail_setup(char *line) + { + rsbac_debug_adf_jail = 1; + return 1; + } + __setup("rsbac_debug_adf_jail", debug_adf_jail_setup); + #if defined(CONFIG_RSBAC_SWITCH_JAIL) && defined(RSBAC_SWITCH_BOOT_OFF) +// module_param(rsbac_switch_off_jail, bool, S_IRUGO); + static int R_INIT switch_off_jail_setup(char *line) + { + rsbac_switch_jail = 0; + return 1; + } + __setup("rsbac_switch_off_jail", switch_off_jail_setup); + #endif + #endif + #if defined(CONFIG_RSBAC_PAX) +// module_param(rsbac_debug_adf_pax, bool, S_IRUGO); + static int R_INIT debug_adf_pax_setup(char *line) + { + rsbac_debug_adf_pax = 1; + return 1; + } + __setup("rsbac_debug_adf_pax", debug_adf_pax_setup); + #if defined(CONFIG_RSBAC_SWITCH_PAX) && defined(RSBAC_SWITCH_BOOT_OFF) +// module_param(rsbac_switch_off_pax, bool, S_IRUGO); + static int R_INIT switch_off_pax_setup(char *line) + { + rsbac_switch_pax = 0; + return 1; + } + __setup("rsbac_switch_off_pax", switch_off_pax_setup); + #endif + #endif + #if defined(CONFIG_RSBAC_SWITCH_FF) && defined(RSBAC_SWITCH_BOOT_OFF) +// module_param(rsbac_switch_off_ff, bool, S_IRUGO); + static int R_INIT switch_off_ff_setup(char *line) + { + rsbac_switch_ff = 0; + return 1; + } + __setup("rsbac_switch_off_ff", switch_off_ff_setup); + #endif + #if defined(CONFIG_RSBAC_SWITCH_RES) && defined(RSBAC_SWITCH_BOOT_OFF) +// module_param(rsbac_switch_off_res, bool, S_IRUGO); + static int R_INIT switch_off_res_setup(char *line) + { + rsbac_switch_res = 0; + return 1; + } + __setup("rsbac_switch_off_res", switch_off_res_setup); + #endif + #if defined(CONFIG_RSBAC_SWITCH_CAP) && defined(RSBAC_SWITCH_BOOT_OFF) +// module_param(rsbac_switch_off_cap, bool, S_IRUGO); + static int R_INIT switch_off_cap_setup(char *line) + { + rsbac_switch_cap = 0; + return 1; + } + __setup("rsbac_switch_off_cap", switch_off_cap_setup); + #endif + #if defined(CONFIG_RSBAC_SWITCH_MPROTECT) && defined(RSBAC_SWITCH_BOOT_OFF) +// module_param(rsbac_switch_off_mprotect, bool, S_IRUGO); + static int R_INIT switch_off_mprotect_setup(char *line) + { + rsbac_switch_mprotect = 0; + return 1; + } + __setup("rsbac_switch_off_mprotect", switch_off_mprotect_setup); + #endif + #if defined(CONFIG_RSBAC_UDF) +// module_param(rsbac_debug_adf_udf, bool, S_IRUGO); + static int R_INIT debug_adf_udf_setup(char *line) + { + rsbac_debug_adf_udf = 1; + return 1; + } + __setup("rsbac_debug_adf_udf", debug_adf_udf_setup); + #if defined(CONFIG_RSBAC_SWITCH_UDF) && defined(RSBAC_SWITCH_BOOT_OFF) +// module_param(rsbac_switch_off_udf, bool, S_IRUGO); + static int R_INIT switch_off_udf_setup(char *line) + { + rsbac_switch_udf = 0; + return 1; + } + __setup("rsbac_switch_off_udf", switch_off_udf_setup); + #endif + #endif + #if defined(CONFIG_RSBAC_UM) +// module_param(rsbac_debug_ds_um, bool, S_IRUGO); + static int R_INIT debug_ds_um_setup(char *line) + { + rsbac_debug_ds_um = 1; + return 1; + } + __setup("rsbac_debug_ds_um", debug_ds_um_setup); +// module_param(rsbac_debug_aef_um, bool, S_IRUGO); + static int R_INIT debug_aef_um_setup(char *line) + { + rsbac_debug_aef_um = 1; + return 1; + } + __setup("rsbac_debug_aef_um", debug_aef_um_setup); +// module_param(rsbac_debug_adf_um, bool, S_IRUGO); + static int R_INIT debug_adf_um_setup(char *line) + { + rsbac_debug_adf_um = 1; + return 1; + } + __setup("rsbac_debug_adf_um", debug_adf_um_setup); + #endif + #if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +// module_param(rsbac_debug_auto, bool, S_IRUGO); + static int R_INIT debug_auto_setup(char *line) + { + rsbac_debug_auto = 1; + return 1; + } + __setup("rsbac_debug_auto", debug_auto_setup); + #endif +#ifdef CONFIG_RSBAC_FD_CACHE +// module_param(rsbac_debug_fdcache, bool, S_IRUGO); + static int R_INIT debug_fdcache_setup(char *line) + { + rsbac_debug_fdcache++; + return 1; + } + __setup("rsbac_debug_fdcache", debug_fdcache_setup); + #endif + /* RSBAC: debug_lists */ +// module_param(rsbac_debug_lists, bool, S_IRUGO); + static int R_INIT debug_lists_setup(char *line) + { + rsbac_debug_lists = 1; + return 1; + } + __setup("rsbac_debug_lists", debug_lists_setup); + /* RSBAC: debug_stack */ +// module_param(rsbac_debug_stack, bool, S_IRUGO); + static int R_INIT debug_stack_setup(char *line) + { + rsbac_debug_stack = 1; + return 1; + } + __setup("rsbac_debug_stack", debug_stack_setup); + /* RSBAC: debug for data structures? */ +// module_param(rsbac_debug_ds, bool, S_IRUGO); + static int R_INIT debug_ds_setup(char *line) + { + rsbac_debug_ds = 1; + return 1; + } + __setup("rsbac_debug_ds", debug_ds_setup); + /* RSBAC: debug for writing of data structures? */ +// module_param(rsbac_debug_write, bool, S_IRUGO); + static int R_INIT debug_write_setup(char *line) + { + rsbac_debug_write = 1; + return 1; + } + __setup("rsbac_debug_write", debug_write_setup); + /* RSBAC: debug for AEF? */ +// module_param(rsbac_debug_aef, bool, S_IRUGO); + static int R_INIT debug_aef_setup(char *line) + { + rsbac_debug_aef = 1; + return 1; + } + __setup("rsbac_debug_aef", debug_aef_setup); + /* RSBAC: debug_no_write for ds */ +// module_param(rsbac_debug_no_write, bool, S_IRUGO); + static int R_INIT debug_no_write_setup(char *line) + { + rsbac_debug_no_write = 1; + return 1; + } + __setup("rsbac_debug_no_write", debug_no_write_setup); + /* RSBAC: debug default for ADF */ +// module_param(rsbac_debug_adf_default, int, S_IRUGO); + static int R_INIT debug_adf_default_setup(char *line) + { + rsbac_debug_adf_default = 1; + return 1; + } + __setup("rsbac_debug_adf_default", debug_adf_default_setup); +#ifdef CONFIG_RSBAC_MPROTECT + /* RSBAC: debug_mprotect */ +// module_param(rsbac_debug_mprotect, bool, S_IRUGO); + static int R_INIT debug_mprotect_setup(char *line) + { + rsbac_debug_mprotect = 1; + return 1; + } + __setup("rsbac_debug_mprotect", debug_mprotect_setup); +#endif +#endif /* DEBUG */ + +#if defined(CONFIG_RSBAC_RMSG) +static DEFINE_SPINLOCK(rsbac_log_lock); + +#if defined(CONFIG_RSBAC_LOG_REMOTE) +static DEFINE_SPINLOCK(rsbac_log_remote_lock); +#endif + +/* + * Commands to do_syslog: + * + * 0 -- Close the log. Currently a NOP. + * 1 -- Open the log. Currently a NOP. + * 2 -- Read from the log. + * 3 -- Read all messages remaining in the ring buffer. + * 4 -- Read and clear all messages remaining in the ring buffer + * 5 -- Clear ring buffer. + * 9 -- Return number of unread characters in the log buffer + */ +int rsbac_log(int type, char * buf, int len) +{ + unsigned long count; + int do_clear = 0; + int error = 0; + char * k_buf; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + struct rsbac_log_list_item_t * log_item; + + /* RSBAC */ + rsbac_target_id.scd = ST_rsbac_log; + rsbac_attribute_value.dummy = 0; + if ((type == 4) || (type == 5)) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "rsbac_log(): function %u, calling ADF for MODIFY_SYSTEM_DATA\n", type); + } +#endif + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + error = -EPERM; + goto out; + } + } + else + if(type >= 1) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "rsbac_log(): function %u, calling ADF for GET_STATUS_DATA\n", type); + } +#endif + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + error = -EPERM; + goto out; + } + } + + switch (type) { + case 0: /* Close log */ + break; + case 1: /* Open log */ + break; + case 2: /* Read from log */ + if (!buf || len < 0) { + error = -EINVAL; + goto out; + } + if (!len) { + error = 0; + goto out; + } + error = access_ok(VERIFY_WRITE,buf,len); + if (!error) + goto out; + error = wait_event_interruptible(rlog_wait, log_list_head.count); + if (error) + goto out; + if (len > RSBAC_LOG_MAXREADBUF) + len = RSBAC_LOG_MAXREADBUF; + k_buf = rsbac_kmalloc(len); + count = 0; + spin_lock(&rsbac_log_lock); + log_item = log_list_head.head; + while (log_item && (count + log_item->size < len)) { + memcpy(k_buf + count, log_item->buffer, log_item->size); + count += log_item->size; + log_item = log_item->next; + kfree(log_list_head.head); + log_list_head.head = log_item; + if(!log_item) + log_list_head.tail = NULL; + log_list_head.count--; + } + spin_unlock(&rsbac_log_lock); + error = copy_to_user(buf, k_buf, count); + if (!error) + error = count; + rsbac_kfree(k_buf); + break; + case 4: /* Read/clear last kernel messages */ + do_clear = 1; + /* FALL THRU */ + case 3: /* Read last kernel messages */ + error = -EINVAL; + if (!buf || len < 0) + goto out; + error = 0; + if (!len) + goto out; + error = access_ok(VERIFY_WRITE,buf,len); + if (!error) + goto out; + if (len > RSBAC_LOG_MAXREADBUF) + len = RSBAC_LOG_MAXREADBUF; + k_buf = rsbac_kmalloc(len); + count = 0; + spin_lock(&rsbac_log_lock); + log_item = log_list_head.head; + while (log_item && (count + log_item->size < len)) { + memcpy(k_buf + count, log_item->buffer, log_item->size); + count += log_item->size; + log_item = log_item->next; + if(do_clear) { + kfree(log_list_head.head); + log_list_head.head = log_item; + if(!log_item) + log_list_head.tail = NULL; + log_list_head.count--; + } + } + spin_unlock(&rsbac_log_lock); + error = copy_to_user(buf, k_buf, count); + if (!error) + error = count; + rsbac_kfree(k_buf); + break; + case 5: /* Clear ring buffer */ + spin_lock(&rsbac_log_lock); + log_item = log_list_head.head; + while (log_item) { + log_item = log_item->next; + kfree(log_list_head.head); + log_list_head.head = log_item; + } + log_list_head.tail = NULL; + log_list_head.count = 0; + spin_unlock(&rsbac_log_lock); + error = 0; + break; + case 9: /* Number of chars in the log buffer */ + error = 0; + spin_lock(&rsbac_log_lock); + log_item = log_list_head.head; + while (log_item) { + error += log_item->size; + log_item = log_item->next; + } + spin_unlock(&rsbac_log_lock); + break; + default: + error = -EINVAL; + break; + } +out: + return error; +} +#endif /* RMSG */ + +#ifdef CONFIG_RSBAC_SYSLOG_RATE +static void syslog_rate_reset(u_long dummy) + { + if(syslog_count > rsbac_syslog_rate) + printk(KERN_INFO "syslog_rate_reset: resetting syslog_count at %u, next message is %u\n", + syslog_count, log_seq); + syslog_count = 0; + mod_timer(&rsbac_syslog_rate_timer, jiffies + HZ); + } +#endif + +EXPORT_SYMBOL(rsbac_printk); +int rsbac_printk(const char *fmt, ...) +{ + va_list args; + int printed_len; + char * buf; +#if defined(CONFIG_RSBAC_RMSG) + struct rsbac_log_list_item_t * log_item; +#endif + + if (rsbac_is_initialized()) + buf = rsbac_kmalloc(RSBAC_LOG_MAXLINE); + else + buf = kmalloc(RSBAC_LOG_MAXLINE, GFP_ATOMIC); + if (!buf) + return -ENOMEM; + /* Emit the output into the buffer */ + va_start(args, fmt); + printed_len = vsnprintf(buf + 11, RSBAC_LOG_MAXLINE - 13, fmt, args); + va_end(args); + if(printed_len < 4) { + kfree(buf); + return printed_len; + } + buf[0] = buf[11]; + buf[1] = buf[12]; + sprintf(buf + 2, "%010u", log_seq++); + buf[12] = '|'; + /* Terminate string */ + buf[printed_len + 11] = 0; + + /* copy to printk */ +#ifdef CONFIG_RSBAC_RMSG_NOSYSLOG + if (!rsbac_nosyslog) +#endif + { +#ifdef CONFIG_RSBAC_SYSLOG_RATE + syslog_count++; + if(syslog_count < rsbac_syslog_rate) +#endif + printk("%s", buf); +#ifdef CONFIG_RSBAC_SYSLOG_RATE + else + if(syslog_count == rsbac_syslog_rate) + printk(KERN_INFO "rsbac_printk: Applying syslog rate limit at count %u, message %u!\n", + syslog_count, log_seq - 1); +#endif + } + /* Buffer is ready, now copy into log list */ +#if defined(CONFIG_RSBAC_RMSG) + if (rsbac_is_initialized()) + log_item = rsbac_kmalloc(sizeof(*log_item) + printed_len + 12); + else + log_item = kmalloc(sizeof(*log_item) + printed_len + 12, GFP_ATOMIC); + if(log_item) { + memcpy(log_item->buffer, buf, printed_len + 11); + log_item->buffer[printed_len + 11] = 0; + log_item->size = printed_len + 11; + log_item->next = NULL; + spin_lock(&rsbac_log_lock); + if (log_list_head.tail) { + log_list_head.tail->next = log_item; + } else { + log_list_head.head = log_item; + } + log_list_head.tail = log_item; + log_list_head.count++; + while(log_list_head.count > rsbac_rmsg_maxentries) { + log_item = log_list_head.head; + log_list_head.head = log_item->next; + log_list_head.count--; + log_list_head.lost++; + kfree(log_item); + } + spin_unlock(&rsbac_log_lock); + wake_up_interruptible(&rlog_wait); + } +#endif + +#if defined(CONFIG_RSBAC_LOG_REMOTE) + /* Copy into remote log list */ + if (rsbac_is_initialized()) + log_item = rsbac_kmalloc(sizeof(*log_item) + printed_len + 12); + else + log_item = kmalloc(sizeof(*log_item) + printed_len + 12, GFP_ATOMIC); + if(log_item) { + memcpy(log_item->buffer, buf, printed_len + 11); + log_item->buffer[printed_len + 11] = 0; + log_item->size = printed_len + 11; + log_item->next = NULL; + spin_lock(&rsbac_log_remote_lock); + if (remote_log_list_head.tail) { + remote_log_list_head.tail->next = log_item; + } else { + remote_log_list_head.head = log_item; + } + remote_log_list_head.tail = log_item; + remote_log_list_head.count++; + while(remote_log_list_head.count > rsbac_log_remote_maxentries) { + log_item = remote_log_list_head.head; + remote_log_list_head.head = log_item->next; + remote_log_list_head.count--; + remote_log_list_head.lost++; + kfree(log_item); + } + spin_unlock(&rsbac_log_remote_lock); +#ifdef CONFIG_RSBAC_LOG_REMOTE_SYNC + wake_up_interruptible(&rsbaclogd_wait); +#endif + } +#endif + + kfree(buf); + return printed_len; +} + +#if defined(CONFIG_RSBAC_RMSG) +#if defined(CONFIG_RSBAC_PROC) +static int rmsg_open(struct inode * inode, struct file * file) +{ + return rsbac_log(1,NULL,0); +} + +static int rmsg_release(struct inode * inode, struct file * file) +{ + (void) rsbac_log(0,NULL,0); + return 0; +} + +static ssize_t rmsg_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + return rsbac_log(2,buf,count); +} + +static unsigned int rmsg_poll(struct file *file, poll_table * wait) +{ + poll_wait(file, &rlog_wait, wait); + if (rsbac_log(9, 0, 0)) + return POLLIN | POLLRDNORM; + return 0; +} + +static struct file_operations rmsg_proc_fops = { + .read = rmsg_read, + .poll = rmsg_poll, /* rmsg_poll */ + .open = rmsg_open, + .release = rmsg_release +}; + +static struct proc_dir_entry *rmsg; + +#endif /* PROC */ +#endif /* RMSG */ + +#if defined(CONFIG_RSBAC_PROC) +#ifndef PROC_BLOCK_SIZE +#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ +#endif + +static int +log_levels_proc_show(struct seq_file *m, void *v) +{ + int i,j; + char * name; + char * name2; + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (!rsbac_is_initialized()) + return (-ENOSYS); + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "log_levels_proc_info(): calling ADF\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + name = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if(!name) + return -ENOMEM; + name2 = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if(!name2) + { + rsbac_kfree(name); + return -ENOMEM; + } + + seq_printf(m, "RSBAC Log Levels\n----------------\n"); + seq_printf(m, "Name\t\t\tFILE\tDIR\tFIFO\tSYMLINK\tDEV\tIPC\tSCD\tUSER\tPROCESS\tNETDEV\tNETTEMP\tNETOBJ\tNETT_NT\tNONE\n"); + + for (i = 0; i PROC_BLOCK_SIZE) { + return(-EOVERFLOW); + } + + if (!(k_buf = (char *) __get_free_page(GFP_KERNEL))) + return(-ENOMEM); + err = copy_from_user(k_buf, buf, count); + if(err < 0) + return err; + + err = count; + if(count < 15 || strncmp("log_levels", k_buf, 10)) + { + goto out; + } + if (!rsbac_is_initialized()) + { + err = -ENOSYS; + goto out; + } + + /* + * Usage: echo "log_levels request #N" > /proc/rsbac_info/log_levels + * to set log level for request to given value + */ + for(i=0; i 0) + seq_printf(m, "rsbac_list_check_interval is %u\n", + rsbac_list_check_interval); +#endif + +#if defined(CONFIG_RSBAC_LOG_REMOTE) +#if defined(CONFIG_RSBAC_LOG_REMOTE_TCP) + seq_printf(m, "rsbac_log_remote_addr (TCP) is %u.%u.%u.%u\n", + NIPQUAD(rsbac_log_remote_addr)); +#else + seq_printf(m, "rsbac_log_remote_addr (UDP) is %u.%u.%u.%u\n", + NIPQUAD(rsbac_log_remote_addr)); +#endif + seq_printf(m, "rsbac_log_remote_port is %u\n", + ntohs(rsbac_log_remote_port)); +#endif + +#ifdef CONFIG_RSBAC_INIT_DELAY + seq_printf(m, "rsbac_no_delay_init is %i\n", + rsbac_no_delay_init); + seq_printf(m, "rsbac_delayed_root is %02u:%02u\n", + RSBAC_MAJOR(rsbac_delayed_root), RSBAC_MINOR(rsbac_delayed_root)); +#endif + +#if defined(CONFIG_RSBAC_UM_EXCL) + seq_printf(m, "rsbac_um_no_excl is %i\n", + rsbac_um_no_excl); +#endif + +#if defined(CONFIG_RSBAC_RC_LEARN) + seq_printf(m, "rsbac_rc_learn is %i\n", + rsbac_rc_learn); +#endif + +#if defined(CONFIG_RSBAC_AUTH) + seq_printf(m, "rsbac_auth_enable_login is %i\n", + rsbac_auth_enable_login); + +#if defined(CONFIG_RSBAC_AUTH_LEARN) + seq_printf(m, "rsbac_auth_learn is %i\n", + rsbac_auth_learn); +#endif +#endif + +#if defined(CONFIG_RSBAC_CAP_LEARN) + seq_printf(m, "rsbac_cap_learn is %i\n", + rsbac_cap_learn); +#endif + +#if defined(CONFIG_RSBAC_ACL_LEARN) + seq_printf(m, "rsbac_acl_learn_fd is %i\n", + rsbac_acl_learn_fd); +#endif + + seq_printf(m, "rsbac_no_defaults is %i\n", + rsbac_no_defaults); +#ifdef CONFIG_RSBAC_DEBUG + seq_printf(m, "rsbac_debug_write is %i\n", + rsbac_debug_write); + seq_printf(m, "rsbac_debug_stack is %i\n", + rsbac_debug_stack); + seq_printf(m, "rsbac_debug_lists is %i\n", + rsbac_debug_lists); + seq_printf(m, "rsbac_debug_ds is %i\n", + rsbac_debug_ds); + seq_printf(m, "rsbac_debug_aef is %i\n", + rsbac_debug_aef); + seq_printf(m, "rsbac_debug_no_write is %i\n", + rsbac_debug_no_write); +#ifdef CONFIG_RSBAC_MPROTECT + seq_printf(m, "rsbac_debug_mprotect is %i\n", + rsbac_debug_mprotect); +#endif + +#if defined(CONFIG_RSBAC_REG) +/* Boolean debug switch for REG */ + seq_printf(m, "rsbac_debug_reg is %i\n", + rsbac_debug_reg); +#endif + +#if defined(CONFIG_RSBAC_NET) +/* Boolean debug switch for NET data structures */ + seq_printf(m, "rsbac_debug_ds_net is %i\n", + rsbac_debug_ds_net); +/* Boolean debug switch for NET syscalls / AEF */ + seq_printf(m, "rsbac_debug_aef_net is %i\n", + rsbac_debug_aef_net); +/* Boolean debug switch for NET decisions / ADF */ + seq_printf(m, "rsbac_debug_adf_net is %i\n", + rsbac_debug_adf_net); +#endif + +#if defined(CONFIG_RSBAC_MAC) +/* Boolean debug switch for MAC data structures */ + seq_printf(m, "rsbac_debug_ds_mac is %i\n", + rsbac_debug_ds_mac); +/* Boolean debug switch for MAC syscalls / AEF */ + seq_printf(m, "rsbac_debug_aef_mac is %i\n", + rsbac_debug_aef_mac); +/* Boolean debug switch for MAC decisions / ADF */ + seq_printf(m, "rsbac_debug_adf_mac is %i\n", + rsbac_debug_adf_mac); +#endif + +#if defined(CONFIG_RSBAC_DAZ) +/* Boolean debug switch for DAZ decisions / ADF */ + seq_printf(m, "rsbac_debug_adf_daz is %i\n", + rsbac_debug_adf_daz); +#endif + +#if defined(CONFIG_RSBAC_RC) +/* Boolean debug switch for RC data structures */ + seq_printf(m, "rsbac_debug_ds_rc is %i\n", + rsbac_debug_ds_rc); +/* Boolean debug switch for RC syscalls / AEF */ + seq_printf(m, "rsbac_debug_aef_rc is %i\n", + rsbac_debug_aef_rc); +/* Boolean debug switch for RC decisions / ADF */ + seq_printf(m, "rsbac_debug_adf_rc is %i\n", + rsbac_debug_adf_rc); +#endif + +#if defined(CONFIG_RSBAC_AUTH) +/* Boolean debug switch for AUTH data structures */ + seq_printf(m, "rsbac_debug_ds_auth is %i\n", + rsbac_debug_ds_auth); + +/* Boolean debug switch for AUTH syscalls / AEF */ + seq_printf(m, "rsbac_debug_aef_auth is %i\n", + rsbac_debug_aef_auth); + +/* Boolean debug switch for AUTH decisions / ADF */ + seq_printf(m, "rsbac_debug_adf_auth is %i\n", + rsbac_debug_adf_auth); +#endif + +#if defined(CONFIG_RSBAC_ACL) +/* Boolean debug switch for ACL data structures */ + seq_printf(m, "rsbac_debug_ds_acl is %i\n", + rsbac_debug_ds_acl); + +/* Boolean debug switch for ACL syscalls / AEF */ + seq_printf(m, "rsbac_debug_aef_acl is %i\n", + rsbac_debug_aef_acl); + +/* Boolean debug switch for ACL decisions / ADF */ + seq_printf(m, "rsbac_debug_adf_acl is %i\n", + rsbac_debug_adf_acl); +#endif + +#if defined(CONFIG_RSBAC_JAIL) +/* Boolean debug switch for JAIL syscalls / AEF */ + seq_printf(m, "rsbac_debug_aef_jail is %i\n", + rsbac_debug_aef_jail); +/* Boolean debug switch for JAIL decisions / ADF */ + seq_printf(m, "rsbac_debug_adf_jail is %i\n", + rsbac_debug_adf_jail); +#endif +#if defined(CONFIG_RSBAC_PAX) +/* Boolean debug switch for PAX decisions / ADF */ + seq_printf(m, "rsbac_debug_adf_pax is %i\n", + rsbac_debug_adf_pax); +#endif +#if defined(CONFIG_RSBAC_UM) +/* Boolean debug switch for UM data structures */ + seq_printf(m, "rsbac_debug_ds_um is %i\n", + rsbac_debug_ds_um); +/* Boolean debug switch for UM syscalls / AEF */ + seq_printf(m, "rsbac_debug_aef_um is %i\n", + rsbac_debug_aef_um); +/* Boolean debug switch for UM decisions / ADF */ + seq_printf(m, "rsbac_debug_adf_um is %i\n", + rsbac_debug_adf_um); +#endif +#if defined(CONFIG_RSBAC_UDF) +/* Boolean debug switch for UDF decisions / ADF */ + seq_printf(m, "rsbac_debug_adf_udf is %i\n", + rsbac_debug_adf_udf); +#endif + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) + seq_printf(m, "rsbac_debug_auto is %i\n", + rsbac_debug_auto); +#endif /* CONFIG_RSBAC_AUTO_WRITE > 0 */ +#ifdef CONFIG_RSBAC_FD_CACHE + seq_printf(m, "rsbac_debug_fdcache is %i\n", + rsbac_debug_fdcache); +#endif +#endif /* DEBUG */ + +#if defined(CONFIG_RSBAC_RMSG) + seq_printf(m, "rsbac_rmsg_maxentries is %u\n", + rsbac_rmsg_maxentries); + seq_printf(m, "%u messages in log buffer, %lu messages lost, sequence is %u\n", + log_list_head.count, log_list_head.lost, log_seq); +#if defined(CONFIG_RSBAC_LOG_REMOTE) + seq_printf(m, "rsbac_log_remote_maxentries is %u\n", + rsbac_log_remote_maxentries); + seq_printf(m, "%u messages in remote log buffer, %lu messages lost\n", + remote_log_list_head.count, remote_log_list_head.lost); +#endif +#endif + + return 0; +} + +static ssize_t debug_proc_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos) +{ + ssize_t err; + char * k_buf; + char * p; + unsigned int debug_level; +#ifdef CONFIG_RSBAC_SOFTMODE_IND + enum rsbac_switch_target_t sw_target; +#endif + + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(count > PROC_BLOCK_SIZE) { + return(-EOVERFLOW); + } + if(count < 10) + return -EINVAL; + + if (!(k_buf = (char *) __get_free_page(GFP_KERNEL))) + return(-ENOMEM); + err = copy_from_user(k_buf, buf, count); + if(err < 0) + return err; + + err = count; + + if(!strncmp("debug", k_buf, 5) || !strncmp("rsbac", k_buf, 5)) + { + p = k_buf + 6; + } + else + if(!strncmp("rsbac_debug", k_buf, 11)) + { + p = k_buf + 12; + } + else + goto out; + + if (!rsbac_is_initialized()) + { + err = -ENOSYS; + goto out; + } + if(count < 10) + return -EINVAL; + + +#ifdef CONFIG_RSBAC_SOFTMODE +#ifdef CONFIG_RSBAC_SOFTMODE_IND +/* Boolean switch for RSBAC individual soft mode */ + /* + * Usage: echo "debug ind_softmode modname #N" > /proc/rsbac_info/debug + * to set rsbac_ind_softmode[module] to given value + */ + if(!strncmp("ind_softmode", k_buf + 6, 12)) + { + char tmp[20]; + + p += 13; + + if( *p == '\0' ) + goto out; + + sw_target = get_switch_target_nr(p); + if(sw_target == SW_NONE) + goto out; + get_switch_target_name(tmp, sw_target); + p += strlen(tmp)+1; + if( *p == '\0' ) + goto out; + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + if(debug_level && rsbac_softmode_prohibit) + { + rsbac_printk(KERN_WARNING + "debug_proc_write(): setting of softmode prohibited!\n"); + err = -EPERM; + goto out; + } +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for switching\n"); + } +#endif + rsbac_target_id.dummy = 0; + rsbac_attribute_value.switch_target = sw_target; + if (!rsbac_adf_request(R_SWITCH_MODULE, + task_pid(current), + T_NONE, + rsbac_target_id, + A_switch_target, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_ind_softmode[%s] to %u\n", + tmp, + debug_level); + rsbac_ind_softmode[sw_target] = debug_level; + err = count; + goto out; + } + else + { + rsbac_printk(KERN_INFO + "debug_proc_write(): rejecting invalid ind_softmode value (should be 0 or 1)\n"); + err = -EINVAL; + goto out; + } + } +#endif + +/* Boolean switch for RSBAC soft mode prohibit */ + /* + * Usage: echo "debug softmode_prohibit #N" > /proc/rsbac_info/debug + * to set rsbac_softmode to given value + */ + if(!strncmp("softmode_prohibit", k_buf + 6, 17)) + { + p += 18; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + if(!debug_level && rsbac_softmode_prohibit) + { + rsbac_printk(KERN_WARNING + "debug_proc_write(): setting of softmode prohibited!\n"); + err = -EPERM; + goto out; + } +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for softmode\n"); + } +#endif + rsbac_target_id.dummy = 0; + rsbac_attribute_value.switch_target = SW_SOFTMODE; + if (!rsbac_adf_request(R_SWITCH_MODULE, + task_pid(current), + T_NONE, + rsbac_target_id, + A_switch_target, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_softmode_prohibit to %u\n", + debug_level); + rsbac_softmode_prohibit = debug_level; + err = count; + goto out; + } + else + { + rsbac_printk(KERN_INFO + "debug_proc_write(): rejecting invalid softmode_prohibit value (should be 0 or 1)\n"); + err = -EINVAL; + goto out; + } + } +/* Boolean switch for RSBAC soft mode */ + /* + * Usage: echo "debug softmode #N" > /proc/rsbac_info/debug + * to set rsbac_softmode to given value + */ + if(!strncmp("softmode", k_buf + 6, 8)) + { + p += 9; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + if(debug_level && rsbac_softmode_prohibit) + { + rsbac_printk(KERN_WARNING + "debug_proc_write(): setting of softmode prohibited!\n"); + err = -EPERM; + goto out; + } +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for softmode\n"); + } +#endif + rsbac_target_id.dummy = 0; + rsbac_attribute_value.switch_target = SW_SOFTMODE; + if (!rsbac_adf_request(R_SWITCH_MODULE, + task_pid(current), + T_NONE, + rsbac_target_id, + A_switch_target, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_softmode to %u\n", + debug_level); + rsbac_softmode = debug_level; + err = count; + goto out; + } + else + { + rsbac_printk(KERN_INFO + "debug_proc_write(): rejecting invalid softmode value (should be 0 or 1)\n"); + err = -EINVAL; + goto out; + } + } +#endif + +#ifdef CONFIG_RSBAC_FREEZE +/* Boolean switch to enable freezing */ + /* + * Usage: echo "debug freeze #N" > /proc/rsbac_info/debug + * to set freeze to given value + */ + if(!strncmp("freeze", k_buf + 6, 6)) + { + p += 7; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + if(!debug_level && rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "debug_proc_write(): RSBAC configuration frozen, no administration allowed!\n"); + err = -EPERM; + goto out; + } + +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for freeze\n"); + } +#endif + rsbac_target_id.dummy = 0; + rsbac_attribute_value.switch_target = SW_FREEZE; + if (!rsbac_adf_request(R_SWITCH_MODULE, + task_pid(current), + T_NONE, + rsbac_target_id, + A_switch_target, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_freeze to %u\n", + debug_level); + rsbac_freeze = debug_level; + err = count; + goto out; + } + else + { + rsbac_printk(KERN_INFO + "debug_proc_write(): rejecting invalid freeze value (should be 0 or 1)\n"); + err = -EINVAL; + goto out; + } + } +#endif + +/* Set list rcu rate limit */ + /* + * Usage: echo "debug list_rcu_rate #n" > /proc/rsbac_info/debug + * to set rate limit to given value + */ + if(!strncmp("list_rcu_rate", k_buf + 6, 13)) + { + u_int tmp_rate; + + p += 14; + if( *p == '\0' ) + goto out; + + tmp_rate = simple_strtoul(p, NULL, 0); + if (tmp_rate > 1000) + tmp_rate = 1000; + +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for list_rcu_rate\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_list_rcu_rate to %u\n", + tmp_rate); + rsbac_list_rcu_rate = tmp_rate; + err = count; + goto out; + } + +/* Set list rehash trigger */ + /* + * Usage: echo "debug list_auto_rehash_trigger #n" > /proc/rsbac_info/debug + * to set rehash trigger to given value + */ + if(!strncmp("list_auto_rehash_trigger", k_buf + 6, 24)) + { + u_int tmp_trigger; + + p += 25; + if( *p == '\0' ) + goto out; + + tmp_trigger = simple_strtoul(p, NULL, 0); + if (tmp_trigger < 4) + tmp_trigger = 4; + +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for list_auto_rehash_trigger\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_list_auto_rehash_trigger to %u\n", + tmp_trigger); + rsbac_list_auto_rehash_trigger = tmp_trigger; + err = count; + goto out; + } + +#ifdef CONFIG_RSBAC_DAZ_CACHE +/* Set DAZ cache ttl */ + /* + * Usage: echo "debug daz_ttl #n" > /proc/rsbac_info/debug + * to set daz cache ttl to given value + */ + if(!strncmp("daz_ttl", k_buf + 6, 7)) + { + rsbac_time_t tmp_ttl; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + p += 8; + if( *p == '\0' ) + goto out; + + tmp_ttl = simple_strtoul(p, NULL, 0); +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for daz_ttl\n"); + } +#endif + /* Security Officer? */ + i_tid.user = __kuid_val(current_uid()); + if (rsbac_get_attr(SW_DAZ, + T_USER, + i_tid, + A_daz_role, + &i_attr_val1, + TRUE)) + { + rsbac_printk(KERN_WARNING + "debug_proc_write(): rsbac_get_attr() returned error!\n"); + return -EPERM; + } + /* if not sec_officer or admin, deny */ + if (i_attr_val1.system_role != SR_security_officer) + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_DAZ] + #endif + ) + #endif + return -EPERM; + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_daz_ttl to %u\n", + tmp_ttl); + rsbac_daz_set_ttl(tmp_ttl); + err = count; + goto out; + } +#endif + +#ifdef CONFIG_RSBAC_UDF_CACHE +/* Set UDF cache ttl */ + /* + * Usage: echo "debug udf_ttl #n" > /proc/rsbac_info/debug + * to set udf cache ttl to given value + */ + if(!strncmp("udf_ttl", k_buf + 6, 7)) + { + rsbac_time_t tmp_ttl; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + p += 8; + if( *p == '\0' ) + goto out; + + tmp_ttl = simple_strtoul(p, NULL, 0); +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for udf_ttl\n"); + } +#endif + /* Security Officer? */ + i_tid.user = __kuid_val(current_uid()); + if (rsbac_get_attr(SW_UDF, + T_USER, + i_tid, + A_udf_role, + &i_attr_val1, + TRUE)) + { + rsbac_printk(KERN_WARNING + "debug_proc_write(): rsbac_get_attr() returned error!\n"); + return -EPERM; + } + /* if not sec_officer or admin, deny */ + if (i_attr_val1.system_role != SR_security_officer) + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_UDF] + #endif + ) + #endif + return -EPERM; + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_udf_ttl to %u\n", + tmp_ttl); + rsbac_udf_set_ttl(tmp_ttl); + err = count; + goto out; + } +#endif + +#if defined(CONFIG_RSBAC_LOG_REMOTE) +/* Set remote address for remote logging */ + /* + * Usage: echo "debug log_remote_addr a.b.c.d" > /proc/rsbac_info/debug + * to set log_remote_addr to given value + */ + if(!strncmp("log_remote_addr", k_buf + 6, 15)) + { + __u32 tmp_addr; + char * tmp; + + p += 16; + if( *p == '\0' ) + goto out; + + tmp=p; + while(*tmp) + { + if( (*tmp != '.') + && ( (*tmp < '0') + || (*tmp > '9') + ) + ) + { + *tmp = 0; + break; + } + tmp++; + } + err = rsbac_net_str_to_inet(p, &tmp_addr); + if(!err) + { +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for remote_log_addr\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac_remote_log; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_log_remote_addr to %u.%u.%u.%u\n", + NIPQUAD(tmp_addr)); + rsbac_log_remote_addr = tmp_addr; + err = count; + goto out; + } + else + { + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp) + { + get_error_name(tmp, err); + rsbac_printk(KERN_INFO + "debug_proc_write(): converting remote socket address %s failed with error %s, exiting!\n", + p, + tmp); + rsbac_kfree(tmp); + } + err = -EINVAL; + goto out; + } + } +/* Set remote port for remote logging */ + /* + * Usage: echo "debug log_remote_port #n" > /proc/rsbac_info/debug + * to set log_remote_port to given value + */ + if(!strncmp("log_remote_port", k_buf + 6, 15)) + { + __u16 tmp_port; + + p += 16; + if( *p == '\0' ) + goto out; + + tmp_port = simple_strtoul(p, NULL, 0); +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for remote_log_port\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac_remote_log; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_log_remote_port to %u\n", + tmp_port); + rsbac_log_remote_port = htons(tmp_port); + err = count; + goto out; + } +#endif + +#ifdef CONFIG_RSBAC_SYSLOG_RATE +/* Set syslog rate limit */ + /* + * Usage: echo "debug syslog_rate #n" > /proc/rsbac_info/debug + * to set rate limit to given value + */ + if(!strncmp("syslog_rate", k_buf + 6, 11)) + { + u_int tmp_rate; + + p += 12; + if( *p == '\0' ) + goto out; + + tmp_rate = simple_strtoul(p, NULL, 0); +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for syslog_rate\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_syslog_rate to %u\n", + tmp_rate); + rsbac_syslog_rate = tmp_rate; + err = count; + goto out; + } +#endif + +#ifdef CONFIG_RSBAC_FD_CACHE +/* Set fd_cache_ttl */ + /* + * Usage: echo "debug fd_cache_ttl #n" > /proc/rsbac_info/debug + * to set ttl to given value + */ + if(!strncmp("fd_cache_ttl", k_buf + 6, 12)) + { + u_int tmp_ttl; + + p += 13; + if( *p == '\0' ) + goto out; + + tmp_ttl = simple_strtoul(p, NULL, 0); +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for fd_cache_ttl\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_fd_cache_ttl to %u\n", + tmp_ttl); + rsbac_fd_cache_ttl = tmp_ttl; + err = count; + goto out; + } +#endif + +#ifdef CONFIG_RSBAC_UM_NAME_CACHE +/* Set um_name_cache_ttl */ + /* + * Usage: echo "debug um_name_cache_ttl #n" > /proc/rsbac_info/debug + * to set ttl to given value + */ + if(!strncmp("um_name_cache_ttl", k_buf + 6, 17)) + { + u_int tmp_ttl; + + p += 18; + if( *p == '\0' ) + goto out; + + tmp_ttl = simple_strtoul(p, NULL, 0); +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for um_name_cache_ttl\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_um_name_cache_ttl to %u\n", + tmp_ttl); + rsbac_um_name_cache_ttl = tmp_ttl; + err = count; + goto out; + } + +/* Set um_name_cache_disable */ + /* + * Usage: echo "debug um_name_cache_disable #n" > /proc/rsbac_info/debug + * to set ttl to given value + */ + if(!strncmp("um_name_cache_disable", k_buf + 6, 21)) + { + u_int tmp_disable; + + p += 22; + if( *p == '\0' ) + goto out; + + tmp_disable = simple_strtoul(p, NULL, 0); +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for um_name_cache_disable\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_um_name_cache_disable to %u\n", + tmp_disable); + rsbac_um_name_cache_disable = tmp_disable; + err = count; + goto out; + } +#endif + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) +/* Set rsbac_list_check_interval */ + /* + * Usage: echo "debug list_check_interval #n" > /proc/rsbac_info/debug + * to set ttl to given value + */ + if(!strncmp("list_check_interval", k_buf + 6, 19)) + { + u_int tmp_ttl; + + p += 20; + if( *p == '\0' ) + goto out; + + tmp_ttl = simple_strtoul(p, NULL, 0); +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for list_check_interval\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_list_check_interval to %u\n", + tmp_ttl); + rsbac_list_check_interval = tmp_ttl; + err = count; + goto out; + } +#endif + +#ifdef CONFIG_RSBAC_RMSG_NOSYSLOG +/* Boolean switch for disabling logging to syslog */ + /* + * Usage: echo "debug nosyslog #N" > /proc/rsbac_info/debug + * to set rsbac_nosyslog to given value + */ + if(!strncmp("nosyslog", k_buf + 6, 8)) + { + p += 9; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for nosyslog\n"); + } +#endif + rsbac_target_id.dummy = 0; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SWITCH_LOG, + task_pid(current), + T_NONE, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_nosyslog to %u\n", + debug_level); + rsbac_nosyslog = debug_level; + err = count; + goto out; + } + else + { + rsbac_printk(KERN_INFO + "debug_proc_write(): rejecting invalid nosyslog value (should be 0 or 1)\n"); + err = -EINVAL; + goto out; + } + } +#endif + +#ifdef CONFIG_RSBAC_RMSG +/* Set rsbac log messages limit */ + /* + * Usage: echo "debug rmsg_maxentries #n" > /proc/rsbac_info/debug + * to set limit to given value + */ + if(!strncmp("rmsg_maxentries", k_buf + 6, 15)) + { + u_int tmp_rate; + + p += 16; + if( *p == '\0' ) + goto out; + + tmp_rate = simple_strtoul(p, NULL, 0); +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for rmsg_maxentries\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rmsg_maxentries to %u\n", + tmp_rate); + rsbac_rmsg_maxentries = tmp_rate; + err = count; + goto out; + } +#endif + +#ifdef CONFIG_RSBAC_LOG_REMOTE +/* Set rsbac remote log messages limit */ + /* + * Usage: echo "debug log_remote_maxentries #n" > /proc/rsbac_info/debug + * to set limit to given value + */ + if(!strncmp("log_remote_maxentries", k_buf + 6, 21)) + { + u_int tmp_rate; + + p += 22; + if( *p == '\0' ) + goto out; + + tmp_rate = simple_strtoul(p, NULL, 0); +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF for log_remote_maxentries\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting log_remote_maxentries to %u\n", + tmp_rate); + rsbac_log_remote_maxentries = tmp_rate; + err = count; + goto out; + } +#endif + +#if defined(CONFIG_RSBAC_RC_LEARN) +/* Boolean switch for RC learning mode */ + /* + * Usage: echo "debug rc_learn #N" > /proc/rsbac_info/debug + * to set rsbac_rc_learn to given value + */ + if(!strncmp("rc_learn", k_buf + 6, 8)) + { + p += 9; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_target_id.dummy = 0; + rsbac_attribute_value.rc_learn = debug_level; + if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE, + task_pid(current), + T_NONE, + rsbac_target_id, + A_rc_learn, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_rc_learn to %u\n", + debug_level); + rsbac_rc_learn = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#if defined(CONFIG_RSBAC_AUTH_LEARN) +/* Boolean switch for AUTH learning mode */ + /* + * Usage: echo "debug auth_learn #N" > /proc/rsbac_info/debug + * to set rsbac_auth_learn to given value + */ + if(!strncmp("auth_learn", k_buf + 6, 10)) + { + p += 11; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_target_id.dummy = 0; + rsbac_attribute_value.auth_learn = debug_level; + if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE, + task_pid(current), + T_NONE, + rsbac_target_id, + A_auth_learn, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_auth_learn to %u\n", + debug_level); + rsbac_auth_learn = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#if defined(CONFIG_RSBAC_CAP_LEARN) +/* Boolean switch for CAP learning mode */ + /* + * Usage: echo "debug cap_learn #N" > /proc/rsbac_info/debug + * to set rsbac_cap_learn to given value + */ + if(!strncmp("cap_learn", k_buf + 6, 9)) + { + p += 10; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_target_id.dummy = 0; + rsbac_attribute_value.cap_learn = debug_level; + if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE, + task_pid(current), + T_NONE, + rsbac_target_id, + A_cap_learn, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_cap_learn to %u\n", + debug_level); + rsbac_cap_learn = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#ifdef CONFIG_RSBAC_CAP_LOG_MISSING +/* Boolean switch for CAP logging of missing caps */ + /* + * Usage: echo "debug cap_log_missing #N" > /proc/rsbac_info/debug + * to set rsbac_cap_log_missing to given value + */ + if(!strncmp("cap_log_missing", k_buf + 6, 15)) + { + p += 16; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_cap_log_missing to %u\n", + debug_level); + rsbac_cap_log_missing = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#ifdef CONFIG_RSBAC_JAIL_LOG_MISSING +/* Boolean switch for JAIL logging of missing caps */ + /* + * Usage: echo "debug jail_log_missing #N" > /proc/rsbac_info/debug + * to set rsbac_jail_log_missing to given value + */ + if(!strncmp("jail_log_missing", k_buf + 6, 16)) + { + p += 17; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_jail_log_missing to %u\n", + debug_level); + rsbac_jail_log_missing = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + + +#if defined(CONFIG_RSBAC_ACL_LEARN) +/* Boolean switch for ACL FD learning mode */ + /* + * Usage: echo "debug acl_learn_fd #N" > /proc/rsbac_info/debug + * to set rsbac_acl_learn_fd to given value + */ + if(!strncmp("acl_learn_fd", k_buf + 6, 12)) + { + p += 13; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + /* use default acls */ + rsbac_target_id.file.device = RSBAC_ZERO_DEV; + rsbac_target_id.file.inode = 0; + rsbac_target_id.file.dentry_p = NULL; + rsbac_attribute_value.acl_learn = debug_level; + + if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE, + task_pid(current), + T_FILE, + rsbac_target_id, + A_acl_learn, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_acl_learn_fd to %u\n", + debug_level); + rsbac_acl_learn_fd = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#if defined(CONFIG_RSBAC_DEBUG) + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "debug_proc_write(): calling ADF\n"); + } + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + goto out; + } + +#if defined(CONFIG_RSBAC_NET) +/* Boolean debug switch for NET data structures */ + /* + * Usage: echo "debug ds_net #N" > /proc/rsbac_info/debug + * to set rsbac_debug_ds_net to given value + */ + if(!strncmp("ds_net", k_buf + 6, 6)) + { + p += 7; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_ds_net to %u\n", + debug_level); + rsbac_debug_ds_net = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +/* Boolean debug switch for NET syscalls / AEF */ + /* + * Usage: echo "debug aef_net #N" > /proc/rsbac_info/debug + * to set rsbac_debug_aef_net to given value + */ + if(!strncmp("aef_net", k_buf + 6, 7)) + { + p += 8; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_aef_net to %u\n", + debug_level); + rsbac_debug_aef_net = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + +/* Boolean debug switch for NET decisions / ADF */ + /* + * Usage: echo "debug adf_net #N" > /proc/rsbac_info/debug + * to set rsbac_debug_adf_net to given value + */ + if(!strncmp("adf_net", k_buf + 6, 7)) + { + p += 8; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_adf_net to %u\n", + debug_level); + rsbac_debug_adf_net = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#if defined(CONFIG_RSBAC_MAC) +/* Boolean debug switch for MAC data structures */ + /* + * Usage: echo "debug ds_mac #N" > /proc/rsbac_info/debug + * to set rsbac_debug_ds_mac to given value + */ + if(!strncmp("ds_mac", k_buf + 6, 6)) + { + p += 7; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_ds_mac to %u\n", + debug_level); + rsbac_debug_ds_mac = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +/* Boolean debug switch for MAC syscalls / AEF */ + /* + * Usage: echo "debug aef_mac #N" > /proc/rsbac_info/debug + * to set rsbac_debug_aef_mac to given value + */ + if(!strncmp("aef_mac", k_buf + 6, 7)) + { + p += 8; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_aef_mac to %u\n", + debug_level); + rsbac_debug_aef_mac = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + +/* Boolean debug switch for MAC decisions / ADF */ + /* + * Usage: echo "debug adf_mac #N" > /proc/rsbac_info/debug + * to set rsbac_debug_adf_mac to given value + */ + if(!strncmp("adf_mac", k_buf + 6, 7)) + { + p += 8; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_adf_mac to %u\n", + debug_level); + rsbac_debug_adf_mac = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#if defined(CONFIG_RSBAC_DAZ) +/* Boolean debug switch for DAZ decisions / ADF */ + /* + * Usage: echo "debug adf_daz #N" > /proc/rsbac_info/debug + * to set rsbac_debug_adf_daz to given value + */ + if(!strncmp("adf_daz", k_buf + 6, 7)) + { + p += 8; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_adf_daz to %u\n", + debug_level); + rsbac_debug_adf_daz = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#if defined(CONFIG_RSBAC_RC) +/* Boolean debug switch for RC data structures */ + /* + * Usage: echo "debug ds_rc #N" > /proc/rsbac_info/debug + * to set rsbac_debug_ds_rc to given value + */ + if(!strncmp("ds_rc", k_buf + 6, 5)) + { + p += 6; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_ds_rc to %u\n", + debug_level); + rsbac_debug_ds_rc = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +/* Boolean debug switch for RC syscalls / AEF */ + /* + * Usage: echo "debug aef_rc #N" > /proc/rsbac_info/debug + * to set rsbac_debug_aef_rc to given value + */ + if(!strncmp("aef_rc", k_buf + 6, 6)) + { + p += 7; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_aef_rc to %u\n", + debug_level); + rsbac_debug_aef_rc = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + +/* Boolean debug switch for RC decisions / ADF */ + /* + * Usage: echo "debug adf_rc #N" > /proc/rsbac_info/debug + * to set rsbac_debug_adf_rc to given value + */ + if(!strncmp("adf_rc", k_buf + 6, 6)) + { + p += 7; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_adf_rc to %u\n", + debug_level); + rsbac_debug_adf_rc = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#if defined(CONFIG_RSBAC_AUTH) +/* Boolean debug switch for AUTH data structures */ + /* + * Usage: echo "debug ds_auth #N" > /proc/rsbac_info/debug + * to set rsbac_debug_ds_auth to given value + */ + if(!strncmp("ds_auth", k_buf + 6, 7)) + { + p += 8; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_ds_auth to %u\n", + debug_level); + rsbac_debug_ds_auth = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +/* Boolean debug switch for AUTH syscalls / AEF */ + /* + * Usage: echo "debug aef_auth #N" > /proc/rsbac_info/debug + * to set rsbac_debug_aef_auth to given value + */ + if(!strncmp("aef_auth", k_buf + 6, 8)) + { + p += 9; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_aef_auth to %u\n", + debug_level); + rsbac_debug_aef_auth = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + +/* Boolean debug switch for AUTH decisions / ADF */ + /* + * Usage: echo "debug adf_auth #N" > /proc/rsbac_info/debug + * to set rsbac_debug_adf_auth to given value + */ + if(!strncmp("adf_auth", k_buf + 6, 8)) + { + p += 9; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_adf_auth to %u\n", + debug_level); + rsbac_debug_adf_auth = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + +#endif + +#if defined(CONFIG_RSBAC_REG) +/* Boolean debug switch for REG */ + /* + * Usage: echo "debug reg #N" > /proc/rsbac_info/debug + * to set rsbac_debug_reg to given value + */ + if(!strncmp("reg", k_buf + 6, 3)) + { + p += 3; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_reg to %u\n", + debug_level); + rsbac_debug_reg = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#if defined(CONFIG_RSBAC_ACL) +/* Boolean debug switch for ACL data structures */ + /* + * Usage: echo "debug ds_acl #N" > /proc/rsbac_info/debug + * to set rsbac_debug_ds_acl to given value + */ + if(!strncmp("ds_acl", k_buf + 6, 6)) + { + p += 7; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_ds_acl to %u\n", + debug_level); + rsbac_debug_ds_acl = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +/* Boolean debug switch for ACL syscalls / AEF */ + /* + * Usage: echo "debug aef_acl #N" > /proc/rsbac_info/debug + * to set rsbac_debug_aef_acl to given value + */ + if(!strncmp("aef_acl", k_buf + 6, 7)) + { + p += 8; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_aef_acl to %u\n", + debug_level); + rsbac_debug_aef_acl = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + +/* Boolean debug switch for ACL decisions / ADF */ + /* + * Usage: echo "debug adf_acl #N" > /proc/rsbac_info/debug + * to set rsbac_debug_adf_acl to given value + */ + if(!strncmp("adf_acl", k_buf + 6, 7)) + { + p += 8; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_adf_acl to %u\n", + debug_level); + rsbac_debug_adf_acl = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#if defined(CONFIG_RSBAC_JAIL) +/* Boolean debug switch for JAIL syscalls / AEF */ + /* + * Usage: echo "debug aef_jail #N" > /proc/rsbac_info/debug + * to set rsbac_debug_aef_jail to given value + */ + if(!strncmp("aef_jail", k_buf + 6, 8)) + { + p += 9; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_aef_jail to %u\n", + debug_level); + rsbac_debug_aef_jail = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + +/* Boolean debug switch for JAIL decisions / ADF */ + /* + * Usage: echo "debug adf_jail #N" > /proc/rsbac_info/debug + * to set rsbac_debug_adf_jail to given value + */ + if(!strncmp("adf_jail", k_buf + 6, 8)) + { + p += 9; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_adf_jail to %u\n", + debug_level); + rsbac_debug_adf_jail = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#if defined(CONFIG_RSBAC_PAX) +/* Boolean debug switch for PAX decisions / ADF */ + /* + * Usage: echo "debug adf_pax #N" > /proc/rsbac_info/debug + * to set rsbac_debug_adf_pax to given value + */ + if(!strncmp("adf_pax", k_buf + 6, 7)) + { + p += 8; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_adf_pax to %u\n", + debug_level); + rsbac_debug_adf_pax = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#if defined(CONFIG_RSBAC_UDF) +/* Boolean debug switch for UDF decisions / ADF */ + /* + * Usage: echo "debug adf_udf #N" > /proc/rsbac_info/debug + * to set rsbac_debug_adf_udf to given value + */ + if(!strncmp("adf_udf", k_buf + 6, 7)) + { + p += 8; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_adf_udf to %u\n", + debug_level); + rsbac_debug_adf_udf = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#if defined(CONFIG_RSBAC_UM) +/* Boolean debug switch for UM data structures */ + /* + * Usage: echo "debug ds_um #N" > /proc/rsbac_info/debug + * to set rsbac_debug_ds_um to given value + */ + if(!strncmp("ds_um", k_buf + 6, 5)) + { + p += 6; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_ds_um to %u\n", + debug_level); + rsbac_debug_ds_um = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +/* Boolean debug switch for UM syscalls / AEF */ + /* + * Usage: echo "debug aef_um #N" > /proc/rsbac_info/debug + * to set rsbac_debug_aef_um to given value + */ + if(!strncmp("aef_um", k_buf + 6, 6)) + { + p += 7; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_aef_um to %u\n", + debug_level); + rsbac_debug_aef_um = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + +/* Boolean debug switch for UM decisions / ADF */ + /* + * Usage: echo "debug adf_um #N" > /proc/rsbac_info/debug + * to set rsbac_debug_adf_um to given value + */ + if(!strncmp("adf_um", k_buf + 6, 6)) + { + p += 7; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_adf_um to %u\n", + debug_level); + rsbac_debug_adf_um = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + + /* + * Usage: echo "debug ds #N" > /proc/rsbac_info/debug + * to set rsbac_debug_ds to given value + */ + if(!strncmp("ds", k_buf + 6, 2)) + { + p += 3; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_ds to %u\n", + debug_level); + rsbac_debug_ds = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + + /* + * Usage: echo "debug write #N" > /proc/rsbac_info/debug + * to set rsbac_debug_write to given value + */ + if(!strncmp("write", k_buf + 6, 5)) + { + p += 6; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_write to %u\n", + debug_level); + rsbac_debug_write = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + + /* + * Usage: echo "debug stack #N" > /proc/rsbac_info/debug + * to set rsbac_debug_stack to given value + */ + if(!strncmp("stack", k_buf + 6, 5)) + { + p += 6; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_stack to %u\n", + debug_level); + rsbac_debug_stack = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + +#ifdef CONFIG_RSBAC_MPROTECT + /* + * Usage: echo "debug mprotect #N" > /proc/rsbac_info/debug + * to set rsbac_debug_mprotect to given value + */ + if(!strncmp("mprotect", k_buf + 6, 8)) + { + p += 9; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_mprotect to %u\n", + debug_level); + rsbac_debug_mprotect = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + + /* + * Usage: echo "debug lists #N" > /proc/rsbac_info/debug + * to set rsbac_debug_lists to given value + */ + if(!strncmp("lists", k_buf + 6, 5)) + { + p += 6; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_lists to %u\n", + debug_level); + rsbac_debug_lists = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + + /* Boolean debug switch for AEF */ + /* + * Usage: echo "debug aef #N" > /proc/rsbac_info/debug + * to set rsbac_debug_aef to given value + */ + if(!strncmp("aef", k_buf + 6, 3)) + { + p += 4; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_aef to %u\n", + debug_level); + rsbac_debug_aef = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + +/* Boolean debug switch for NO_WRITE */ + /* + * Usage: echo "debug no_write #N" > /proc/rsbac_info/debug + * to set rsbac_debug_no_write to given value + */ + if(!strncmp("no_write", k_buf + 6, 8)) + { + p += 9; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_no_write to %u\n", + debug_level); + rsbac_debug_no_write = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } + +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) + /* + * Usage: echo "debug auto #N" > /proc/rsbac_info/debug + * to set rsbac_debug_auto to given value + */ + if(!strncmp("auto", k_buf + 6, 4)) + { + p += 5; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0 or 1 */ + if(!debug_level || (debug_level == 1)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_auto to %u\n", + debug_level); + rsbac_debug_auto = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif /* CONFIG_RSBAC_AUTO_WRITE > 0 */ + +#ifdef CONFIG_RSBAC_FD_CACHE + /* + * Usage: echo "debug fdcache #N" > /proc/rsbac_info/debug + * to set rsbac_debug_fdcache to given value + */ + if(!strncmp("fdcache", k_buf + 6, 7)) + { + p += 8; + + if( *p == '\0' ) + goto out; + + debug_level = simple_strtoul(p, NULL, 0); + /* only accept 0, 1 or 2 */ + if(!debug_level || (debug_level == 1) || (debug_level == 2)) + { + rsbac_printk(KERN_INFO + "debug_proc_write(): setting rsbac_debug_fdcache to %u\n", + debug_level); + rsbac_debug_fdcache = debug_level; + err = count; + goto out; + } + else + { + goto out_inv; + } + } +#endif + +#endif /* DEBUG */ + +out: + free_page((ulong) k_buf); + return err; + +out_inv: + rsbac_printk(KERN_INFO + "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n"); + err = -EINVAL; + goto out; + } + +static int debug_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, debug_proc_show, NULL); +} + +static const struct file_operations debug_proc_fops = { + .owner = THIS_MODULE, + .open = debug_proc_open, + .read = seq_read, + .write = debug_proc_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct proc_dir_entry *debug; +#endif /* defined(CONFIG_RSBAC_PROC) */ + +#if defined(CONFIG_RSBAC_LOG_REMOTE) + +/* rsbac kernel daemon for remote logging */ +static int rsbaclogd(void * dummy) + { + struct task_struct *tsk = current; + int err; + int sock_fd; + struct rsbac_log_list_item_t * log_item; + struct sockaddr_in addr; + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + mm_segment_t oldfs; + + rsbac_printk(KERN_INFO "rsbaclogd(): Initializing.\n"); + wait_event_interruptible_timeout(rsbaclogd_wait, remote_log_list_head.count, rsbac_log_remote_interval); + + /* create a socket */ +#ifndef CONFIG_RSBAC_LOG_REMOTE_TCP + sock_fd = sys_socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(sock_fd < 0) + { + rsbac_printk(KERN_WARNING + "rsbaclogd(): creating local log socket failed with error %s, exiting!\n", + get_error_name(tmp, sock_fd)); + rsbaclogd_pid = NULL; + kfree(tmp); + return -RSBAC_EWRITEFAILED; + } + /* bind local address */ + addr.sin_family = PF_INET; + addr.sin_port = htons(CONFIG_RSBAC_LOG_LOCAL_PORT); + err = rsbac_net_str_to_inet(CONFIG_RSBAC_LOG_LOCAL_ADDR, + &addr.sin_addr.s_addr); + if(err < 0) + { + rsbac_printk(KERN_WARNING + "rsbaclogd(): converting local socket address %s failed with error %s, exiting!\n", + CONFIG_RSBAC_LOG_LOCAL_ADDR, + get_error_name(tmp, err)); + sys_close(sock_fd); + rsbaclogd_pid = NULL; + kfree(tmp); + return -RSBAC_EINVALIDVALUE; + } + /* change data segment - sys_bind reads address from user space */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = sys_bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr)); + set_fs(oldfs); + if(err < 0) + { + rsbac_printk(KERN_WARNING + "rsbaclogd(): binding local socket address %u.%u.%u.%u:%u failed with error %s, exiting!\n", + NIPQUAD(addr.sin_addr.s_addr), + CONFIG_RSBAC_LOG_LOCAL_PORT, + get_error_name(tmp, err)); + sys_close(sock_fd); + rsbaclogd_pid = NULL; + kfree(tmp); + return -RSBAC_EWRITEFAILED; + } +#endif /* ifndef CONFIG_RSBAC_LOG_REMOTE_TCP */ +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_stack) + { + unsigned long * n = (unsigned long *) (current+1); + + while (!*n) + n++; + rsbac_printk(KERN_DEBUG "rsbaclogd: free stack: %lu\n", + (unsigned long) n - (unsigned long)(current+1)); + } +#endif + ignore_signals(tsk); + for(;;) + { + /* wait */ + if (!wait_event_interruptible_timeout(rsbaclogd_wait, remote_log_list_head.count, rsbac_log_remote_interval)) + continue; +#ifdef CONFIG_PM + if (try_to_freeze()) + continue; +#endif + + /* Do nothing without remote address */ + if(!rsbac_log_remote_addr || !rsbac_log_remote_port || !remote_log_list_head.head) + continue; + + +#ifdef CONFIG_RSBAC_LOG_REMOTE_TCP + sock_fd = sys_socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if(sock_fd < 0) + { + rsbac_printk(KERN_WARNING + "rsbaclogd(): creating local log socket failed with error %s, exiting!\n", + get_error_name(tmp, sock_fd)); + continue; + } + /* bind local address */ + addr.sin_family = PF_INET; + addr.sin_port = htons(CONFIG_RSBAC_LOG_LOCAL_PORT); + err = rsbac_net_str_to_inet(CONFIG_RSBAC_LOG_LOCAL_ADDR, + &addr.sin_addr.s_addr); + if(err < 0) + { + rsbac_printk(KERN_WARNING + "rsbaclogd(): converting local socket address %s failed with error %s, exiting!\n", + CONFIG_RSBAC_LOG_LOCAL_ADDR, + get_error_name(tmp, err)); + sys_close(sock_fd); + continue; + } + /* change data segment - sys_bind reads address from user space */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = sys_bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr)); + set_fs(oldfs); + if(err < 0) + { + rsbac_printk(KERN_WARNING + "rsbaclogd(): binding local socket address %u.%u.%u.%u:%u failed with error %s, exiting!\n", + NIPQUAD(addr.sin_addr.s_addr), + CONFIG_RSBAC_LOG_LOCAL_PORT, + get_error_name(tmp, err)); + sys_close(sock_fd); + continue; + } + /* Target address might have changed */ + addr.sin_family = PF_INET; + addr.sin_port = rsbac_log_remote_port; + addr.sin_addr.s_addr = rsbac_log_remote_addr; + /* connect to remote socket */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = sys_connect(sock_fd, + (struct sockaddr *)&addr, + sizeof(addr)); + set_fs(oldfs); + if(err < 0) + { + printk(KERN_WARNING + "rsbaclogd(): connecting to remote TCP address %u.%u.%u.%u:%u failed with error %s, exiting!\n", + NIPQUAD(addr.sin_addr.s_addr), + ntohs(addr.sin_port), + get_error_name(tmp, err)); + sys_close(sock_fd); + continue; + } +#else + /* Target address might have changed */ + addr.sin_family = PF_INET; + addr.sin_port = rsbac_log_remote_port; + addr.sin_addr.s_addr = rsbac_log_remote_addr; +#endif + while(remote_log_list_head.head) + { + spin_lock(&rsbac_log_remote_lock); + log_item = remote_log_list_head.head; + /* Just to be sure */ + if (!log_item) { + spin_unlock(&rsbac_log_remote_lock); + break; + } + remote_log_list_head.head = log_item->next; + if(!remote_log_list_head.head) + remote_log_list_head.tail = NULL; + remote_log_list_head.count--; + spin_unlock(&rsbac_log_remote_lock); + +#ifdef CONFIG_RSBAC_LOG_REMOTE_TCP + /* change data segment - sys_send reads data and address from user space */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = sys_send(sock_fd, + log_item->buffer, + log_item->size, + 0); + set_fs(oldfs); +#else + /* change data segment - sys_sendto reads data and address from user space */ + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = sys_sendto(sock_fd, + log_item->buffer, + log_item->size, + MSG_DONTWAIT, + (struct sockaddr *)&addr, + sizeof(addr)); + set_fs(oldfs); +#endif + if(err < log_item->size) + { + if((err < 0) && (err != -EAGAIN)) + printk(KERN_WARNING + "rsbaclogd(): sending to remote socket address %u.%u.%u.%u:%u failed with error %i!\n", + NIPQUAD(addr.sin_addr.s_addr), + ntohs(addr.sin_port), + err); + /* Restore log item to beginning of the list */ + spin_lock(&rsbac_log_remote_lock); + log_item->next = remote_log_list_head.head; + remote_log_list_head.head = log_item; + if(!remote_log_list_head.tail) + remote_log_list_head.tail = log_item; + remote_log_list_head.count++; + spin_unlock(&rsbac_log_remote_lock); + break; + } + else { + kfree(log_item); + } + } +#ifdef CONFIG_RSBAC_LOG_REMOTE_TCP + sys_close(sock_fd); +#endif + } + return 0; + } +#endif + +static int ll_conv( + void * old_desc, + void * old_data, + void * new_desc, + void * new_data) + { + rsbac_log_entry_t * new_aci = new_data; + rsbac_old_log_entry_t * old_aci = old_data; + int i; + + memcpy(new_desc, old_desc, sizeof(rsbac_adf_request_int_t)); + for(i=0; i < T_NONE - 1; i++) + (*new_aci)[i] = (*old_aci)[i]; + (*new_aci)[T_NONE - 1] = LL_denied; + (*new_aci)[T_NONE] = (*old_aci)[T_NONE - 1]; + return 0; + } + +static int ll_old_conv( + void * old_desc, + void * old_data, + void * new_desc, + void * new_data) + { + rsbac_log_entry_t * new_aci = new_data; + rsbac_old_log_entry_t * old_aci = old_data; + int i; + + memcpy(new_desc, old_desc, sizeof(rsbac_adf_request_int_t)); + for(i=0; i < T_NONE - 2; i++) + (*new_aci)[i] = (*old_aci)[i]; + (*new_aci)[T_NONE - 1] = LL_denied; + (*new_aci)[T_NONE - 2] = LL_denied; + (*new_aci)[T_NONE] = (*old_aci)[T_NONE - 1]; + return 0; + } + +rsbac_list_conv_function_t * ll_get_conv(rsbac_version_t old_version) + { + switch(old_version) + { + case RSBAC_LOG_LEVEL_OLD_VERSION: + return ll_conv; + case RSBAC_LOG_LEVEL_OLD_OLD_VERSION: + return ll_old_conv; + default: + return NULL; + } + } + + +/********************************/ +/* Init */ +/********************************/ + +#ifdef CONFIG_RSBAC_INIT_DELAY +inline void rsbac_init_debug(void) +#else +inline void __init rsbac_init_debug(void) +#endif + { + int i; +#if defined(CONFIG_RSBAC_LOG_REMOTE) + struct task_struct * rsbaclogd_thread; +#endif + + if (!debug_initialized) + { + struct rsbac_list_info_t * info_p; + int tmperr; + rsbac_enum_t * def_data_p; + + rsbac_printk(KERN_INFO "rsbac_init_debug(): Initializing\n"); + info_p = rsbac_kmalloc(sizeof(*info_p)); + if(!info_p) + { + memset(rsbac_log_levels, LL_denied, sizeof(rsbac_log_levels)); + return; + } + def_data_p = rsbac_kmalloc(sizeof(rsbac_log_entry_t)); + if(!def_data_p) + { + memset(rsbac_log_levels, LL_denied, sizeof(rsbac_log_levels)); + rsbac_kfree(info_p); + return; + } + /* register log_levels list */ + for(i=0; i<=T_NONE; i++) + def_data_p[i] = LL_denied; + info_p->version = RSBAC_LOG_LEVEL_VERSION; + info_p->key = RSBAC_LOG_LEVEL_KEY; + info_p->desc_size = sizeof(rsbac_adf_request_int_t); + info_p->data_size = sizeof(rsbac_log_entry_t); + info_p->max_age = 0; + tmperr = rsbac_list_register(RSBAC_LIST_VERSION, + &log_levels_handle, + info_p, + RSBAC_LIST_PERSIST | RSBAC_LIST_DEF_DATA, + NULL, + ll_get_conv, + def_data_p, + RSBAC_LOG_LEVEL_LIST_NAME, + RSBAC_AUTO_DEV); + rsbac_kfree(info_p); + rsbac_kfree(def_data_p); + if(tmperr) + { + char * tmp; + + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if(tmp) + { + rsbac_printk(KERN_WARNING + "rsbac_init_debug(): registering log levels list ll failed with error %s!\n", + get_error_name(tmp, tmperr)); + rsbac_kfree(tmp); + } + memset(rsbac_log_levels, LL_denied, sizeof(rsbac_log_levels)); + } + else + { + rsbac_adf_request_int_t req; + + for(req = 0; req < R_NONE; req++) + rsbac_list_get_data(log_levels_handle, &req, rsbac_log_levels[req]); + } + + #if defined(CONFIG_RSBAC_PROC) + log_levels = proc_create("log_levels", S_IFREG | S_IRUGO | S_IWUGO, proc_rsbac_root_p, &log_levels_proc_fops); + + debug = proc_create("debug", S_IFREG | S_IRUGO | S_IWUGO, proc_rsbac_root_p, &debug_proc_fops); + + #if defined(CONFIG_RSBAC_RMSG) + rmsg = proc_create("rmsg", S_IFREG | S_IRUGO, proc_rsbac_root_p, &rmsg_proc_fops); + #endif + #endif + + #if defined(CONFIG_RSBAC_LOG_REMOTE) + /* Start rsbac logging thread for auto write */ + if(!rsbac_log_remote_port) + rsbac_log_remote_port = htons(CONFIG_RSBAC_LOG_REMOTE_PORT); + tmperr = rsbac_net_str_to_inet(rsbac_log_remote_addr_string, + &rsbac_log_remote_addr); + if(tmperr < 0) + { + char * tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if(tmp) + { + get_error_name(tmp, tmperr); + rsbac_printk(KERN_WARNING + "rsbac_init_debug(): converting remote socket address %s failed with error %s, exiting!\n", + rsbac_log_remote_addr_string, + tmp); + rsbac_log_remote_addr = 0; + rsbac_kfree(tmp); + } + } + rsbaclogd_thread = kthread_create(rsbaclogd, NULL, "rsbaclogd"); + wake_up_process(rsbaclogd_thread); + rsbaclogd_pid = task_pid(rsbaclogd_thread); + rsbac_printk(KERN_INFO "rsbac_init_debug(): Started rsbaclogd thread with pid %u\n", + pid_nr(rsbaclogd_pid)); + #endif + + #ifdef CONFIG_RSBAC_SYSLOG_RATE + init_timer(&rsbac_syslog_rate_timer); + rsbac_syslog_rate_timer.function = syslog_rate_reset; + rsbac_syslog_rate_timer.data = 0; + rsbac_syslog_rate_timer.expires = jiffies + HZ; + add_timer(&rsbac_syslog_rate_timer); + #endif + + debug_initialized = TRUE; + } + + #ifdef CONFIG_RSBAC_SOFTMODE + if(rsbac_softmode) + rsbac_printk(KERN_DEBUG "rsbac_softmode is set\n"); + if(rsbac_softmode_prohibit) + rsbac_printk(KERN_DEBUG "rsbac_softmode_prohibit is set\n"); + #endif + #ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + rsbac_printk(KERN_DEBUG "rsbac_freeze is set\n"); + #endif + if(rsbac_list_recover) + rsbac_printk(KERN_DEBUG "rsbac_list_recover is set\n"); + if(rsbac_list_noread) + rsbac_printk(KERN_DEBUG "rsbac_list_noread is set\n"); + #if defined(CONFIG_RSBAC_UM_EXCL) + if(rsbac_um_no_excl) + rsbac_printk(KERN_DEBUG "rsbac_um_no_excl is set\n"); + #endif + #if defined(CONFIG_RSBAC_DAZ_CACHE) + rsbac_printk(KERN_DEBUG "rsbac_daz_ttl is %u\n", + rsbac_daz_get_ttl()); + #endif + #if defined(CONFIG_RSBAC_UDF_CACHE) + rsbac_printk(KERN_DEBUG "rsbac_udf_ttl is %u\n", + rsbac_udf_get_ttl()); + #endif + #if defined(CONFIG_RSBAC_RC_LEARN) + if(rsbac_rc_learn) + rsbac_printk(KERN_DEBUG "rsbac_rc_learn is set\n"); + #endif + #if defined(CONFIG_RSBAC_AUTH_LEARN) + if(rsbac_auth_learn) + rsbac_printk(KERN_DEBUG "rsbac_auth_learn is set\n"); + #endif + #if defined(CONFIG_RSBAC_CAP_LEARN) + if(rsbac_cap_learn) + rsbac_printk(KERN_DEBUG "rsbac_cap_learn is set\n"); + #endif + #if defined(CONFIG_RSBAC_ACL_LEARN) + if(rsbac_acl_learn_fd) + rsbac_printk(KERN_DEBUG "rsbac_acl_learn_fd is set\n"); + #endif + #ifdef CONFIG_RSBAC_CAP_PROC_HIDE + if(rsbac_cap_process_hiding) + rsbac_printk(KERN_DEBUG "rsbac_cap_process_hiding is set\n"); + #endif + #ifdef CONFIG_RSBAC_CAP_LOG_MISSING + if(rsbac_cap_log_missing) + rsbac_printk(KERN_DEBUG "rsbac_cap_log_missing is set\n"); + #endif + #ifdef CONFIG_RSBAC_JAIL_LOG_MISSING + if(rsbac_jail_log_missing) + rsbac_printk(KERN_DEBUG "rsbac_jail_log_missing is set\n"); + #endif + #ifdef CONFIG_RSBAC_RMSG_NOSYSLOG + if(rsbac_nosyslog) + rsbac_printk(KERN_DEBUG "rsbac_nosyslog is set\n"); + #endif + #ifdef CONFIG_RSBAC_SYSLOG_RATE + if(rsbac_syslog_rate != CONFIG_RSBAC_SYSLOG_RATE_DEF) + rsbac_printk(KERN_DEBUG "rsbac_syslog_rate is %u\n", + rsbac_syslog_rate); + #endif +#ifdef CONFIG_RSBAC_FD_CACHE + if(rsbac_fd_cache_disable) { + rsbac_printk(KERN_DEBUG "rsbac_fd_cache_disable is %u\n", + rsbac_fd_cache_disable); + } else { + if(rsbac_fd_cache_ttl != CONFIG_RSBAC_FD_CACHE_TTL) + rsbac_printk(KERN_DEBUG "rsbac_fd_cache_ttl is %u\n", + rsbac_fd_cache_ttl); + } + if(rsbac_fd_cache_fuse) { + rsbac_printk(KERN_DEBUG "rsbac_fd_cache_fuse is %u\n", + rsbac_fd_cache_fuse); + } + if(rsbac_fd_cache_ceph) { + rsbac_printk(KERN_DEBUG "rsbac_fd_cache_ceph is %u\n", + rsbac_fd_cache_ceph); + } +#endif +#ifdef CONFIG_RSBAC_UM_NAME_CACHE + if(rsbac_um_name_cache_disable) { + rsbac_printk(KERN_DEBUG "rsbac_um_name_cache_disable is %u\n", + rsbac_um_name_cache_disable); + } else { + if(rsbac_um_name_cache_ttl != CONFIG_RSBAC_UM_NAME_CACHE_TTL) + rsbac_printk(KERN_DEBUG "rsbac_um_name_cache_ttl is %u\n", + rsbac_um_name_cache_ttl); + } +#endif +#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) + if(rsbac_list_check_interval != CONFIG_RSBAC_LIST_CHECK_INTERVAL) + rsbac_printk(KERN_DEBUG "rsbac_list_check_interval is %u\n", + rsbac_list_check_interval); +#endif + #ifdef CONFIG_RSBAC_INIT_DELAY + if(rsbac_no_delay_init) + rsbac_printk(KERN_DEBUG "rsbac_no_delay_init is set\n"); + if(rsbac_delayed_root_str[0]) + rsbac_printk(KERN_DEBUG "rsbac_delayed_root is %s\n", + rsbac_delayed_root_str); + #endif + if(rsbac_no_defaults) + rsbac_printk(KERN_DEBUG "rsbac_no_defaults is set\n"); + +#if defined(CONFIG_RSBAC_DEBUG) + if(rsbac_debug_ds) + rsbac_printk(KERN_DEBUG "rsbac_debug_ds is set\n"); + if(rsbac_debug_write) + rsbac_printk(KERN_DEBUG "rsbac_debug_write is set\n"); + if(rsbac_debug_no_write) + rsbac_printk(KERN_DEBUG "rsbac_debug_no_write is set\n"); + if(rsbac_debug_stack) + rsbac_printk(KERN_DEBUG "rsbac_debug_stack is set\n"); + if(rsbac_debug_lists) + rsbac_printk(KERN_DEBUG "rsbac_debug_lists is set\n"); + if(rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "rsbac_debug_aef is set\n"); + if(rsbac_debug_adf_default != 1) + rsbac_printk(KERN_DEBUG "rsbac_debug_adf_default is set to %i\n", + rsbac_debug_adf_default); +#ifdef CONFIG_RSBAC_MPROTECT + if(rsbac_debug_mprotect) + rsbac_printk(KERN_DEBUG "rsbac_debug_mprotect is set\n"); +#endif + + #if defined(CONFIG_RSBAC_REG) + if(rsbac_debug_reg) + rsbac_printk(KERN_DEBUG "rsbac_debug_reg is set\n"); + #endif + + #if defined(CONFIG_RSBAC_NET) + if(rsbac_debug_ds_net) + rsbac_printk(KERN_DEBUG "rsbac_debug_ds_net is set\n"); + if(rsbac_debug_aef_net) + rsbac_printk(KERN_DEBUG "rsbac_debug_aef_net is set\n"); + if(rsbac_debug_adf_net) + rsbac_printk(KERN_DEBUG "rsbac_debug_adf_net is set\n"); + #endif + + #if defined(CONFIG_RSBAC_MAC) + if(rsbac_debug_ds_mac) + rsbac_printk(KERN_DEBUG "rsbac_debug_ds_mac is set\n"); + if(rsbac_debug_aef_mac) + rsbac_printk(KERN_DEBUG "rsbac_debug_aef_mac is set\n"); + if(rsbac_debug_adf_mac) + rsbac_printk(KERN_DEBUG "rsbac_debug_adf_mac is set\n"); + #endif + + #if defined(CONFIG_RSBAC_DAZ) + if(rsbac_debug_adf_daz) + rsbac_printk(KERN_DEBUG "rsbac_debug_adf_daz is set\n"); + #endif + + #if defined(CONFIG_RSBAC_RC) + if(rsbac_debug_ds_rc) + rsbac_printk(KERN_DEBUG "rsbac_debug_ds_rc is set\n"); + if(rsbac_debug_aef_rc) + rsbac_printk(KERN_DEBUG "rsbac_debug_aef_rc is set\n"); + if(rsbac_debug_adf_rc) + rsbac_printk(KERN_DEBUG "rsbac_debug_adf_rc is set\n"); + #endif + + #if defined(CONFIG_RSBAC_AUTH) + if(rsbac_debug_ds_auth) + rsbac_printk(KERN_DEBUG "rsbac_debug_ds_auth is set\n"); + if(rsbac_debug_aef_auth) + rsbac_printk(KERN_DEBUG "rsbac_debug_aef_auth is set\n"); + if(rsbac_debug_adf_auth) + rsbac_printk(KERN_DEBUG "rsbac_debug_adf_auth is set\n"); + #endif + + #if defined(CONFIG_RSBAC_ACL) + if(rsbac_debug_ds_acl) + rsbac_printk(KERN_DEBUG "rsbac_debug_ds_acl is set\n"); + if(rsbac_debug_aef_acl) + rsbac_printk(KERN_DEBUG "rsbac_debug_aef_acl is set\n"); + if(rsbac_debug_adf_acl) + rsbac_printk(KERN_DEBUG "rsbac_debug_adf_acl is set\n"); + #endif + + #if defined(CONFIG_RSBAC_JAIL) + if(rsbac_debug_aef_jail) + rsbac_printk(KERN_DEBUG "rsbac_debug_aef_jail is set\n"); + if(rsbac_debug_adf_jail) + rsbac_printk(KERN_DEBUG "rsbac_debug_adf_jail is set\n"); + #endif + + #if defined(CONFIG_RSBAC_PAX) + if(rsbac_debug_adf_pax) + rsbac_printk(KERN_DEBUG "rsbac_debug_adf_pax is set\n"); + #endif + + #if defined(CONFIG_RSBAC_UDF) + if(rsbac_debug_adf_udf) + rsbac_printk(KERN_DEBUG "rsbac_debug_adf_udf is set\n"); + #endif + + #if defined(CONFIG_RSBAC_UM) + if(rsbac_debug_ds_um) + rsbac_printk(KERN_DEBUG "rsbac_debug_ds_um is set\n"); + if(rsbac_debug_aef_um) + rsbac_printk(KERN_DEBUG "rsbac_debug_aef_um is set\n"); + if(rsbac_debug_adf_um) + rsbac_printk(KERN_DEBUG "rsbac_debug_adf_um is set\n"); + #endif + + #if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0) + if(rsbac_debug_auto) + rsbac_printk(KERN_DEBUG "rsbac_debug_auto is set\n"); + #endif +#ifdef CONFIG_RSBAC_FD_CACHE + if(rsbac_debug_fdcache) + rsbac_printk(KERN_DEBUG "rsbac_debug_fdcache is %u\n", rsbac_debug_fdcache); +#endif +#endif /* DEBUG */ + + } + diff --git a/rsbac/help/getname.c b/rsbac/help/getname.c new file mode 100644 index 000000000000..5165cc64cf12 --- /dev/null +++ b/rsbac/help/getname.c @@ -0,0 +1,1938 @@ +/************************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2017: */ +/* Amon Ott */ +/* Helper functions for all parts */ +/* Last modified: 21/Mar/2017 */ +/************************************* */ + +#include +#include +#include +#include +#include + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_RSBAC_LOG_PROGRAM_FILE +#include +#endif +#else +#include +#include +#include +#endif + +static char request_list[R_NONE + 1][24] = { + "ADD_TO_KERNEL", + "ALTER", + "APPEND_OPEN", + "CHANGE_GROUP", + "CHANGE_OWNER", + "CHDIR", + "CLONE", + "CLOSE", + "CREATE", + "DELETE", + "EXECUTE", + "GET_PERMISSIONS_DATA", + "GET_STATUS_DATA", + "LINK_HARD", + "MODIFY_ACCESS_DATA", + "MODIFY_ATTRIBUTE", + "MODIFY_PERMISSIONS_DATA", + "MODIFY_SYSTEM_DATA", + "MOUNT", + "READ", + "READ_ATTRIBUTE", + "READ_WRITE_OPEN", + "READ_OPEN", + "REMOVE_FROM_KERNEL", + "RENAME", + "SEARCH", + "SEND_SIGNAL", + "SHUTDOWN", + "SWITCH_LOG", + "SWITCH_MODULE", + "TERMINATE", + "TRACE", + "TRUNCATE", + "UMOUNT", + "WRITE", + "WRITE_OPEN", + "MAP_EXEC", + "BIND", + "LISTEN", + "ACCEPT", + "CONNECT", + "SEND", + "RECEIVE", + "NET_SHUTDOWN", + "CHANGE_DAC_EFF_OWNER", + "CHANGE_DAC_FS_OWNER", + "CHANGE_DAC_EFF_GROUP", + "CHANGE_DAC_FS_GROUP", + "IOCTL", + "LOCK", + "AUTHENTICATE", + "MOVETO", + "NONE" +}; + +static char result_list[UNDEFINED + 1][12] = { + "NOT_GRANTED", + "GRANTED", + "DO_NOT_CARE", + "UNDEFINED" +}; + +static rsbac_switch_target_int_t attr_mod_list[A_none + 1] = { + SW_GEN, /* pseudo */ + SW_MAC, /* security_level */ + SW_MAC, /* initial_security_level */ + SW_MAC, /* local_sec_level */ + SW_MAC, /* remote_sec_level */ + SW_MAC, /* min_security_level */ + SW_MAC, /* mac_categories */ + SW_MAC, /* mac_initial_categories */ + SW_MAC, /* local_mac_categories */ + SW_MAC, /* remote_mac_categories */ + SW_MAC, /* mac_min_categories */ + SW_MAC, /* mac_user_flags */ + SW_MAC, /* mac_process_flags */ + SW_MAC, /* mac_file_flags */ + SW_NONE, /* system_role */ + SW_MAC, /* mac_role */ + SW_DAZ, /* daz_role */ + SW_FF, /* ff_role */ + SW_AUTH, /* auth_role */ + SW_CAP, /* cap_role */ + SW_JAIL, /* jail_role */ + SW_PAX, /* pax_role */ + SW_MAC, /* current_sec_level */ + SW_MAC, /* mac_curr_categories */ + SW_MAC, /* min_write_open */ + SW_MAC, /* min_write_categories */ + SW_MAC, /* max_read_open */ + SW_MAC, /* max_read_categories */ + SW_MAC, /* mac_auto */ + SW_MAC, /* mac_check */ + SW_MAC, /* mac_prop_trusted */ + SW_NONE, /* pm_role */ + SW_NONE, /* pm_process_type */ + SW_NONE, /* pm_current_task */ + SW_NONE, /* pm_object_class */ + SW_NONE, /* local_pm_object_class */ + SW_NONE, /* remote_pm_object_class */ + SW_NONE, /* pm_ipc_purpose */ + SW_NONE, /* local_pm_ipc_purpose */ + SW_NONE, /* remote_pm_ipc_purpose */ + SW_NONE, /* pm_object_type */ + SW_NONE, /* local_pm_object_type */ + SW_NONE, /* remote_pm_object_type */ + SW_NONE, /* pm_program_type */ + SW_NONE, /* pm_tp */ + SW_NONE, /* pm_task_set */ + SW_DAZ, /* daz_scanned */ + SW_DAZ, /* daz_scanner */ + SW_FF, /* ff_flags */ + SW_RC, /* rc_type */ + SW_RC, /* rc_select_type */ + SW_RC, /* local_rc_type */ + SW_RC, /* remote_rc_type */ + SW_RC, /* rc_type_fd */ + SW_RC, /* rc_type_nt */ + SW_RC, /* rc_force_role */ + SW_RC, /* rc_initial_role */ + SW_RC, /* rc_role */ + SW_RC, /* rc_def_role */ + SW_AUTH, /* auth_may_setuid */ + SW_AUTH, /* auth_may_set_cap */ + SW_AUTH, /* auth_learn */ + SW_CAP, /* min_caps */ + SW_CAP, /* max_caps */ + SW_CAP, /* max_caps_user */ + SW_CAP, /* max_caps_program */ + SW_JAIL, /* jail_id */ + SW_JAIL, /* jail_parent */ + SW_JAIL, /* jail_ip */ + SW_JAIL, /* jail_flags */ + SW_JAIL, /* jail_max_caps */ + SW_JAIL, /* jail_scd_get */ + SW_JAIL, /* jail_scd_modify */ + SW_PAX, /* pax_flags */ + SW_RES, /* res_role */ + SW_RES, /* res_min */ + SW_RES, /* res_max */ + SW_GEN, /* log_array_low */ + SW_GEN, /* local_log_array_low */ + SW_GEN, /* remote_log_array_low */ + SW_GEN, /* log_array_high */ + SW_GEN, /* local_log_array_high */ + SW_GEN, /* remote_log_array_high */ + SW_GEN, /* log_program_based */ + SW_GEN, /* log_user_based */ + SW_GEN, /* symlink_add_remote_ip */ + SW_GEN, /* symlink_add_uid */ + SW_GEN, /* symlink_add_mac_level */ + SW_GEN, /* symlink_add_rc_role */ + SW_GEN, /* allow_write_exec */ + SW_CAP, /* cap_process_hiding */ + SW_GEN, /* fake_root_uid */ + SW_GEN, /* audit_uid */ + SW_GEN, /* auid_exempt */ + SW_AUTH, /* auth_last_auth */ + SW_GEN, /* remote_ip */ + SW_CAP, /* cap_ld_env */ + SW_DAZ, /* daz_do_scan */ + SW_GEN, /* vset */ + SW_UDF, /* udf_role */ + SW_UDF, /* udf_checked */ + SW_UDF, /* udf_checker */ + SW_UDF, /* udf_do_check */ +#ifdef __KERNEL__ + /* adf-request helpers */ + SW_NONE, /* group */ + SW_NONE, /* signal */ + SW_NONE, /* mode */ + SW_NONE, /* nlink */ + SW_NONE, /* switch_target */ + SW_NONE, /* mod_name */ + SW_NONE, /* request */ + SW_NONE, /* trace_request */ + SW_NONE, /* auth_add_f_cap */ + SW_NONE, /* auth_remove_f_cap */ + SW_NONE, /* auth_get_caplist */ + SW_NONE, /* prot_bits */ + SW_NONE, /* internal */ + SW_NONE, /* create_data */ + SW_NONE, /* new_object */ + SW_NONE, /* rlimit */ + SW_NONE, /* new_dir_dentry_p */ + SW_NONE, /* auth_start_uid */ + SW_NONE, /* auth_start_euid */ + SW_NONE, /* auth_start_gid */ + SW_NONE, /* auth_start_egid */ + SW_NONE, /* acl_learn */ + SW_NONE, /* priority */ + SW_NONE, /* pgid */ + SW_NONE, /* kernel_thread */ + SW_NONE, /* open_flag */ + SW_NONE, /* reboot_cmd */ + SW_NONE, /* setsockopt_level */ + SW_NONE, /* ioctl_cmd */ + SW_NONE, /* f_mode */ + SW_NONE, /* process */ + SW_NONE, /* sock_type */ + SW_NONE, /* pagenr */ + SW_NONE, /* cap_learn */ + SW_NONE, /* rc_learn */ + SW_NONE, /* old_dir_inode_p */ +#endif + SW_NONE /* none */ +}; + +static char attribute_list[A_none + 1][23] = { + "pseudo", + "security_level", + "initial_security_level", + "local_sec_level", + "remote_sec_level", + "min_security_level", + "mac_categories", + "mac_initial_categories", + "local_mac_categories", + "remote_mac_categories", + "mac_min_categories", + "mac_user_flags", + "mac_process_flags", + "mac_file_flags", + "system_role", + "mac_role", + "daz_role", + "ff_role", + "auth_role", + "cap_role", + "jail_role", + "pax_role", + "current_sec_level", + "mac_curr_categories", + "min_write_open", + "min_write_categories", + "max_read_open", + "max_read_categories", + "mac_auto", + "mac_check", + "mac_prop_trusted", + "pm_role", + "pm_process_type", + "pm_current_task", + "pm_object_class", + "local_pm_object_class", + "remote_pm_object_class", + "pm_ipc_purpose", + "local_pm_ipc_purpose", + "remote_pm_ipc_purpose", + "pm_object_type", + "local_pm_object_type", + "remote_pm_object_type", + "pm_program_type", + "pm_tp", + "pm_task_set", + "daz_scanned", + "daz_scanner", + "ff_flags", + "rc_type", + "rc_select_type", + "local_rc_type", + "remote_rc_type", + "rc_type_fd", + "rc_type_nt", + "rc_force_role", + "rc_initial_role", + "rc_role", + "rc_def_role", + "auth_may_setuid", + "auth_may_set_cap", + "auth_learn", + "min_caps", + "max_caps", + "max_caps_user", + "max_caps_program", + "jail_id", + "jail_parent", + "jail_ip", + "jail_flags", + "jail_max_caps", + "jail_scd_get", + "jail_scd_modify", + "pax_flags", + "res_role", + "res_min", + "res_max", + "log_array_low", + "local_log_array_low", + "remote_log_array_low", + "log_array_high", + "local_log_array_high", + "remote_log_array_high", + "log_program_based", + "log_user_based", + "symlink_add_remote_ip", + "symlink_add_uid", + "symlink_add_mac_level", + "symlink_add_rc_role", + "allow_write_exec", + "cap_process_hiding", + "fake_root_uid", + "audit_uid", + "auid_exempt", + "auth_last_auth", + "remote_ip", + "cap_ld_env", + "daz_do_scan", + "vset", + "udf_role", + "udf_checked", + "udf_checker", + "udf_do_check", +#ifdef __KERNEL__ + /* adf-request helpers */ + "owner", + "group", + "signal", + "mode", + "nlink", + "switch_target", + "mod_name", + "request", + "trace_request", + "auth_add_f_cap", + "auth_remove_f_cap", + "auth_get_caplist", + "prot_bits", + "internal", + "create_data", + "new_object", + "rlimit", + "new_dir_dentry_p", + "auth_start_uid", + "auth_start_euid", + "auth_start_gid", + "auth_start_egid", + "acl_learn", + "priority", + "pgid", + "kernel_thread", + "open_flag", + "reboot_cmd", + "setsockopt_level", + "ioctl_cmd", + "f_mode", + "process", + "sock_type", + "pagenr", + "cap_learn", + "rc_learn", + "old_dir_inode_p", +#endif + "none" +}; + +static char target_list[T_NONE + 1][11] = { + "FILE", + "DIR", + "FIFO", + "SYMLINK", + "DEV", + "IPC", + "SCD", + "USER", + "PROCESS", + "NETDEV", + "NETTEMP", + "NETOBJ", + "NETTEMP_NT", + "GROUP", + "FD", + "UNIXSOCK", + "NONE" +}; + +static char ipc_target_list[I_none + 1][9] = { + "sem", + "msg", + "shm", + "anonpipe", + "mqueue", + "anonunix", + "none" +}; + +static char switch_target_list[SW_NONE + 1][12] = { + "GEN", + "MAC", + "UDF", + "DAZ", + "FF", + "RC", + "AUTH", + "REG", + "ACL", + "CAP", + "JAIL", + "RES", + "PAX", + "SOFTMODE", + "MPROTECT", + "UM", + "FREEZE", + "NONE" +}; + +static char error_list[RSBAC_EMAX][26] = { + "RSBAC_EPERM", + "RSBAC_EACCESS", + "RSBAC_EREADFAILED", + "RSBAC_EWRITEFAILED", + "RSBAC_EINVALIDPOINTER", + "RSBAC_ENOROOTDIR", + "RSBAC_EPATHTOOLONG", + "RSBAC_ENOROOTDEV", + "RSBAC_ENOTFOUND", + "RSBAC_ENOTINITIALIZED", + "RSBAC_EREINIT", + "RSBAC_ECOULDNOTADDDEVICE", + "RSBAC_ECOULDNOTADDITEM", + "RSBAC_ECOULDNOTCREATEPATH", + "RSBAC_EINVALIDATTR", + "RSBAC_EINVALIDDEV", + "RSBAC_EINVALIDTARGET", + "RSBAC_EINVALIDVALUE", + "RSBAC_EEXISTS", + "RSBAC_EINTERNONLY", + "RSBAC_EINVALIDREQUEST", + "RSBAC_ENOTWRITABLE", + "RSBAC_EMALWAREDETECTED", + "RSBAC_ENOMEM", + "RSBAC_EDECISIONMISMATCH", + "RSBAC_EINVALIDVERSION", + "RSBAC_EINVALIDMODULE", + "RSBAC_EEXPIRED", + "RSBAC_EMUSTCHANGE", + "RSBAC_EBUSY", + "RSBAC_EINVALIDTRANSACTION", + "RSBAC_EWEAKPASSWORD", + "RSBAC_EINVALIDLIST", + "RSBAC_EFROMINTERRUPT" +}; + +static char scd_type_list[ST_none + 1][17] = { + "time_strucs", + "clock", + "host_id", + "net_id", + "ioports", + "rlimit", + "swap", + "syslog", + "rsbac", + "rsbac_log", + "other", + "kmem", + "network", + "firewall", + "priority", + "sysfs", + "rsbac_remote_log", + "quota", + "sysctl", + "nfsd", + "ksyms", + "mlock", + "capability", + "kexec", + "videomem", + "none" +}; + +/* Attribute types */ + +#ifndef __KERNEL__ +static char attribute_param_list[A_none + 1][194] = { + "user-pseudo (positive long integer)", /* pseudo */ + "0 = unclassified, 1 = confidential, 2 = secret,\n\t3 = top secret, 254 = inherit, max. level 252", /* security_level */ + "0 = unclassified, 1 = confidential, 2 = secret,\n\t3 = top secret, 254 = inherit, max. level 252", /* initial_security_level */ + "0 = unclassified, 1 = confidential, 2 = secret,\n\t3 = top secret, 254 = inherit, max. level 252", /* local_sec_level */ + "0 = unclassified, 1 = confidential, 2 = secret,\n\t3 = top secret, 254 = inherit, max. level 252", /* remote_sec_level */ + "0 = unclassified, 1 = confidential, 2 = secret,\n\t3 = top secret, 254 = inherit, max. level 252", /* min_security_level */ + "Bit Set String of length 64 for all categories", /* mac_categories */ + "Bit Set String of length 64 for all categories", /* mac_initial_categories */ + "Bit Set String of length 64 for all categories", /* local_mac_categories */ + "Bit Set String of length 64 for all categories", /* remote_mac_categories */ + "Bit Set String of length 64 for all categories", /* mac_min_categories */ + "1 = override, 4 = trusted, 8 = write_up, 16 = read_up,\n\t32 = write_down, 64 = allow_mac_auto", /* mac_user_flags */ + "1 = override, 2 = auto, 4 = trusted, 8 = write_up,\n\t16 = read_up, 32 = write_down, 128 = prop_trusted", /* mac_process_flags */ + "2 = auto, 4 = trusted, 8 = write_up, 16 = read_up,\n\t32 = write_down", /* mac_file_flags */ + "0 = user, 1 = security officer, 2 = administrator,\n\t3 = auditor", /* system_role */ + "0 = user, 1 = security officer, 2 = administrator,\n\t3 = auditor", /* mac_role */ + "0 = user, 1 = security officer, 2 = administrator,\n\t3 = auditor", /* daz_role */ + "0 = user, 1 = security officer, 2 = administrator,\n\t3 = auditor", /* ff_role */ + "0 = user, 1 = security officer, 2 = administrator,\n\t3 = auditor", /* auth_role */ + "0 = user, 1 = security officer, 2 = administrator,\n\t3 = auditor", /* cap_role */ + "0 = user, 1 = security officer, 2 = administrator,\n\t3 = auditor", /* jail_role */ + "0 = user, 1 = security officer, 2 = administrator,\n\t3 = auditor", /* pax_role */ + "0 = unclassified, 1 = confidential, 2 = secret,\n\t3 = top secret, max. level 252", /* current_sec_level */ + "Bit Set String of length 64 for all categories", /* mac_curr_categories */ + "0 = unclassified, 1 = confidential, 2 = secret,\n\t3 = top secret, max. level 252", /* min_write_open */ + "Bit Set String of length 64 for all categories", /* min_write_categories */ + "0 = unclassified, 1 = confidential, 2 = secret,\n\t3 = top secret, max. level 252", /* max_read_open */ + "Bit Set String of length 64 for all categories", /* max_read_categories */ + "0 = no, 1 = yes, 2 = inherit (default value)", /* mac_auto */ + "0 = false, 1 = true", /* mac_check */ + "0 = false, 1 = true", /* mac_prop_trusted */ + "0 = user, 1 = security officer, 2 = data protection officer,\n\t3 = TP-manager, 4 = system-admin", /* pm_role */ + "0 = none, 1 = TP", /* pm_process_type */ + "Task-ID (positive integer)", /* pm_current_task */ + "Class-ID (positive integer)", /* pm_object_class */ + "Class-ID (positive integer)", /* local_pm_object_class */ + "Class-ID (positive integer)", /* remote_pm_object_class */ + "Purpose-ID (positive integer)", /* pm_ipc_purpose */ + "Purpose-ID (positive integer)", /* local_pm_ipc_purpose */ + "Purpose-ID (positive integer)", /* remote_pm_ipc_purpose */ + "0 = none, 1 = TP, 2 = personal data, 3 = non-personal data,\n\t4 = ipc, 5 = dir", /* pm_object_type */ + "0 = none, 1 = TP, 2 = personal data, 3 = non-personal data,\n\t4 = ipc, 5 = dir", /* local_pm_object_type */ + "0 = none, 1 = TP, 2 = personal data, 3 = non-personal data,\n\t4 = ipc, 5 = dir", /* remote_pm_object_type */ + "0 = none, 1 = TP", /* pm_program_type */ + "TP-ID (positive integer)", /* pm_tp */ + "pm-task-list-ID (positive integer)", /* pm_task_set */ + "0 = unscanned, 1 = infected, 2 = clean", /* daz_scanned */ + "0 = FALSE, 1 = TRUE", /* daz_scanner */ + "1 = read_only, 2 = execute_only, 4 = search_only, 8 = write_only,\n\t16 = secure_delete, 32 = no_execute, 64 = no_delete_or_rename,\n\t128 = add_inherited (or'd), 256 = append_only, 512 = no_mount", /* ff_flags */ + "RC-type-id", /* rc_type */ + "RC-type-id (-7 = use fd)", /* rc_select_type */ + "RC-type-id", /* local_rc_type */ + "RC-type-id", /* remote_rc_type */ + "RC-type-id (-2 = inherit from parent)", /* rc_type_fd */ + "RC-type-id", /* rc_type_nt */ + "RC-role-id (-1 = inherit_user, -2 = inherit_process (keep),\n\t-3 = inherit_parent (def.),\n\t-4 = inherit_user_on_chown_only (root default)", /* rc_force_role */ + "RC-role-id (-3 = inherit_parent (default),\n\t-5 = use_force_role (root default)", /* rc_initial_role */ + "RC-role-id", /* rc_role */ + "RC-role-id", /* rc_def_role */ + "0 = off, 1 = full, 2 = last_auth_only, 3 = last_auth_and_gid", /* auth_may_setuid */ + "0 = false, 1 = true", /* auth_may_set_cap */ + "0 = false, 1 = true", /* auth_learn */ + "Bit-Vector value or name list of desired caps", /* min_caps */ + "Bit-Vector value or name list of desired caps", /* max_caps */ + "Bit-Vector value or name list of desired caps", /* max_caps_user */ + "Bit-Vector value or name list of desired caps", /* max_caps_program */ + "JAIL ID (0 = off)", /* jail_id */ + "JAIL ID (0 = no parent jail)", /* jail_parent */ + "JAIL IP address a.b.c.d", /* jail_ip */ + "JAIL flags (or'd, 1 = allow external IPC, 2 = allow all net families,\n\t4 = allow_rlimit, 8 = allow raw IP, 16 = auto adjust IP,\n\t32 = allow localhost, 64 = allow scd clock)", /* jail_flags */ + "Bit-Vector value or name list of desired caps", /* jail_max_caps */ + "List of SCD targets", /* jail_scd_get */ + "List of SCD targets", /* jail_scd_modify */ + "PAX flags with capital=on, non-capital=off, e.g. PeMRxS", /* pax_flags */ + "0 = user, 1 = security officer, 2 = administrator", /* res_role */ + "array of non-negative integer values, all 0 for unset", /* res_min */ + "array of non-negative integer values, all 0 for unset", /* res_max */ + "Bit-String for all Requests, low bit", /* log_array_low */ + "Bit-String for all Requests, low bit", /* local_log_array_low */ + "Bit-String for all Requests, low bit", /* remote_log_array_low */ + "Bit-String for all Requests, high bit (l=0,h=0 = none, l=1,h=0 = denied,\n\tl=0,h=1 = full, l=1,h=1 = request based)", /* log_array_high */ + "Bit-String for all Requests, high bit (l=0,h=0 = none, l=1,h=0 = denied,\n\tl=0,h=1 = full, l=1,h=1 = request based)", /* local_log_array_high */ + "Bit-String for all Requests, high bit (l=0,h=0 = none, l=1,h=0 = denied,\n\tl=0,h=1 = full, l=1,h=1 = request based)", /* remote_log_array_high */ + "Bit-String for all Requests", /* log_program_based */ + "Bit-String for all Requests", /* log_user_based */ + "Number of bytes to add, 0 to turn off", /* symlink_add_remote_ip */ + "0 = false, 1 = true", /* symlink_add_uid */ + "0 = false, 1 = true", /* symlink_add_mac_level */ + "0 = false, 1 = true", /* symlink_add_rc_role */ + "0 = false, 1 = true, 2 = inherit (default)", /* allow_write_exec */ + "0 = off (default), 1 = from other users, 2 = full", /* cap_process_hiding */ + "0 = off (default), 1 = uid_only, 2 = euid_only, 3 = both", /* fake_root_uid */ + "-3 = unset, uid otherwise", /* audit_uid */ + "-3 = unset, uid otherwise", /* auid_exempt */ + "-3 = unset, uid otherwise", /* auth_last_auth */ + "32 Bit value in network byte order", /* remote_ip */ + "0 = disallow executing of program file with LD_ variables set,\n\t1 = do not care (default)", /* cap_ld_env */ + "0 = never, 1 = registered, 2 = always, 3 = inherit", /* daz_do_scan */ + "non-negative virtual set number, 0 = default main set", + "0 = user, 1 = security officer, 2 = administrator,\n\t3 = auditor", /* udf_role */ + "0 = unchecked, 1 = denied, 2 = allowed", /* udf_checked */ + "0 = FALSE, 1 = TRUE", /* udf_checker */ + "0 = never, 1 = always, 2 = inherit", /* udf_do_check */ + "INVALID!" +}; +#endif + +static char log_level_list[LL_invalid + 1][9] = { + "none", + "denied", + "full", + "request", + "invalid!" +}; + +static char cap_list[RSBAC_CAP_MAX + 1][17] = { + "CHOWN", + "DAC_OVERRIDE", + "DAC_READ_SEARCH", + "FOWNER", + "FSETID", + "KILL", + "SETGID", + "SETUID", + "SETPCAP", + "LINUX_IMMUTABLE", + "NET_BIND_SERVICE", + "NET_BROADCAST", + "NET_ADMIN", + "NET_RAW", + "IPC_LOCK", + "IPC_OWNER", + "SYS_MODULE", + "SYS_RAWIO", + "SYS_CHROOT", + "SYS_PTRACE", + "SYS_PACCT", + "SYS_ADMIN", + "SYS_BOOT", + "SYS_NICE", + "SYS_RESOURCE", + "SYS_TIME", + "SYS_TTY_CONFIG", + "MKNOD", + "LEASE", + "AUDIT_WRITE", + "AUDIT_CONTROL", + "SETFCAP", + "MAC_OVERRIDE", + "MAC_ADMIN", + "NONE" +}; + +#ifdef CONFIG_RSBAC_XSTATS +static char syscall_list[RSYS_none + 1][30] = { + "version", + "stats", + "check", + "get_attr", + "get_attr_n", + "set_attr", + "set_attr_n", + "remove_target", + "remove_target_n", + "net_list_all_netdev", + "net_template", + "net_list_all_template", + "switch", + "get_switch", + "adf_log_switch", + "get_adf_log", + "write", + "log", + "mac_set_curr_level", + "mac_get_curr_level", + "mac_get_max_level", + "mac_get_min_level", + "mac_add_p_tru", + "mac_remove_p_tru", + "mac_add_f_tru", + "mac_remove_f_tru", + "mac_get_f_trulist", + "mac_get_p_trulist", + "stats_pm", + "pm", + "pm_change_current_task", + "pm_create_file", + "daz_flush_cache", + "rc_copy_role", + "rc_copy_type", + "rc_get_item", + "rc_set_item", + "rc_change_role", + "rc_get_eff_rights_n", + "rc_get_list", + "auth_add_p_cap", + "auth_remove_p_cap", + "auth_add_f_cap", + "auth_remove_f_cap", + "auth_get_f_caplist", + "auth_get_p_caplist", + "acl", + "acl_n", + "acl_get_rights", + "acl_get_rights_n", + "acl_get_tlist", + "acl_get_tlist_n", + "acl_get_mask", + "acl_get_mask_n", + "acl_group", + "reg", + "jail", + "init", + "rc_get_current_role", + "um_auth_name", + "um_auth_uid", + "um_add_user", + "um_add_group", + "um_add_gm", + "um_mod_user", + "um_mod_group", + "um_get_user_item", + "um_get_group_item", + "um_remove_user", + "um_remove_group", + "um_remove_gm", + "um_user_exists", + "um_group_exists", + "um_get_next_user", + "um_get_user_list", + "um_get_gm_list", + "um_get_gm_user_list", + "um_get_group_list", + "um_get_uid", + "um_get_gid", + "um_set_pass", + "um_set_pass_name", + "um_set_group_pass", + "um_check_account", + "um_check_account_name", + "list_ta_begin", + "list_ta_refresh", + "list_ta_commit", + "list_ta_forget", + "list_all_dev", + "acl_list_all_dev", + "list_all_user", + "acl_list_all_user", + "list_all_group", + "acl_list_all_group", + "list_all_ipc", + "rc_select_fd_create_type", + "um_select_vset", + "um_add_onetime", + "um_add_onetime_name", + "um_remove_all_onetime", + "um_remove_all_onetime_name", + "um_count_onetime", + "um_count_onetime_name", + "list_ta_begin_name", + "um_get_max_history", + "um_get_max_history_name", + "um_set_max_history", + "um_set_max_history_name", + "udf_flush_cache", + "api_min_version", + "api_max_version", + "none" +}; + +char *rsbac_get_syscall_name(char *syscall_name, + enum rsbac_syscall_t syscall) +{ + if (!syscall_name) + return (NULL); + if (syscall >= RSYS_none) + strcpy(syscall_name, "ERROR!"); + else + strcpy(syscall_name, syscall_list[syscall]); + return (syscall_name); +} +#endif + +/*****************************************/ + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(get_request_name); +#endif +#endif + +char *get_request_name(char *request_name, + enum rsbac_adf_request_t request) +{ + if (!request_name) + return (NULL); + if (request >= R_NONE) + strcpy(request_name, "ERROR!"); + else + strcpy(request_name, request_list[request]); + return (request_name); +} + +enum rsbac_adf_request_t get_request_nr(const char *request_name) +{ + enum rsbac_adf_request_t i; + + if (!request_name) + return (R_NONE); + for (i = 0; i < R_NONE; i++) { + if (!strcmp(request_name, request_list[i])) { + return (i); + } + } + return (R_NONE); +} + + +char *get_result_name(char *res_name, enum rsbac_adf_req_ret_t res) +{ + if (!res_name) + return (NULL); + if (res > UNDEFINED) + strcpy(res_name, "ERROR!"); + else + strcpy(res_name, result_list[res]); + return (res_name); +} + +enum rsbac_adf_req_ret_t get_result_nr(const char *res_name) +{ + enum rsbac_adf_req_ret_t i; + + if (!res_name) + return (UNDEFINED); + for (i = 0; i < UNDEFINED; i++) { + if (!strcmp(res_name, result_list[i])) { + return (i); + } + } + return (UNDEFINED); +} + + +enum rsbac_switch_target_t get_attr_module(enum rsbac_attribute_t attr) +{ + if (attr > A_none) + return SW_NONE; + else + return attr_mod_list[attr]; +} + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(get_attribute_name); +#endif +#endif + +char *get_attribute_name(char *attr_name, enum rsbac_attribute_t attr) +{ + if (!attr_name) + return (NULL); + if (attr > A_none) + strcpy(attr_name, "ERROR!"); + else + strcpy(attr_name, attribute_list[attr]); + return (attr_name); +} + +enum rsbac_attribute_t get_attribute_nr(const char *attr_name) +{ + enum rsbac_attribute_t i; + + if (!attr_name) + return (A_none); + for (i = 0; i < A_none; i++) { + if (!strcmp(attr_name, attribute_list[i])) { + return (i); + } + } + return (A_none); +} + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(get_attribute_value_name); +#endif +#endif + +char *get_attribute_value_name(char *attr_val_name, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t *attr_val_p) +{ + if (!attr_val_name) + return (NULL); + if (attr > A_none) + strcpy(attr_val_name, "ERROR!"); + else + switch (attr) { + case A_none: + strcpy(attr_val_name, "none"); + break; +#ifdef __KERNEL__ + case A_create_data: + { + char *tmp = + rsbac_kmalloc(RSBAC_MAXNAMELEN); + + if (tmp) { + if (attr_val_p->create_data. + dentry_p) + snprintf(attr_val_name, + RSBAC_MAXNAMELEN - + 1, + "%s %s, mode %o", + get_target_name_only + (tmp, + attr_val_p-> + create_data. + target), + attr_val_p-> + create_data. + dentry_p->d_name. + name, + attr_val_p-> + create_data. + mode & S_IALLUGO); + else + snprintf(attr_val_name, + RSBAC_MAXNAMELEN - + 1, "%s, mode %o", + get_target_name_only + (tmp, + attr_val_p-> + create_data. + target), + attr_val_p-> + create_data. + mode & S_IALLUGO); + rsbac_kfree(tmp); + } + } + break; + case A_mode: + sprintf(attr_val_name, "%o", attr_val_p->mode); + break; + case A_rlimit: + sprintf(attr_val_name, "%u:%lu:%lu", + attr_val_p->rlimit.resource, + attr_val_p->rlimit.limit.rlim_cur, + attr_val_p->rlimit.limit.rlim_max); + break; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + case A_owner: + if(RSBAC_UID_SET(attr_val_p->owner)) + sprintf(attr_val_name, "%u/%u", + RSBAC_UID_SET(attr_val_p->owner), + RSBAC_UID_NUM(attr_val_p->owner)); + else + sprintf(attr_val_name, "%u", + RSBAC_UID_NUM(attr_val_p->owner)); + break; + case A_group: + if(RSBAC_GID_SET(attr_val_p->group)) + sprintf(attr_val_name, "%u/%u", + RSBAC_GID_SET(attr_val_p->group), + RSBAC_GID_NUM(attr_val_p->group)); + else + sprintf(attr_val_name, "%u", + RSBAC_GID_NUM(attr_val_p->group)); + break; +#endif + case A_priority: + sprintf(attr_val_name, "%i", attr_val_p->priority); + break; + case A_process: + case A_pgid: + { + struct task_struct *task_p; + + task_p = get_pid_task(attr_val_p->process, PIDTYPE_PID); + if (task_p) { + if (pid_alive(task_p)) { + if(task_p->parent) + sprintf(attr_val_name, "%u(%s,parent=%u(%s))", task_p->pid, task_p->comm, task_p->parent->pid, task_p->parent->comm); + else + sprintf(attr_val_name, "%u(%s)", task_p->pid, task_p->comm); + } else { + sprintf(attr_val_name, "%u(dead)", pid_nr(attr_val_p->process)); + } + put_task_struct(task_p); + } else { + sprintf(attr_val_name, "%u", pid_nr(attr_val_p->process)); + } + } + break; + case A_mod_name: + if (attr_val_p->mod_name) + strncpy(attr_val_name, + attr_val_p->mod_name, + RSBAC_MAXNAMELEN - 1); + else + strcpy(attr_val_name, "unknown"); + attr_val_name[RSBAC_MAXNAMELEN - 1] = 0; + break; + case A_auth_add_f_cap: + case A_auth_remove_f_cap: +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if( RSBAC_UID_SET(attr_val_p->auth_cap_range.first) + || RSBAC_UID_SET(attr_val_p->auth_cap_range.last) + ) + sprintf(attr_val_name, "%u/%u:%u/%u", + RSBAC_UID_SET(attr_val_p->auth_cap_range.first), + RSBAC_UID_NUM(attr_val_p->auth_cap_range.first), + RSBAC_UID_SET(attr_val_p->auth_cap_range.last), + RSBAC_UID_NUM(attr_val_p->auth_cap_range.last)); + else +#endif + sprintf(attr_val_name, "%u:%u", + RSBAC_UID_NUM(attr_val_p->auth_cap_range.first), + RSBAC_UID_NUM(attr_val_p->auth_cap_range.last)); + break; + case A_switch_target: + get_switch_target_name(attr_val_name, + attr_val_p->switch_target); + break; + case A_request: + get_request_name(attr_val_name, + attr_val_p->request); + break; + case A_sock_type: + rsbac_get_net_type_name(attr_val_name, + attr_val_p->sock_type); + break; +#endif +#if defined(CONFIG_RSBAC_PAX) || !defined(__KERNEL__) + case A_pax_flags: + pax_print_flags(attr_val_name, + attr_val_p->pax_flags); + break; +#endif +#if defined(CONFIG_RSBAC_AUTH) || !defined(__KERNEL__) + case A_auth_last_auth: +#if defined(CONFIG_RSBAC_AUTH_LEARN) && defined(__KERNEL__) + case A_auth_start_uid: + case A_auth_start_euid: +#endif +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(attr_val_p->auth_last_auth)) + sprintf(attr_val_name, "%u/%u", + RSBAC_UID_SET(attr_val_p->auth_last_auth), + RSBAC_UID_NUM(attr_val_p->auth_last_auth)); + else +#endif + sprintf(attr_val_name, "%u", + RSBAC_UID_NUM(attr_val_p->auth_last_auth)); + break; +#endif +#ifdef CONFIG_RSBAC_AUTH_GROUP + case A_auth_start_gid: +#ifdef CONFIG_RSBAC_AUTH_DAC_GROUP + case A_auth_start_egid: +#endif +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_GID_SET(attr_val_p->auth_last_auth)) + sprintf(attr_val_name, "%u/%u", + RSBAC_GID_SET(attr_val_p->auth_last_auth), + RSBAC_GID_NUM(attr_val_p->auth_last_auth)); + else +#endif + sprintf(attr_val_name, "%u", + RSBAC_GID_NUM(attr_val_p->auth_start_gid)); + break; +#endif +#if defined(CONFIG_RSBAC_FF) || !defined(__KERNEL__) + case A_ff_flags: + sprintf(attr_val_name, "%u", + attr_val_p->ff_flags); + break; +#endif +#if defined(CONFIG_RSBAC_UDF) || !defined(__KERNEL__) + case A_udf_checker: + sprintf(attr_val_name, "%u", + attr_val_p->udf_checker); + break; + case A_udf_do_check: + sprintf(attr_val_name, "%u", + attr_val_p->udf_do_check); + break; +#endif + default: + snprintf(attr_val_name, RSBAC_MAXNAMELEN - 1, "%u", + attr_val_p->u_dummy); + } + return (attr_val_name); +} + + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(get_scd_type_name); +#endif +#endif + +char *get_scd_type_name(char *res_name, enum rsbac_scd_type_t res) +{ + if (!res_name) + return (NULL); + if (res > ST_none) + strcpy(res_name, "ERROR!"); + else + strcpy(res_name, scd_type_list[res]); + return (res_name); +} + +enum rsbac_scd_type_t get_scd_type_nr(const char *res_name) +{ + enum rsbac_scd_type_t i; + + if (!res_name) + return (ST_none); + for (i = 0; i < ST_none; i++) { + if (!strcmp(res_name, scd_type_list[i])) { + return (i); + } + } + return (ST_none); +} + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_get_program_name); +#endif +#endif + +char *rsbac_get_program_name(void) +{ + char * program_name; +#ifdef CONFIG_RSBAC_LOG_PROGRAM_FILE + struct file *file_p; +#endif + +#ifdef CONFIG_RSBAC_LOG_PROGRAM_FILE +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + program_name = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN); + /* max. path name len + some extra */ +#else + program_name = rsbac_kmalloc(2 * RSBAC_MAXNAMELEN); + /* max. file name len + some extra */ +#endif +#else + program_name = rsbac_kmalloc(RSBAC_MAXNAMELEN); +#endif + + if (unlikely(!program_name)) + return NULL; + +#ifdef CONFIG_RSBAC_LOG_PROGRAM_FILE + file_p = get_task_exe_file(current); + if( file_p + && file_p->f_path.dentry + ) { + char * p = program_name; + + p += sprintf(program_name, "%s, ", current->comm); +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + rsbac_get_full_path(file_p->f_path.dentry, p, CONFIG_RSBAC_MAX_PATH_LEN); +#else + if ( file_p->f_path.dentry->d_name.len + && file_p->f_path.dentry->d_name.name + ) { + int namelen = rsbac_min(file_p->f_path.dentry->d_name.len, RSBAC_MAXNAMELEN); + + strncpy(p, file_p->f_path.dentry->d_name.name, namelen); + p[namelen]=0; + } else { + sprintf(program_name, "%s", current->comm); + } +#endif + } else { + sprintf(program_name, "%s", current->comm); + } +#else + sprintf(program_name, "%s", current->comm); +#endif + + return program_name; +} + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(get_target_name); +#endif +#endif + +char *get_target_name(char *target_type_name, + enum rsbac_target_t target, + char *target_id_name, union rsbac_target_id_t tid) +{ +#ifdef __KERNEL__ + char *help_name; +#else + char help_name[RSBAC_MAXNAMELEN + 4]; +#endif + +#ifdef __KERNEL__ +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + help_name = rsbac_kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + 4); +#else + help_name = rsbac_kmalloc(RSBAC_MAXNAMELEN + 4); +#endif + if (!help_name) + return NULL; +#endif + + switch (target) { +#ifdef __KERNEL__ + case T_FD: + if(target_type_name) + strcpy(target_type_name, "FD"); + if (!target_id_name) + break; + sprintf(target_id_name, "Device %02u:%02u Inode %lu", + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), (u_long) tid.file.inode); + if (tid.file.dentry_p && tid.file.dentry_p->d_name.name + && tid.file.dentry_p->d_name.len) { +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (rsbac_get_full_path + (tid.file.dentry_p, help_name, + CONFIG_RSBAC_MAX_PATH_LEN) > 0) { + strcat(target_id_name, " Path "); + strcat(target_id_name, help_name); + } +#else + int namelen = + rsbac_min(tid.file.dentry_p->d_name.len, + RSBAC_MAXNAMELEN); + + strcat(target_id_name, " Name "); + strncpy(help_name, tid.file.dentry_p->d_name.name, + namelen); + help_name[namelen] = 0; + strcat(target_id_name, help_name); +#endif + } + break; + case T_FILE: + if(target_type_name) + strcpy(target_type_name, "FILE"); + if (!target_id_name) + break; + sprintf(target_id_name, "Device %02u:%02u Inode %lu", + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), (u_long) tid.file.inode); + if (tid.file.dentry_p && tid.file.dentry_p->d_name.name + && tid.file.dentry_p->d_name.len) { +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (rsbac_get_full_path + (tid.file.dentry_p, help_name, + CONFIG_RSBAC_MAX_PATH_LEN) > 0) { + strcat(target_id_name, " Path "); + strcat(target_id_name, help_name); + } +#else + int namelen = + rsbac_min(tid.file.dentry_p->d_name.len, + RSBAC_MAXNAMELEN); + + strcat(target_id_name, " Name "); + strncpy(help_name, tid.file.dentry_p->d_name.name, + namelen); + help_name[namelen] = 0; + strcat(target_id_name, help_name); +#endif + } + break; + case T_DIR: + if(target_type_name) + strcpy(target_type_name, "DIR"); + if (!target_id_name) + break; + sprintf(target_id_name, "Device %02u:%02u Inode %lu", + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), (u_long) tid.dir.inode); + if (tid.dir.dentry_p && tid.dir.dentry_p->d_name.name + && tid.dir.dentry_p->d_name.len) { +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (rsbac_get_full_path + (tid.dir.dentry_p, help_name, + CONFIG_RSBAC_MAX_PATH_LEN) > 0) { + strcat(target_id_name, " Path "); + strcat(target_id_name, help_name); + } +#else + int namelen = + rsbac_min(tid.dir.dentry_p->d_name.len, + RSBAC_MAXNAMELEN); + + strcat(target_id_name, " Name "); + strncpy(help_name, tid.dir.dentry_p->d_name.name, + namelen); + help_name[namelen] = 0; + strcat(target_id_name, help_name); +#endif + } + break; + case T_FIFO: + if(target_type_name) + strcpy(target_type_name, "FIFO"); + if (!target_id_name) + break; + sprintf(target_id_name, "Device %02u:%02u Inode %lu", + RSBAC_MAJOR(tid.file.device), + RSBAC_MINOR(tid.file.device), (u_long) tid.fifo.inode); + if (tid.fifo.dentry_p && tid.fifo.dentry_p->d_name.name + && tid.fifo.dentry_p->d_name.len) { +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (rsbac_get_full_path + (tid.fifo.dentry_p, help_name, + CONFIG_RSBAC_MAX_PATH_LEN) > 0) { + strcat(target_id_name, " Path "); + strcat(target_id_name, help_name); + } +#else + int namelen = + rsbac_min(tid.fifo.dentry_p->d_name.len, + RSBAC_MAXNAMELEN); + + strcat(target_id_name, " Name "); + strncpy(help_name, tid.fifo.dentry_p->d_name.name, + namelen); + help_name[namelen] = 0; + strcat(target_id_name, help_name); +#endif + } + break; + case T_SYMLINK: + if(target_type_name) + strcpy(target_type_name, "SYMLINK"); + if (!target_id_name) + break; + sprintf(target_id_name, "Device %02u:%02u Inode %lu", + RSBAC_MAJOR(tid.symlink.device), + RSBAC_MINOR(tid.symlink.device), (u_long) tid.symlink.inode); + if (tid.symlink.dentry_p + && tid.symlink.dentry_p->d_name.name + && tid.symlink.dentry_p->d_name.len) { +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (rsbac_get_full_path + (tid.symlink.dentry_p, help_name, + CONFIG_RSBAC_MAX_PATH_LEN) > 0) { + strcat(target_id_name, " Path "); + strcat(target_id_name, help_name); + } +#else + int namelen = + rsbac_min(tid.symlink.dentry_p->d_name.len, + RSBAC_MAXNAMELEN); + + strcat(target_id_name, " Name "); + strncpy(help_name, + tid.symlink.dentry_p->d_name.name, + namelen); + help_name[namelen] = 0; + strcat(target_id_name, help_name); +#endif + } + break; + case T_UNIXSOCK: + if(target_type_name) + strcpy(target_type_name, "UNIXSOCK"); + if (!target_id_name) + break; + sprintf(target_id_name, "Device %02u:%02u Inode %lu", + RSBAC_MAJOR(tid.unixsock.device), + RSBAC_MINOR(tid.unixsock.device), (u_long) tid.unixsock.inode); + if (tid.symlink.dentry_p + && tid.unixsock.dentry_p->d_name.name + && tid.unixsock.dentry_p->d_name.len) { +#ifdef CONFIG_RSBAC_LOG_FULL_PATH + if (rsbac_get_full_path + (tid.unixsock.dentry_p, help_name, + CONFIG_RSBAC_MAX_PATH_LEN) > 0) { + strcat(target_id_name, " Path "); + strcat(target_id_name, help_name); + } +#else + int namelen = + rsbac_min(tid.unixsock.dentry_p->d_name.len, + RSBAC_MAXNAMELEN); + + strcat(target_id_name, " Name "); + strncpy(help_name, + tid.unixsock.dentry_p->d_name.name, + namelen); + help_name[namelen] = 0; + strcat(target_id_name, help_name); +#endif + } + break; + case T_DEV: + if(target_type_name) + strcpy(target_type_name, "DEV"); + if (!target_id_name) + break; + switch (tid.dev.type) { + case D_block: + sprintf(target_id_name, "block %02u:%02u", + tid.dev.major, tid.dev.minor); + break; + case D_char: + sprintf(target_id_name, "char %02u:%02u", + tid.dev.major, tid.dev.minor); + break; + case D_block_major: + sprintf(target_id_name, "block major %02u", + tid.dev.major); + break; + case D_char_major: + sprintf(target_id_name, "char major %02u", + tid.dev.major); + break; + default: + sprintf(target_id_name, "*unknown* %02u:%02u", + tid.dev.major, tid.dev.minor); + } + break; + case T_NETOBJ: + if(target_type_name) + strcpy(target_type_name, "NETOBJ"); + if (!target_id_name) + break; +#ifdef CONFIG_NET + if (tid.netobj.sock_p + && tid.netobj.sock_p->ops && tid.netobj.sock_p->sk) { + char type_name[RSBAC_MAXNAMELEN]; + + switch (tid.netobj.sock_p->ops->family) { + case AF_INET: + { + __u32 saddr; + __u16 sport; + __u32 daddr; + __u16 dport; + struct net_device *dev; + char ldevname[RSBAC_IFNAMSIZ + 10]; + char rdevname[RSBAC_IFNAMSIZ + 10]; + + if (tid.netobj.local_addr) { + struct sockaddr_in *addr = + tid.netobj.local_addr; + + saddr = + addr->sin_addr.s_addr; + sport = + ntohs(addr->sin_port); + } else { + saddr = + inet_sk(tid.netobj. + sock_p->sk)-> + inet_saddr; + sport = + inet_sk(tid.netobj. + sock_p->sk)-> + inet_num; + } + if (tid.netobj.remote_addr) { + struct sockaddr_in *addr = + tid.netobj.remote_addr; + + daddr = + addr->sin_addr.s_addr; + dport = + ntohs(addr->sin_port); + } else { + daddr = + inet_sk(tid.netobj. + sock_p->sk)-> + inet_daddr; + dport = + ntohs(inet_sk + (tid.netobj. + sock_p->sk)-> + inet_dport); + } + dev = ip_dev_find(&init_net, saddr); + + if (dev) { + sprintf(ldevname, "%s:", + dev->name); + dev_put(dev); + } else + ldevname[0] = 0; + dev = ip_dev_find(&init_net, daddr); + if (dev) { + sprintf(rdevname, "%s:", + dev->name); + dev_put(dev); + } else + rdevname[0] = 0; + sprintf(target_id_name, + "%p INET %s proto %s local %s%u.%u.%u.%u:%u remote %s%u.%u.%u.%u:%u", + tid.netobj.sock_p, + rsbac_get_net_type_name + (type_name, + tid.netobj.sock_p->type), + rsbac_get_net_protocol_name + (help_name, + tid.netobj.sock_p->sk-> + sk_protocol), + ldevname, + NIPQUAD(saddr), + sport, + rdevname, + NIPQUAD(daddr), dport); + } + break; + case AF_NETLINK: + if (tid.netobj.local_addr || tid.netobj.remote_addr) { + struct sockaddr_nl *addr; + + if(tid.netobj.local_addr) + addr = tid.netobj.local_addr; + else + addr = tid.netobj.remote_addr; + + sprintf(target_id_name, + "%p NETLINK %s %s %u", + tid.netobj.sock_p, + rsbac_get_net_type_name + (type_name, + tid.netobj.sock_p->type), + rsbac_get_net_netlink_family_name( + help_name, + tid.netobj.sock_p->sk->sk_protocol), + addr->nl_pid); + } else { + sprintf(target_id_name, + "%p NETLINK %s %s", + tid.netobj.sock_p, + rsbac_get_net_type_name + (type_name, + tid.netobj.sock_p->type), + rsbac_get_net_netlink_family_name( + help_name, + tid.netobj.sock_p->sk->sk_protocol)); + } + break; + default: + sprintf(target_id_name, "%p %s %s", + tid.netobj.sock_p, + rsbac_get_net_family_name + (help_name, + tid.netobj.sock_p->ops->family), + rsbac_get_net_type_name(type_name, + tid.netobj. + sock_p-> + type)); + } + } else +#endif /* CONFIG_NET */ + { + sprintf(target_id_name, "%p", tid.netobj.sock_p); + } + break; +#endif /* __KERNEL__ */ + case T_IPC: + if(target_type_name) + strcpy(target_type_name, "IPC"); + if (!target_id_name) + break; + switch (tid.ipc.type) { + case I_sem: + strcpy(target_id_name, "Sem-ID "); + break; + case I_msg: + strcpy(target_id_name, "Msg-ID "); + break; + case I_shm: + strcpy(target_id_name, "Shm-ID "); + break; + case I_anonpipe: + strcpy(target_id_name, "AnonPipe-ID "); + break; + case I_mqueue: + strcpy(target_id_name, "Mqueue-ID "); + break; + case I_anonunix: + strcpy(target_id_name, "AnonUnix-ID "); + break; + default: + strcpy(target_id_name, "ID "); + break; + }; + sprintf(help_name, "%lu", tid.ipc.id.id_nr); + strcat(target_id_name, help_name); + break; + case T_SCD: + if(target_type_name) + strcpy(target_type_name, "SCD"); + if (target_id_name) + get_scd_type_name(target_id_name, tid.scd); + break; + case T_USER: + if(target_type_name) + strcpy(target_type_name, "USER"); + if (target_id_name) { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(tid.user)) + sprintf(target_id_name, "%u/%u", + RSBAC_UID_SET(tid.user), + RSBAC_UID_NUM(tid.user)); + else +#endif + sprintf(target_id_name, "%u", RSBAC_UID_NUM(tid.user)); + } + break; + case T_PROCESS: + if(target_type_name) + strcpy(target_type_name, "PROCESS"); + if (target_id_name) { + struct task_struct *task_p; + + task_p = get_pid_task(tid.process, PIDTYPE_PID); + if (task_p) { + if (pid_alive(task_p)) { + if(task_p->parent) + sprintf(target_id_name, "%u(%s,parent=%u(%s))", task_p->pid, task_p->comm, task_p->parent->pid, task_p->parent->comm); + else + sprintf(target_id_name, "%u(%s)", task_p->pid, task_p->comm); + } else { + sprintf(target_id_name, "%u(dead)", pid_nr(tid.process)); + } + put_task_struct(task_p); + } else { + sprintf(target_id_name, "%u", pid_nr(tid.process)); + } + } + break; + case T_GROUP: + if(target_type_name) + strcpy(target_type_name, "GROUP"); + if (target_id_name) { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_GID_SET(tid.group)) + sprintf(target_id_name, "%u/%u", + RSBAC_GID_SET(tid.group), + RSBAC_GID_NUM(tid.group)); + else +#endif + sprintf(target_id_name, "%u", RSBAC_GID_NUM(tid.group)); + } + break; + case T_NETDEV: + if(target_type_name) + strcpy(target_type_name, "NETDEV"); + if (!target_id_name) + break; + strncpy(target_id_name, tid.netdev, RSBAC_IFNAMSIZ); + target_id_name[RSBAC_IFNAMSIZ] = 0; + break; + case T_NETTEMP: + if(target_type_name) + strcpy(target_type_name, "NETTEMP"); + if (target_id_name) + sprintf(target_id_name, "%u", tid.nettemp); + break; + case T_NETTEMP_NT: + if(target_type_name) + strcpy(target_type_name, "NETTEMP_NT"); + if (target_id_name) + sprintf(target_id_name, "%u", tid.nettemp); + break; + case T_NONE: + if(target_type_name) + strcpy(target_type_name, "NONE"); + if (target_id_name) + strcpy(target_id_name, "NONE"); + break; + default: + if(target_type_name) + strcpy(target_type_name, "ERROR!!!"); + if (target_id_name) + sprintf(target_id_name, "%u", target); + } +#ifdef __KERNEL__ + rsbac_kfree(help_name); +#endif + if(target_type_name) + return target_type_name; + else + return target_id_name; +} + +char *get_target_name_only(char *target_type_name, + enum rsbac_target_t target) +{ + if (!target_type_name) + return (NULL); + + switch (target) { + case T_FILE: + strcpy(target_type_name, "FILE"); + break; + case T_DIR: + strcpy(target_type_name, "DIR"); + break; + case T_FIFO: + strcpy(target_type_name, "FIFO"); + break; + case T_SYMLINK: + strcpy(target_type_name, "SYMLINK"); + break; + case T_UNIXSOCK: + strcpy(target_type_name, "UNIXSOCK"); + break; + case T_FD: + strcpy(target_type_name, "FD"); + break; + case T_DEV: + strcpy(target_type_name, "DEV"); + break; + case T_NETOBJ: + strcpy(target_type_name, "NETOBJ"); + break; + case T_IPC: + strcpy(target_type_name, "IPC"); + break; + case T_SCD: + strcpy(target_type_name, "SCD"); + break; + case T_USER: + strcpy(target_type_name, "USER"); + break; + case T_PROCESS: + strcpy(target_type_name, "PROCESS"); + break; + case T_GROUP: + strcpy(target_type_name, "GROUP"); + break; + case T_NETDEV: + strcpy(target_type_name, "NETDEV"); + break; + case T_NETTEMP: + strcpy(target_type_name, "NETTEMP"); + break; + case T_NETTEMP_NT: + strcpy(target_type_name, "NETTEMP_NT"); + break; + case T_NONE: + strcpy(target_type_name, "NONE"); + break; + default: + strcpy(target_type_name, "ERROR!!!"); + } + return (target_type_name); +} + +enum rsbac_target_t get_target_nr(const char *target_name) +{ + enum rsbac_target_t i; + + if (!target_name) + return (T_NONE); + for (i = 0; i < T_NONE; i++) { + if (!strcmp(target_name, target_list[i])) { + return (i); + } + } + return (T_NONE); +} + +char *get_ipc_target_name(char *ipc_name, enum rsbac_ipc_type_t target) +{ + if (!ipc_name) + return (NULL); + if (target > I_none) + strcpy(ipc_name, "ERROR!"); + else + strcpy(ipc_name, ipc_target_list[target]); + return (ipc_name); +} + +enum rsbac_ipc_type_t get_ipc_target_nr(const char *ipc_name) +{ + enum rsbac_ipc_type_t i; + + if (!ipc_name) + return (I_none); + for (i = 0; i < I_none; i++) { + if (!strcmp(ipc_name, ipc_target_list[i])) { + return (i); + } + } + return (I_none); +} + + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(get_switch_target_name); +#endif +#endif + +char *get_switch_target_name(char *switch_name, + enum rsbac_switch_target_t target) +{ + if (!switch_name) + return (NULL); + if (target > SW_NONE) + strcpy(switch_name, "ERROR!"); + else + strcpy(switch_name, switch_target_list[target]); + return (switch_name); +} + +enum rsbac_switch_target_t get_switch_target_nr(const char *switch_name) +{ + enum rsbac_switch_target_t i; + + if (!switch_name) + return (SW_NONE); + for (i = 0; i < SW_NONE; i++) { +#ifdef __KERNEL__ + if (!strncmp + (switch_name, switch_target_list[i], + strlen(switch_target_list[i]))) +#else + if (!strcmp(switch_name, switch_target_list[i])) +#endif + { + return (i); + } + } + return (SW_NONE); +} + + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(get_error_name); +#endif +#endif + +char *get_error_name(char *error_name, int error) +{ + if (!error_name) + return (NULL); +#ifndef __KERNEL__ + if((error == -1) && RSBAC_ERROR(-errno)) + error = -errno; +#endif + if (RSBAC_ERROR(error)) + strcpy(error_name, error_list[(-error) - RSBAC_EPERM]); + else +#ifdef __KERNEL__ + inttostr(error_name, error); +#else + strcpy(error_name, strerror(errno)); +#endif + return (error_name); +} + +#ifndef __KERNEL__ +char *get_attribute_param(char *attr_name, enum rsbac_attribute_t attr) +{ + if (!attr_name) + return (NULL); + if (attr > A_none) + strcpy(attr_name, "ERROR!"); + else + strcpy(attr_name, attribute_param_list[attr]); + return (attr_name); +} +#endif + +char *get_log_level_name(char *ll_name, enum rsbac_log_level_t target) +{ + if (!ll_name) + return (NULL); + if (target > LL_invalid) + strcpy(ll_name, "ERROR!"); + else + strcpy(ll_name, log_level_list[target]); + return (ll_name); +} + +enum rsbac_log_level_t get_log_level_nr(const char *ll_name) +{ + enum rsbac_log_level_t i; + + if (!ll_name) + return (LL_invalid); + for (i = 0; i < LL_invalid; i++) { + if (!strcmp(ll_name, log_level_list[i])) { + return (i); + } + } + return (LL_invalid); +} + +char *get_cap_name(char *name, u_int value) +{ + if (!name) + return (NULL); + if (value > CAP_NONE) + strcpy(name, "ERROR!"); + else + strcpy(name, cap_list[value]); + return (name); +} + +int get_cap_nr(const char *name) +{ + int i; + + if (!name) + return (CAP_NONE); + for (i = 0; i < CAP_NONE; i++) { + if (!strcasecmp(name, cap_list[i])) { + return (i); + } + } + return (CAP_NONE); +} diff --git a/rsbac/help/helpers.c b/rsbac/help/helpers.c new file mode 100644 index 000000000000..1939cb35623f --- /dev/null +++ b/rsbac/help/helpers.c @@ -0,0 +1,1212 @@ +/************************************* */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2015: */ +/* Amon Ott */ +/* Helper functions for all parts */ +/* Last modified: 07/Jul/2015 */ +/************************************* */ + +#ifndef __KERNEL__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_RSBAC_RC +#include +#endif +#endif +#ifndef __KERNEL__ +#include +#include +#include +#include +#include +#endif + +int rsbac_get_vset_num(char * sourcename, rsbac_um_set_t * vset_p) + { + if (!sourcename || !vset_p) + return -RSBAC_EINVALIDPOINTER; + if (!strcmp(sourcename,"all")) { + *vset_p = RSBAC_UM_VIRTUAL_ALL; + return 0; + } + if (!strcmp(sourcename,"auto") || !strcmp(sourcename,"keep")) { + *vset_p = RSBAC_UM_VIRTUAL_KEEP; + return 0; + } +#ifdef __KERNEL__ + *vset_p = simple_strtoul(sourcename, NULL, 0); +#else + *vset_p = strtoul(sourcename, NULL, 0); +#endif + if(!*vset_p && strcmp(sourcename,"0")) + return -RSBAC_EINVALIDVALUE; + if (*vset_p > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; + return 0; + } + +#ifndef __KERNEL__ +int rsbac_u32_compare(__u32 * a, __u32 * b) + { + if(*a < *b) + return -1; + if(*a > *b) + return 1; + return 0; + } + +int rsbac_user_compare(const void * a, const void * b) + { + return rsbac_u32_compare((__u32 *) a, (__u32 *) b); + } + +int rsbac_group_compare(const void * a, const void * b) + { + return rsbac_u32_compare((__u32 *) a, (__u32 *) b); + } + +int rsbac_nettemp_id_compare(const void * a, const void * b) + { + return rsbac_u32_compare((__u32 *) a, (__u32 *) b); + } + +int rsbac_dev_compare(const void *desc1, const void *desc2) +{ + int result; + + result = memcmp(&((struct rsbac_dev_desc_t *)desc1)->type, + &((struct rsbac_dev_desc_t *)desc2)->type, + sizeof(((struct rsbac_dev_desc_t *)desc1)->type)); + if (result) + return result; + result = memcmp(&((struct rsbac_dev_desc_t *)desc1)->major, + &((struct rsbac_dev_desc_t *)desc2)->major, + sizeof(((struct rsbac_dev_desc_t *)desc1)->major)); + if (result) + return result; + return memcmp(&((struct rsbac_dev_desc_t *)desc1)->minor, + &((struct rsbac_dev_desc_t *)desc2)->minor, + sizeof(((struct rsbac_dev_desc_t *)desc1)->minor)); +} +#endif + +char * inttostr(char * str, int i) + { + int j = 0; + + if(!str) + return(NULL); + + if (i<0) + { + str[j] = '-'; + j++; + i = -i; + } + if (i>=10000) + { + str[j] = '0' + (i / 10000); + j++; + } + if (i>=1000) + { + str[j] = '0' + ((i % 10000) / 1000); + j++; + } + if (i>=100) + { + str[j] = '0' + ((i % 1000) / 100); + j++; + } + if (i>=10) + { + str[j] = '0' + ((i % 100) / 10); + j++; + } + str[j] = '0' + (i % 10); + j++; + str[j] = 0; + return (str); + }; + +char * ulongtostr(char * str, u_long i) + { + int j = 0; + u_long k = 1000000000; + + if(!str) + return(NULL); + + if (i>=k) + { + str[j] = '0' + ((i / k) % 100); + j++; + } + k /= 10; + + while (k>1) + { + if (i>=k) + { + str[j] = '0' + ((i % (k*10)) / k); + j++; + } + k /= 10; + }; + + str[j] = '0' + (i % 10); + j++; + str[j] = 0; + return (str); + }; + +char * longtostr(char * str, long i) + { + int j = 0; + u_long k = 1000000000; + + if(!str) + return(NULL); + + if (i<0) + { + str[0] = '-'; + j = 1; + i = -i; + } + if (i>=k) + { + str[j] = '0' + ((i / k) % 100); + j++; + } + k /= 10; + + while (k>1) + { + if (i>=k) + { + str[j] = '0' + ((i % (k*10)) / k); + j++; + } + k /= 10; + }; + + str[j] = '0' + (i % 10); + j++; + str[j] = 0; + return (str); + }; + +char * u64tostrmac(char * str, __u64 i) + { + int j = 0; + __u64 k; + + if(!str) + return(NULL); + + k = 1; + for(j = RSBAC_MAC_MAX_CAT;j >= 0;j--) + { + if (i & k) + str[j] = '1'; + else + str[j] = '0'; + k<<=1; + }; + + str[RSBAC_MAC_NR_CATS] = 0; + return (str); + }; + +#ifndef __KERNEL__ + +void error_exit(int error) + { + char tmp1[80]; + + if(error<0) + { + get_error_name(tmp1,error); + fprintf(stderr, "Error: %s\n", tmp1); + exit(1); + } + } + +void show_error(int error) + { + char tmp1[80]; + + if(error<0) + { + get_error_name(tmp1,error); + fprintf(stderr, "Error: %s\n", tmp1); + } + } + +int rsbac_get_uid_name(rsbac_uid_t * uid, char * name, char * sourcename) + { + struct passwd * user_info_p; + rsbac_uid_t uid_i; + + if(!(user_info_p = getpwnam(sourcename))) + { + uid_i = strtoul(sourcename,0,10); + if( !uid_i + && strcmp("0", sourcename) + ) + { + return -RSBAC_EINVALIDVALUE; + } + if(name) + { + if((user_info_p = getpwuid(uid_i))) + strcpy(name, user_info_p->pw_name); + else + sprintf(name, "%u", uid_i); + } + } + else + { + uid_i = user_info_p->pw_uid; + if(name) + strcpy(name, user_info_p->pw_name); + } + if(uid) + *uid = uid_i; + return 0; + } + +int rsbac_get_fullname(char * fullname, rsbac_uid_t uid) + { + struct passwd * user_info_p; + rsbac_uid_t uid_i; + + if(!fullname) + return -RSBAC_EINVALIDPOINTER; + if(!(user_info_p = getpwuid(uid))) + { + sprintf(fullname, "%u", uid); + } + else + { + strcpy(fullname, user_info_p->pw_gecos); + } + return 0; + } + +char * get_user_name(rsbac_uid_t user, char * name) + { + struct passwd * user_info_p; + + if((user_info_p = getpwuid(user))) + { + strcpy(name, user_info_p->pw_name); + } + else + { + sprintf(name, "%u", user); + } + return name; + } + +char * get_group_name(rsbac_gid_t group, char * name) + { + struct group * group_info_p; + + if((group_info_p = getgrgid(group))) + { + strcpy(name, group_info_p->gr_name); + } + else + { + sprintf(name, "%u", group); + } + return name; + } + +int rsbac_get_gid_name(rsbac_gid_t * gid, char * name, char * sourcename) + { + struct group * group_info_p; + rsbac_gid_t gid_i; + + if(!(group_info_p = getgrnam(sourcename))) + { + gid_i = strtoul(sourcename,0,10); + if( !gid_i + && strcmp("0", sourcename) + ) + { + return -RSBAC_EINVALIDVALUE; + } + if(name) + { + if((group_info_p = getgrgid(gid_i))) + strcpy(name, group_info_p->gr_name); + else + sprintf(name, "%u", gid_i); + } + } + else + { + gid_i = group_info_p->gr_gid; + if(name) + strcpy(name, group_info_p->gr_name); + } + if(gid) + *gid = gid_i; + return 0; + } + + +char * u64tostrlog(char * str, __u64 i) + { + int j = 0; + __u64 k; + + if(!str) + return(NULL); + + k = 1; + for(j = R_NONE - 1;j >= 0;j--) + { + if (i & k) + str[j] = '1'; + else + str[j] = '0'; + k<<=1; + }; + + str[R_NONE] = 0; + return (str); + }; + +__u64 strtou64log(char * str, __u64 * i_p) + { + int j; + __u64 k = 1, res=0; + + if(!str) + return(0); + + if (strlen(str) < R_NONE) + return(-1); + for(j=R_NONE-1;j>=0;j--) + { + if(str[j] != '0') + { + res |= k; + } + k <<= 1; + } + for(j=R_NONE;j<64;j++) + { + res |= k; + k <<= 1; + } + *i_p = res; + return(res); + }; + +char * u64tostrrc(char * str, __u64 i) + { + int j = 0; + __u64 k; + + if(!str) + return(NULL); + + k = 1; + for(j = 63;j >= 0;j--) + { + if (i & k) + str[j] = '1'; + else + str[j] = '0'; + k<<=1; + }; + + str[64] = 0; + return (str); + }; + +__u64 strtou64rc(char * str, __u64 * i_p) + { + int j; + __u64 k = 1, res=0; + + if(!str) + return(0); + + if (strlen(str) < 64) + return(-1); + for(j=63;j>=0;j--) + { + if(str[j] != '0') + { + res |= k; + } + k <<= 1; + } + *i_p = res; + return(res); + }; + +char * u64tostrrcr(char * str, __u64 i) + { + int j = 0; + __u64 k; + + if(!str) + return(NULL); + + k = 1; + for(j = RCR_NONE - 1;j >= 0;j--) + { + if (i & k) + str[j] = '1'; + else + str[j] = '0'; + k<<=1; + }; + + str[RCR_NONE] = 0; + return (str); + }; + +__u64 strtou64rcr(char * str, __u64 * i_p) + { + int j; + __u64 k = 1, res=0; + + if(!str) + return(0); + + if (strlen(str) < RCR_NONE) + return(-1); + for(j=RCR_NONE-1;j>=0;j--) + { + if(str[j] != '0') + { + res |= k; + } + k <<= 1; + } + for(j=RCR_NONE;j<64;j++) + { + res |= k; + k <<= 1; + } + *i_p = res; + return(res); + }; + +__u64 strtou64mac(char * str, __u64 * i_p) + { + int j; + __u64 k = 1, res=0; + + if(!str) + return(0); + + if (strlen(str) < RSBAC_MAC_NR_CATS) + return(-1); + for(j=RSBAC_MAC_MAX_CAT;j>=0;j--) + { + if(str[j] != '0') + { + res |= k; + } + k <<= 1; + } + for(j=RSBAC_MAC_NR_CATS;j<64;j++) + { + res |= k; + k <<= 1; + } + *i_p = res; + return(res); + }; + +__u64 strtou64acl(char * str, __u64 * i_p) + { + int j; + __u64 k = 1, res=0; + + if(!str) + return(0); + + if (strlen(str) < (ACLR_NONE - 1)) + return(-1); + for(j=ACLR_NONE-1;j>=0;j--) + { + if(str[j] != '0') + { + res |= k; + } + k <<= 1; + } + for(j=ACLR_NONE-1;j<64;j++) + { + res |= k; + k <<= 1; + } + *i_p = res; + return(res); + } + +int strtodevdesc(char * str, struct rsbac_dev_desc_t * dev_p) + { + char * p; + char * c; + + if(!str) + return -RSBAC_EINVALIDVALUE; + if(!strcmp(str, ":DEFAULT:")) + { + *dev_p = RSBAC_ZERO_DEV_DESC; + return 0; + } + p = str; + c = strchr(p,':'); + switch(*p) + { + case 'b': + case 'B': + if(c) + dev_p->type = D_block; + else + dev_p->type = D_block_major; + break; + case 'c': + case 'C': + if(c) + dev_p->type = D_char; + else + dev_p->type = D_char_major; + break; + default: + return -RSBAC_EINVALIDTARGET; + } + p++; + dev_p->major = strtoul(p,0,0); + if(c) + { + c++; + dev_p->minor = strtoul(c,0,0); + } + else + dev_p->minor = 0; + return 0; + } + +char * devdesctostr(char * str, struct rsbac_dev_desc_t dev) + { + if(RSBAC_IS_ZERO_DEV_DESC(dev)) + { + sprintf(str, ":DEFAULT:"); + return str; + } + switch(dev.type) + { + case D_block: + case D_char: + sprintf(str, "%c%u:%u", 'b' + dev.type, dev.major, dev.minor); + break; + case D_block_major: + case D_char_major: + sprintf(str, "%c%u", + 'b' + dev.type - (D_block_major - D_block), + dev.major); + break; + default: + sprintf(str, "invalid!"); + } + return str; + } +#endif /* ifndef __KERNEL__ */ + +char * u64tostracl(char * str, __u64 i) + { + int j = 0; + __u64 k; + + if(!str) + return(NULL); + + k = 1; + for(j = ACLR_NONE - 1;j >= 0;j--) + { + if (i & k) + str[j] = '1'; + else + str[j] = '0'; + k<<=1; + }; + + str[ACLR_NONE] = 0; + return (str); + }; + +char * u32tostrcap(char * str, __u32 i) + { + int j = 0; + __u32 k; + + if(!str) + return(NULL); + + k = 1; + for(j = CAP_NONE - 1;j >= 0;j--) + { + if (i & k) + str[j] = '1'; + else + str[j] = '0'; + k<<=1; + }; + + str[CAP_NONE] = 0; + return (str); + }; +int kcaptostrcap(char * str, rsbac_cap_vector_t i) + { + int j = 0; + int off; + __u32 k; + + if(!str) + return(-1); + + k = 1; + for(j = CAP_NONE - 1;j >= 32;j--) + { + if (i.cap[1] & k) + str[j-32] = '1'; + else + str[j-32] = '0'; + k<<=1; + }; + k = 1; + off = CAP_NONE-32; + for(j = 31+off;j >= off;j--) + { + if (i.cap[0] & k) + str[j] = '1'; + else + str[j] = '0'; + k<<=1; + }; + + str[CAP_NONE] = 0; + + return 0; + }; + +int strcaptokcap(char * str, rsbac_cap_vector_t * i) + { + int j; + int off; + __u32 k = 1; + + if(!str) + return -1; + if (strlen(str) < CAP_NONE) + return -1; + + for(j = CAP_NONE-1; j >= 32; j--) + { + if(str[j-32] != '0') + { + i->cap[1] |= k; + } + k <<= 1; + } + k = 1; + off = CAP_NONE-32; + for(j =31+off ;j >= off; j--) { + if(str[j] != '0') { + i->cap[0] |= k; + } + k <<= 1; + } +/* for(j=CAP_NONE;j<32;j++) + { + res |= k; + k <<= 1; + }*/ +/* *i_p = res;*/ + + return 0; + } +__u32 strtou32cap(char * str, __u32 * i_p) + { + int j; + __u32 k = 1, res=0; + + if(!str) + return(0); + + if (strlen(str) < CAP_NONE) + return(-1); + for(j=CAP_NONE-1;j>=0;j--) + { + if(str[j] != '0') + { + res |= k; + } + k <<= 1; + } + for(j=CAP_NONE;j<32;j++) + { + res |= k; + k <<= 1; + } + *i_p = res; + return(res); + }; + + +#ifdef __KERNEL__ + +#ifdef CONFIG_RSBAC_UM_VIRTUAL +rsbac_um_set_t rsbac_get_vset(void) + { + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val; + + i_tid.process = task_pid(current); + if(rsbac_get_attr(SW_GEN, + T_PROCESS, + i_tid, + A_vset, + &i_attr_val, + TRUE)) + return 0; + else + return i_attr_val.vset; + } +#endif + +/* find the current owner of this process */ +int rsbac_get_owner(rsbac_uid_t * user_p) + { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + *user_p = RSBAC_GEN_UID(rsbac_get_vset(), __kuid_val(current_uid())); +#else + *user_p = __kuid_val(current_uid()); +#endif + return 0; + } + +void rsbac_ds_get_error(const char * function, enum rsbac_attribute_t attr) + { + if(!function) + return; + if(attr != A_none) + { + char tmp[80]; + + get_attribute_name(tmp, attr); + rsbac_printk(KERN_WARNING + "%s: rsbac_get_attr() for %s returned error!\n", + function, tmp); + } + else + { + rsbac_printk(KERN_WARNING + "%s: rsbac_get_attr() returned error!\n", + function); + } + } + +void rsbac_ds_get_error_num(const char * function, enum rsbac_attribute_t attr, int err) + { + char tmp2[80]; + + if(!function) + return; + if(attr != A_none) + { + char tmp[80]; + + get_attribute_name(tmp, attr); + get_error_name(tmp2, err); + rsbac_printk(KERN_WARNING + "%s: rsbac_get_attr() for %s returned error %s!\n", + function, tmp, tmp2); + } + else + { + get_error_name(tmp2, err); + rsbac_printk(KERN_WARNING + "%s: rsbac_get_attr() returned error %s!\n", + function, tmp2); + } + } + +void rsbac_ds_set_error(const char * function, enum rsbac_attribute_t attr) + { + if(!function) + return; + if(attr != A_none) + { + char tmp[80]; + + get_attribute_name(tmp, attr); + rsbac_printk(KERN_WARNING + "%s: rsbac_set_attr() for %s returned error!\n", + function, tmp); + } + else + { + rsbac_printk(KERN_WARNING + "%s: rsbac_set_attr() returned error!\n", + function); + } + } + +void rsbac_ds_set_error_num(const char * function, enum rsbac_attribute_t attr, int err) + { + char tmp2[80]; + + if(!function) + return; + if(attr != A_none) + { + char tmp[80]; + + get_attribute_name(tmp, attr); + get_error_name(tmp2, err); + rsbac_printk(KERN_WARNING + "%s: rsbac_set_attr() for %s returned error %s!\n", + function, tmp, tmp2); + } + else + { + get_error_name(tmp2, err); + rsbac_printk(KERN_WARNING + "%s: rsbac_set_attr() returned error %s!\n", + function, tmp2); + } + } + +#ifdef CONFIG_RSBAC_RC +void rsbac_rc_ds_get_error(const char * function, enum rsbac_rc_item_t item) + { + if(!function) + return; + if(item != RI_none) + { + char tmp[80]; + + get_rc_item_name(tmp, item); + rsbac_printk(KERN_WARNING + "%s: rsbac_rc_get_item() for %s returned error!\n", + function, tmp); + } + else + { + rsbac_printk(KERN_WARNING + "%s: rsbac_rc_get_item() returned error!\n", + function); + } + } + +void rsbac_rc_ds_set_error(const char * function, enum rsbac_rc_item_t item) + { + if(!function) + return; + if(item != RI_none) + { + char tmp[80]; + + get_rc_item_name(tmp, item); + rsbac_printk(KERN_WARNING + "%s: rsbac_rc_set_item() for %s returned error!\n", + function, tmp); + } + else + { + rsbac_printk(KERN_WARNING + "%s: rsbac_rc_set_item() returned error!\n", + function); + } + } +#endif + +int rsbac_handle_filldir(const struct file *file, const char *name, const unsigned int namlen, const ino_t ino) +{ + enum rsbac_target_t rsbac_target = T_NONE; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + struct dentry *obj_dentry = NULL; + int err = 1; + + if(!rsbac_initialized) { + goto old_func; + } + + if(!name || !file || !file->f_path.dentry || !file->f_path.dentry->d_sb + || !MAJOR(file->f_path.dentry->d_sb->s_dev)) + goto old_func; + + if (in_interrupt()) + { + printk(KERN_WARNING "rsbac_handle_filldir(): called from interrupt: pid %u(%s)!\n", + current->pid, current->comm); + goto old_func; + } + + obj_dentry = rsbac_lookup_one_len(name, file->f_path.dentry, namlen); + if (!obj_dentry || IS_ERR(obj_dentry)) { + goto old_func; + } + if (!obj_dentry->d_inode || IS_ERR(obj_dentry->d_inode)) { + goto out_dput; + } + if (!obj_dentry->d_inode->i_mode || !obj_dentry->d_inode->i_sb || !obj_dentry->d_inode->i_sb->s_dev || !ino) { + goto out_dput; + } + if (!obj_dentry->d_sb || !obj_dentry->d_sb->s_magic) { + goto out_dput; + } + rsbac_pr_debug(aef, "[readdir(), sys_getdents()]: calling ADF\n"); + + if (S_ISFIFO(obj_dentry->d_inode->i_mode)) { + if(obj_dentry->d_sb->s_magic != PIPEFS_MAGIC) { + rsbac_target = T_FIFO; + rsbac_target_id.fifo.device = obj_dentry->d_inode->i_sb->s_dev; + rsbac_target_id.fifo.inode = ino; + rsbac_target_id.fifo.dentry_p = obj_dentry; + } + } else + if (S_ISDIR(obj_dentry->d_inode->i_mode)) { + rsbac_target = T_DIR; + rsbac_target_id.dir.device = obj_dentry->d_inode->i_sb->s_dev; + rsbac_target_id.dir.inode = ino; + rsbac_target_id.dir.dentry_p = obj_dentry; + } else + if (S_ISLNK(obj_dentry->d_inode->i_mode)) { + rsbac_target = T_SYMLINK; + rsbac_target_id.file.device = obj_dentry->d_inode->i_sb->s_dev; + rsbac_target_id.file.inode = ino; + rsbac_target_id.file.dentry_p = obj_dentry; + } else + if (S_ISSOCK(obj_dentry->d_inode->i_mode)) { + if (obj_dentry->d_inode->i_sb->s_magic != SOCKFS_MAGIC) { + rsbac_target = T_UNIXSOCK; + rsbac_target_id.unixsock.device = obj_dentry->d_inode->i_sb->s_dev; + rsbac_target_id.unixsock.inode = ino; + rsbac_target_id.unixsock.dentry_p = obj_dentry; + } + } else { + rsbac_target = T_FILE; + rsbac_target_id.file.device = obj_dentry->d_inode->i_sb->s_dev; + rsbac_target_id.file.inode = ino; + rsbac_target_id.file.dentry_p = obj_dentry; + } + rsbac_attribute_value.dummy = 0; + if (rsbac_target != T_NONE) + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + rsbac_target, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + err = 0; + goto out_dput; + } + +out_dput: + if (obj_dentry) + dput(obj_dentry); +old_func: + return err; +} +int rsbac_handle_rw_req(const struct file *file, struct rsbac_rw_req *rsbac_rw_req_obj) +{ + int err = 1; + + if(!rsbac_initialized) { + goto out; + } + +/* if (rsbac_rw_req_obj->rsbac_target != T_NONE){printk("i'm here! going out because of target ! =T_NONE\n"); + goto out;} +*/ + if(!file || !file->f_path.dentry || !file->f_path.dentry->d_sb + || !MAJOR(file->f_path.dentry->d_sb->s_dev) + || !file->f_path.dentry->d_sb->s_magic + || !file->f_path.dentry->d_inode + || IS_ERR(file->f_path.dentry->d_inode) + || !file->f_path.dentry->d_inode->i_mode + || !file->f_path.dentry->d_inode->i_ino) + goto out; + + if (in_interrupt()) + { + printk(KERN_WARNING "rsbac_handle_rw_req(): called from interrupt: pid %u(%s)!\n", + current->pid, current->comm); + goto out; + } + + rsbac_pr_debug(aef, "rsbac_handle_rw_req(): calling ADF\n"); + + rsbac_rw_req_obj->rsbac_attribute = A_none; + rsbac_rw_req_obj->rsbac_attribute_value.dummy = 0; + + if (S_ISFIFO(file->f_path.dentry->d_inode->i_mode)) { + if(file->f_path.dentry->d_sb->s_magic != PIPEFS_MAGIC) { + rsbac_rw_req_obj->rsbac_target = T_FIFO; + rsbac_rw_req_obj->rsbac_target_id.fifo.device = file->f_path.dentry->d_inode->i_sb->s_dev; + rsbac_rw_req_obj->rsbac_target_id.fifo.inode = file->f_path.dentry->d_inode->i_ino; + rsbac_rw_req_obj->rsbac_target_id.fifo.dentry_p = file->f_path.dentry; + } + } else + if (S_ISREG(file->f_path.dentry->d_inode->i_mode)) { + rsbac_rw_req_obj->rsbac_target = T_FILE; + rsbac_rw_req_obj->rsbac_target_id.file.device = file->f_path.dentry->d_inode->i_sb->s_dev; + rsbac_rw_req_obj->rsbac_target_id.file.inode = file->f_path.dentry->d_inode->i_ino; + rsbac_rw_req_obj->rsbac_target_id.file.dentry_p = file->f_path.dentry; + } else + if (S_ISSOCK(file->f_path.dentry->d_inode->i_mode)) { + struct socket * sock = SOCKET_I(file->f_path.dentry->d_inode); + if (sock->ops && (sock->ops->family == AF_UNIX)) { + if (sock->sk) { + if (unix_sk(unix_sk(sock->sk)->peer)) { + if (unix_sk(unix_sk(sock->sk)->peer)->path.dentry && unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode) { + rsbac_rw_req_obj->rsbac_target = T_UNIXSOCK; + rsbac_rw_req_obj->rsbac_target_id.unixsock.device = unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_sb->s_dev; + rsbac_rw_req_obj->rsbac_target_id.unixsock.inode = unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode->i_ino; + rsbac_rw_req_obj->rsbac_target_id.unixsock.dentry_p = unix_sk(unix_sk(sock->sk)->peer)->path.dentry; + } else { + rsbac_rw_req_obj->rsbac_target = T_IPC; + rsbac_rw_req_obj->rsbac_target_id.ipc.type = I_anonunix; + if (unix_sk(unix_sk(sock->sk)->peer)->path.dentry + && unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode + && SOCKET_I(unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode)->file + && SOCKET_I(unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode)->file->f_path.dentry + && SOCKET_I(unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode)->file->f_path.dentry->d_inode) + rsbac_rw_req_obj->rsbac_target_id.ipc.id.id_nr = SOCKET_I(unix_sk(unix_sk(sock->sk)->peer)->path.dentry->d_inode)->file->f_path.dentry->d_inode->i_ino; + else + if (sock->file && sock->file->f_path.dentry && sock->file->f_path.dentry->d_inode) + rsbac_rw_req_obj->rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + else + rsbac_rw_req_obj->rsbac_target_id.ipc.id.id_nr = 0; + } + } else { + if (unix_sk(sock->sk)->path.dentry && unix_sk(sock->sk)->path.dentry->d_inode) { + rsbac_rw_req_obj->rsbac_target = T_UNIXSOCK; + rsbac_rw_req_obj->rsbac_target_id.unixsock.device = unix_sk(sock->sk)->path.dentry->d_sb->s_dev; + rsbac_rw_req_obj->rsbac_target_id.unixsock.inode = unix_sk(sock->sk)->path.dentry->d_inode->i_ino; + rsbac_rw_req_obj->rsbac_target_id.unixsock.dentry_p = unix_sk(sock->sk)->path.dentry; + } else { + rsbac_rw_req_obj->rsbac_target = T_IPC; + rsbac_rw_req_obj->rsbac_target_id.ipc.type = I_anonunix; + if (sock->file && sock->file->f_path.dentry && sock->file->f_path.dentry->d_inode) + rsbac_rw_req_obj->rsbac_target_id.ipc.id.id_nr = sock->file->f_path.dentry->d_inode->i_ino; + else + rsbac_rw_req_obj->rsbac_target_id.ipc.id.id_nr = 0; + } + } + if (sock->sk->sk_peer_pid) { + rsbac_rw_req_obj->rsbac_attribute = A_process; + rsbac_rw_req_obj->rsbac_attribute_value.process = sock->sk->sk_peer_pid; + } + else if (unix_sk(sock->sk)->peer && unix_sk(sock->sk)->peer->sk_peer_pid) { + rsbac_rw_req_obj->rsbac_attribute = A_process; + rsbac_rw_req_obj->rsbac_attribute_value.process = unix_sk(sock->sk)->peer->sk_peer_pid; + } else { + rsbac_rw_req_obj->rsbac_attribute = A_sock_type; + rsbac_rw_req_obj->rsbac_attribute_value.sock_type = sock->type; + } + } + } + } else + if (S_ISBLK(file->f_path.dentry->d_inode->i_mode)) { + rsbac_rw_req_obj->rsbac_target = T_DEV; + rsbac_rw_req_obj->rsbac_target_id.dev.type = D_block; + rsbac_rw_req_obj->rsbac_target_id.dev.major = RSBAC_MAJOR(file->f_path.dentry->d_inode->i_rdev); + rsbac_rw_req_obj->rsbac_target_id.dev.minor = RSBAC_MINOR(file->f_path.dentry->d_inode->i_rdev); + } else + if (S_ISCHR(file->f_path.dentry->d_inode->i_mode)) { + rsbac_rw_req_obj->rsbac_target = T_DEV; + rsbac_rw_req_obj->rsbac_target_id.dev.type = D_char; + rsbac_rw_req_obj->rsbac_target_id.dev.major = RSBAC_MAJOR(file->f_path.dentry->d_inode->i_rdev); + rsbac_rw_req_obj->rsbac_target_id.dev.minor = RSBAC_MINOR(file->f_path.dentry->d_inode->i_rdev); + } +/* + printk("i_mode %i\n", file->f_path.dentry->d_inode->i_mode); + printk("req %i %i\n", rsbac_rw_req_obj->rsbac_request, rsbac_rw_req_obj->rsbac_target); + if (S_ISCHR(file->f_path.dentry->d_inode->i_mode)) + printk("CHR"); + if (S_ISBLK(file->f_path.dentry->d_inode->i_mode)) + printk("BLK"); + if (S_ISSOCK(file->f_path.dentry->d_inode->i_mode)) + printk("SOCK"); + if (S_ISREG(file->f_path.dentry->d_inode->i_mode)) + printk("REG"); + if (S_ISFIFO(file->f_path.dentry->d_inode->i_mode)) + printk("FIFO"); +*/ + if (rsbac_rw_req_obj->rsbac_target != T_NONE) + if (!rsbac_adf_request(rsbac_rw_req_obj->rsbac_request, + task_pid(current), + rsbac_rw_req_obj->rsbac_target, + rsbac_rw_req_obj->rsbac_target_id, + A_none, + rsbac_rw_req_obj->rsbac_attribute_value)) + { + err = 0; + goto out; + } + +out: + return err; +} + +int rsbac_handle_rw_up(struct rsbac_rw_req *rsbac_rw_req_obj) +{ + int err = 0; + + if (rsbac_rw_req_obj->rsbac_target != T_NONE) { + rsbac_rw_req_obj->rsbac_new_target_id.dummy = 0; + err = rsbac_adf_set_attr(rsbac_rw_req_obj->rsbac_request, + task_pid(current), + rsbac_rw_req_obj->rsbac_target, + rsbac_rw_req_obj->rsbac_target_id, + T_NONE, + rsbac_rw_req_obj->rsbac_new_target_id, + rsbac_rw_req_obj->rsbac_attribute, + rsbac_rw_req_obj->rsbac_attribute_value); + if (err) + rsbac_printk(KERN_WARNING "rsbac_handle_rw_up(): rsbac_adf_set_attr() returned error\n"); + } + + return err; +} +#endif +/* __KERNEL__ */ diff --git a/rsbac/help/jail_getname.c b/rsbac/help/jail_getname.c new file mode 100644 index 000000000000..44296828712a --- /dev/null +++ b/rsbac/help/jail_getname.c @@ -0,0 +1,62 @@ +/*********************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2014: */ +/* Amon Ott */ +/* Getname functions for JAIL module */ +/* Last modified: 04/Feb/2014 */ +/*********************************** */ + +#include +#include +#include +#include + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#else +#include +#endif + +#ifdef __KERNEL__ +#ifdef CONFIG_RSBAC_JAIL_LOG_MISSING +void rsbac_jail_log_missing_cap(int cap) + { + char * tmp; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + i_tid.process = task_pid(current); + if (rsbac_get_attr(SW_JAIL, + T_PROCESS, + i_tid, + A_jail_max_caps, + &i_attr_val1, + FALSE)) + { + rsbac_ds_get_error("rsbac_jail_log_missing_cap()", A_jail_max_caps); + } + else + { + if(!((i_attr_val1.jail_max_caps.cap[0] & (1 << cap)) || (i_attr_val1.jail_max_caps.cap[1] & (1 << cap)))) + { + tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN); + if(tmp) + { + get_cap_name(tmp, cap); + rsbac_printk(KERN_DEBUG + "capable(): pid %u(%s), uid %u: missing jail_max_cap %s!\n", + current->pid, current->comm, + __kuid_val(current_uid()), + tmp); + rsbac_kfree(tmp); + } + } + } + } +#endif +#endif diff --git a/rsbac/help/net_getname.c b/rsbac/help/net_getname.c new file mode 100644 index 000000000000..4559e36f3547 --- /dev/null +++ b/rsbac/help/net_getname.c @@ -0,0 +1,352 @@ +/* + * net_getname.c: Getname functions for the Network + * + * Author and Copyright (C) 1999-2009 Amon Ott + * + * This program 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, version 2. + * + * Last modified 03/Feb/2009. + */ + +#include +#include +#include +#include +#include + +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#include +#endif + +static char net_temp_syscall_list[NTS_none + 1][19] = { + "new_template", + "copy_template", + "delete_template", + "check_id", + "get_address", + "get_address_family", + "get_type", + "get_protocol", + "get_netdev", + "get_ports", + "get_name", + "set_address", + "set_address_family", + "set_type", + "set_protocol", + "set_netdev", + "set_ports", + "set_name", + "none" +}; + +static char net_family_list[AF_MAX + 1][19] = { + "ANY", /* 0 */ + "UNIX", /* 1 Unix domain sockets */ + "INET", /* 2 Internet IP Protocol */ + "AX25", /* 3 Amateur Radio AX.25 */ + "IPX", /* 4 Novell IPX */ + "APPLETALK", /* 5 AppleTalk DDP */ + "NETROM", /* 6 Amateur Radio NET/ROM */ + "BRIDGE", /* 7 Multiprotocol bridge */ + "ATMPVC", /* 8 ATM PVCs */ + "X25", /* 9 Reserved for X.25 project */ + "INET6", /* 10 IP version 6 */ + "ROSE", /* 11 Amateur Radio X.25 PLP */ + "DECnet", /* 12 Reserved for DECnet project */ + "NETBEUI", /* 13 Reserved for 802.2LLC project */ + "SECURITY", /* 14 Security callback pseudo AF */ + "KEY", /* 15 PF_KEY key management API */ + "NETLINK", /* 16 */ + "PACKET", /* 17 Packet family */ + "ASH", /* 18 Ash */ + "ECONET", /* 19 Acorn Econet */ + "ATMSVC", /* 20 ATM SVCs */ + "(undefined)", /* 21 */ + "SNA", /* 22 Linux SNA Project (nutters!) */ + "IRDA", /* 23 IRDA sockets */ + "PPPOX", /* 24 PPPoX sockets */ + "WANPIPE", /* 25 Wanpipe API Sockets */ + "(undefined)", /* 26 */ + "(undefined)", /* 27 */ + "(undefined)", /* 28 */ + "(undefined)", /* 29 */ + "(undefined)", /* 30 */ + "BLUETOOTH", /* 31 Bluetooth sockets */ + "MAX" +}; + +#define NETLINK_FAM_MAX 19 + +static char net_netlink_family_list[NETLINK_FAM_MAX + 1][15] = { + "ROUTE", /* 0 Routing/device hook */ + "UNUSED", /* 1 Unused number */ + "USERSOCK", /* 2 Reserved for user mode socket protocols */ + "FIREWALL", /* 3 Firewalling hook */ + "INET_DIAG", /* 4 INET socket monitoring */ + "NFLOG", /* 5 netfilter/iptables ULOG */ + "XFRM", /* 6 ipsec */ + "SELINUX", /* 7 SELinux event notifications */ + "ISCSI", /* 8 Open-iSCSI */ + "AUDIT", /* 9 auditing */ + "FIB_LOOKUP", + "CONNECTOR", + "NETFILTER", /* 12 netfilter subsystem */ + "IP6_FW", + "DNRTMSG", /* 14 DECnet routing messages */ + "KOBJECT_UEVENT", /* 15 Kernel messages to userspace */ + "GENERIC", + "DM", /* 17 (DM Events) */ + "SCSITRANSPORT", /* 18 SCSI Transports */ + "ECRYPTFS" +}; + +struct proto_desc_t { + char name[19]; + int nr; +}; +#define NR_PROTO 18 + +static struct proto_desc_t net_protocol_list[NR_PROTO] = { + {"ANY", 0}, /* 0 Dummy protocol for TCP */ + {"ICMP", 1}, /* Internet Control Message Protocol */ + {"IGMP", 2}, /* Internet Group Management Protocol */ + {"IPIP", 4}, /* IPIP tunnels (older KA9Q tunnels use 94) */ + {"TCP", 6}, /* Transmission Control Protocol */ + {"EGP", 8}, /* Exterior Gateway Protocol */ + {"PUP", 12}, /* PUP protocol */ + {"UDP", 17}, /* User Datagram Protocol */ + {"IDP", 22}, /* XNS IDP protocol */ + {"RSVP", 46}, /* RSVP protocol */ + {"GRE", 47}, /* Cisco GRE tunnels (rfc 1701,1702) */ + {"IPV6", 41}, /* IPv6-in-IPv4 tunnelling */ + {"PIM", 103}, /* Protocol Independent Multicast */ + {"ESP", 50}, /* Encapsulation Security Payload protocol */ + {"AH", 51}, /* Authentication Header protocol */ + {"COMP", 108}, /* Compression Header protocol */ + {"RAW", 255}, /* Raw IP packets */ + {"MAX", RSBAC_NET_PROTO_MAX} +}; + +static char rsbac_net_type_list[RSBAC_NET_TYPE_MAX + 1][19] = { + "ANY", + "STREAM", /* 1 stream (connection) socket */ + "DGRAM", /* 2 datagram (conn.less) socket */ + "RAW", /* 3 raw socket */ + "RDM", /* 4 reliably-delivered message */ + "SEQPACKET", /* 5 sequential packet socket */ + "(undefined)", /* 6 */ + "(undefined)", /* 7 */ + "(undefined)", /* 8 */ + "(undefined)", /* 9 */ + "PACKET", /* 10 linux specific way of */ + /* getting packets at the dev */ + /* level. For writing rarp and */ + /* other similar things on the */ + /* user level. */ + "MAX" +}; + +/*****************************************/ + +char *rsbac_get_net_temp_syscall_name(char *name, + enum rsbac_net_temp_syscall_t value) +{ + if (!name) + return NULL; + if (value > NTS_none) + strcpy(name, "ERROR!"); + else + strcpy(name, net_temp_syscall_list[value]); + return name; +}; + +#ifndef __KERNEL__ +enum rsbac_net_temp_syscall_t rsbac_get_net_temp_syscall_nr(const char + *name) +{ + enum rsbac_net_temp_syscall_t i; + + if (!name) + return NTS_none; + for (i = 0; i < NTS_none; i++) { + if (!strcmp(name, net_temp_syscall_list[i])) { + return i; + } + } + return NTS_none; +}; +#endif + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_get_net_family_name); +#endif +#endif +char *rsbac_get_net_family_name(char *name, u_int value) +{ + if (!name) + return NULL; + if (value > AF_MAX) + strcpy(name, "ERROR!"); + else + strcpy(name, net_family_list[value]); + return name; +}; + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_get_net_netlink_family_name); +#endif +#endif +char *rsbac_get_net_netlink_family_name(char *name, u_int value) +{ + if (!name) + return NULL; + if (value == RSBAC_NET_NETLINK_PROTO_ANY) + strcpy(name, "ANY"); + if (value > NETLINK_FAM_MAX) + strcpy(name, "ERROR!"); + else + strcpy(name, net_netlink_family_list[value]); + return name; +}; + +#ifndef __KERNEL__ +int rsbac_get_net_family_nr(const char *name) +{ + int i; + + if (!name) + return AF_MAX; + if (!strcmp(name, "ANY") + return RSBAC_NET_NETLINK_PROTO_ANY; + for (i = 0; i < AF_MAX; i++) { + if (!strcmp(name, net_family_list[i])) { + return i; + } + } + return AF_MAX; +}; +#endif + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_get_net_protocol_name); +#endif +#endif +char *rsbac_get_net_protocol_name(char *name, u_int value) +{ + int i; + + if (!name) + return NULL; + if (value >= RSBAC_NET_PROTO_MAX) + strcpy(name, "ERROR!"); + else { + for (i = 0; i < NR_PROTO; i++) { + if (net_protocol_list[i].nr == value) { + strcpy(name, net_protocol_list[i].name); + return name; + } + } + sprintf(name, "%u", value); + } + return name; +}; + +#ifndef __KERNEL__ +int rsbac_get_net_protocol_nr(const char *name) +{ + int i; + + if (!name) + return RSBAC_NET_PROTO_MAX; + for (i = 0; i < NR_PROTO; i++) { + if (!strcmp(name, net_protocol_list[i].name)) { + return net_protocol_list[i].nr; + } + } + return RSBAC_NET_PROTO_MAX; +}; +#endif + +#ifdef __KERNEL__ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_get_net_type_name); +#endif +#endif +char *rsbac_get_net_type_name(char *name, u_int value) +{ + if (!name) + return NULL; + if (value > RSBAC_NET_TYPE_MAX) + strcpy(name, "ERROR!"); + else + strcpy(name, rsbac_net_type_list[value]); + return name; +}; + +#ifndef __KERNEL__ +int rsbac_get_net_type_nr(const char *name) +{ + int i; + + if (!name) + return RSBAC_NET_TYPE_MAX; + for (i = 0; i < RSBAC_NET_TYPE_MAX; i++) { + if (!strcmp(name, rsbac_net_type_list[i])) { + return i; + } + } + return RSBAC_NET_TYPE_MAX; +}; +#endif + +#ifdef __KERNEL__ +int rsbac_net_str_to_inet(char *str, __u32 * addr) +{ + char *end; + __u32 s0, s1, s2, s3; + + if (!str || !addr) + return -RSBAC_EINVALIDPOINTER; + end = str; + while (*end) { + if ((*end != '.') + && (*end != '\n') + && (*end != ' ') + && ((*end < '0') + || (*end > '9') + ) + ) + return -RSBAC_EINVALIDVALUE; + end++; + } + s0 = simple_strtoul(str, &end, 10); + if (!*end || (s0 > 255)) + return -RSBAC_EINVALIDVALUE; + end++; + s1 = simple_strtoul(end, &end, 10); + if (!*end || (s1 > 255)) + return -RSBAC_EINVALIDVALUE; + end++; + s2 = simple_strtoul(end, &end, 10); + if (!*end || (s2 > 255)) + return -RSBAC_EINVALIDVALUE; + end++; + s3 = simple_strtoul(end, &end, 10); + if (*end || (s3 > 255)) + return -RSBAC_EINVALIDVALUE; + *addr = s3 | (s2 << 8) | (s1 << 16) | (s0 << 24); + *addr = htonl(*addr); + return 0; +} +#endif diff --git a/rsbac/help/net_helpers.c b/rsbac/help/net_helpers.c new file mode 100644 index 000000000000..fbbb3081763c --- /dev/null +++ b/rsbac/help/net_helpers.c @@ -0,0 +1,117 @@ +/* + * net_helpers.c: Helper functions for the Network. + * + * Author and Copyright (C) 1999-2009 Amon Ott + * + * This program 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, version 2. + * + * Last modified 03/Feb/2009. + */ + +#include +#ifdef __KERNEL__ +#include +#endif + +static __u32 ipv4_mask[32] = { + 0x00000000, 0x00000080, 0x000000C0, 0x000000E0, + 0x000000F0, 0x000000F8, 0x000000FC, 0x000000FE, + 0x000000FF, 0x000080FF, 0x0000C0FF, 0x0000E0FF, + 0x0000F0FF, 0x0000F8FF, 0x0000FCFF, 0x0000FEFF, + 0x0000FFFF, 0x0080FFFF, 0x00C0FFFF, 0x00E0FFFF, + 0x00F0FFFF, 0x00F8FFFF, 0x00FCFFFF, 0x00FEFFFF, + 0x00FFFFFF, 0x80FFFFFF, 0xC0FFFFFF, 0xE0FFFFFF, + 0xF0FFFFFF, 0xF8FFFFFF, 0xFCFFFFFF, 0xFEFFFFFF +}; + +static inline __u32 rsbac_net_make_mask_u32(__u8 bits) +{ + if (bits >= 32) + return (__u32)-1UL; + return ipv4_mask[bits]; +} + +#ifdef __KERNEL__ +/* The lookup data param is always second, so we use it as description here! */ +int rsbac_net_compare_data(void *data1, void *data2) +{ + struct rsbac_net_temp_data_t *temp = data1; + struct rsbac_net_description_t *desc = data2; + + if (!temp || !desc) + return 1; + if ((temp->address_family != RSBAC_NET_ANY) + && (temp->address_family != desc->address_family) + ) + return 1; + switch (desc->address_family) { + case AF_INET: + { + __u32 mask; + int i; + + if(temp->address.inet.nr_addr == 0) + return 1; + if ((temp->type != RSBAC_NET_ANY) + && (desc->type != temp->type) + ) + return 1; + if ((temp->protocol != RSBAC_NET_ANY) + && (desc->protocol != temp->protocol) + ) + return 1; + if(temp->ports.nr_ports > 0) { + i=0; + while(i < temp->ports.nr_ports) { + if ((desc->port >= temp->ports.ports[i].min) + && (desc->port <= temp->ports.ports[i].max)) + break; + i++; + } + if(i == temp->ports.nr_ports) + return 1; + } + if (temp->netdev[0] + && (!desc->netdev[0] + || strncmp(desc->netdev, temp->netdev, + RSBAC_IFNAMSIZ)) + ) + return 1; + if (!desc->address) + return 1; + i=0; + while(i < temp->address.inet.nr_addr) { + mask = rsbac_net_make_mask_u32(temp->address.inet.valid_bits[i]); + if ((((*(__u32 *) desc->address) & mask) == + (temp->address.inet.addr[i] & mask)) + ) + return 0; + i++; + } + return 1; + } + + case AF_NETLINK: + if ((temp->type != RSBAC_NET_ANY) + && (desc->type != temp->type) + ) + return 1; + if ((temp->protocol != RSBAC_NET_NETLINK_PROTO_ANY) + && (desc->protocol != temp->protocol) + ) + return 1; + return 0; + + /* Other address families: only socket type checks for now */ + default: + if ((temp->type != RSBAC_NET_ANY) + && (desc->type != temp->type) + ) + return 1; + return 0; + } + return 1; +} +#endif diff --git a/rsbac/help/pax_getname.c b/rsbac/help/pax_getname.c new file mode 100644 index 000000000000..0822b6ee282d --- /dev/null +++ b/rsbac/help/pax_getname.c @@ -0,0 +1,95 @@ +/********************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2004: */ +/* Amon Ott */ +/* Getname functions for PAX module */ +/* Last modified: 06/Jan/2004 */ +/********************************** */ + +#include +#include +#include +#include + +#ifdef __KERNEL__ +#include +#else +#include +#include +#endif + +char * pax_print_flags(char * string, rsbac_pax_flags_t flags) + { + sprintf(string, "%c%c%c%c%c%c", + flags & PF_PAX_PAGEEXEC ? 'P' : 'p', + flags & PF_PAX_EMUTRAMP ? 'E' : 'e', + flags & PF_PAX_MPROTECT ? 'M' : 'm', + flags & PF_PAX_RANDMMAP ? 'R' : 'r', + flags & PF_PAX_RANDEXEC ? 'X' : 'x', + flags & PF_PAX_SEGMEXEC ? 'S' : 's'); + return string; + } + +#ifndef __KERNEL__ +rsbac_pax_flags_t pax_strtoflags(char * string, rsbac_pax_flags_t init_flags) + { + char * p = string; + rsbac_pax_flags_t add_flags = 0; + rsbac_pax_flags_t remove_flags = 0; + + if(!p) + return init_flags; + while(*p) + { + switch(*p) + { + case 'P': + add_flags |= PF_PAX_PAGEEXEC; + break; + case 'p': + remove_flags |= PF_PAX_PAGEEXEC; + break; + case 'E': + add_flags |= PF_PAX_EMUTRAMP; + break; + case 'e': + remove_flags |= PF_PAX_EMUTRAMP; + break; + case 'M': + add_flags |= PF_PAX_MPROTECT; + break; + case 'm': + remove_flags |= PF_PAX_MPROTECT; + break; + case 'R': + add_flags |= PF_PAX_RANDMMAP; + break; + case 'r': + remove_flags |= PF_PAX_RANDMMAP; + break; + case 'X': + add_flags |= PF_PAX_RANDEXEC; + break; + case 'x': + remove_flags |= PF_PAX_RANDEXEC; + break; + case 'S': + add_flags |= PF_PAX_SEGMEXEC; + break; + case 's': + remove_flags |= PF_PAX_SEGMEXEC; + break; + case 'z': + remove_flags = RSBAC_PAX_ALL_FLAGS; + break; + case 'a': + add_flags = RSBAC_PAX_ALL_FLAGS; + break; + default: + break; + } + p++; + } + return (init_flags | add_flags) & ~remove_flags; + } +#endif diff --git a/rsbac/help/rc_getname.c b/rsbac/help/rc_getname.c new file mode 100644 index 000000000000..eae4d72f5dda --- /dev/null +++ b/rsbac/help/rc_getname.c @@ -0,0 +1,307 @@ +/* + * rc_getname.c: Getname functions for the RC module. + * + * Author and Copyright (C) 1999-2013 Amon Ott + * + * This program 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, version 2. + * + * Last modified 27/Nov/2013. + */ + +#include +#include +#include +#include + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +static char rc_target_list[RT_NONE + 1][13] = { + "ROLE", + "TYPE", + "NONE" +}; + +static char rc_admin_list[RC_none + 1][13] = { + "no_admin", + "role_admin", + "system_admin", + "none" +}; + +static char rc_scd_type_list[RST_none - RST_min + 1][20] = { + "auth_administration", + "udf_administration", + "none" +}; + +static char rc_item_list[RI_none + 1][30] = { + "role_comp", + "admin_roles", + "assign_roles", + "type_comp_fd", + "type_comp_dev", + "type_comp_user", + "type_comp_process", + "type_comp_ipc", + "type_comp_scd", + "type_comp_group", + "type_comp_netdev", + "type_comp_nettemp", + "type_comp_netobj", + "admin_type", + "name", + "def_fd_create_type", + "def_fd_ind_create_type", + "def_user_create_type", + "def_process_create_type", + "def_process_chown_type", + "def_process_execute_type", + "def_ipc_create_type", + "def_group_create_type", + "def_unixsock_create_type", + "boot_role", + "req_reauth", + "type_fd_name", + "type_dev_name", + "type_ipc_name", + "type_user_name", + "type_process_name", + "type_group_name", + "type_netdev_name", + "type_nettemp_name", + "type_netobj_name", + "type_fd_need_secdel", + "type_scd_name", + "remove_role", + "def_fd_ind_create_type_remove", + "type_fd_remove", + "type_dev_remove", + "type_ipc_remove", + "type_user_remove", + "type_process_remove", + "type_group_remove", + "type_netdev_remove", + "type_nettemp_remove", + "type_netobj_remove", +#ifdef __KERNEL__ +#endif + "none" +}; + +#ifndef __KERNEL__ +static char rc_item_param_list[RI_none + 1][100] = { + "\t0 = FALSE, 1 = TRUE", + "\t0 = FALSE, 1 = TRUE", + "\t0 = FALSE, 1 = TRUE", + "\t0 = FALSE, 1 = TRUE", + "\t0 = FALSE, 1 = TRUE", + "\t0 = FALSE, 1 = TRUE", + "0 = FALSE, 1 = TRUE", + "\t0 = FALSE, 1 = TRUE", + "\t0 = FALSE, 1 = TRUE", + "\t0 = FALSE, 1 = TRUE", + "0 = FALSE, 1 = TRUE", + "0 = FALSE, 1 = TRUE", + "0 = FALSE, 1 = TRUE", + "\t0 = no_admin, 1 = role_admin, 2 = system_admin\n\t\t\t(for RC administration only)", + "\t\tString, max. 15 chars", + "number, -2 = inherit from parent, -3 = no_create", + "parent_type new_type, -2 = inherit from parent,\n\t\t\t-3 = no_create", + "number, -2 = inherit from parent, -3 = no_create", + "number, -1 = inherit from process,\n\t\t\t-3 = no_create", + "number, -2 = inherit from parent (keep),\n\t\t\t-3 = no_create", + "number, -2 = inherit from parent (keep),\n\t\t\t-5 = use def_create of new role, -6 = no_chown", + "number, -1 = inherit from process (keep),\n\t\t\t-4 = no_execute", + "number, -3 = no_create", + "number, -7 = use_template (do not set)", + "\t0 = FALSE, 1 = TRUE", + "\tString, max. 15 chars", + "\tString, max. 15 chars", + "\tString, max. 15 chars", + "\tString, max. 15 chars", + "String, max. 15 chars", + "\tString, max. 15 chars", + "String, max. 15 chars", + "String, max. 15 chars", + "String, max. 15 chars", + "0 = FALSE, 1 = TRUE", + "\tString, max. 15 chars (read-only)", + "\t\t(none)" +}; +#endif + +static char rc_special_right_list[RCR_NONE - RSBAC_RC_SPECIAL_RIGHT_BASE + + 1][20] = { + "ADMIN", + "ASSIGN", + "ACCESS_CONTROL", + "SUPERVISOR", + "MODIFY_AUTH", + "CHANGE_AUTHED_OWNER", + "SELECT", + "MODIFY_UDF", + "NONE" +}; + +/*****************************************/ + +char *get_rc_target_name(char *name, enum rsbac_rc_target_t value) +{ + if (!name) + return (NULL); + if (value > RT_NONE) + strcpy(name, "ERROR!"); + else + strcpy(name, rc_target_list[value]); + return (name); +}; + +enum rsbac_rc_target_t get_rc_target_nr(const char *name) +{ + enum rsbac_rc_target_t i; + + if (!name) + return (RT_NONE); + for (i = 0; i < RT_NONE; i++) { + if (!strcmp(name, rc_target_list[i])) { + return (i); + } + } + return (RT_NONE); +}; + +char *get_rc_admin_name(char *name, enum rsbac_rc_admin_type_t value) +{ + if (!name) + return (NULL); + if (value > RC_none) + strcpy(name, "ERROR!"); + else + strcpy(name, rc_admin_list[value]); + return (name); +}; + +enum rsbac_rc_admin_type_t get_rc_admin_nr(const char *name) +{ + enum rsbac_rc_admin_type_t i; + + if (!name) + return (RC_none); + for (i = 0; i < RC_none; i++) { + if (!strcmp(name, rc_admin_list[i])) { + return (i); + } + } + return (RC_none); +}; + +char *get_rc_scd_type_name(char *name, enum rsbac_rc_scd_type_t value) +{ + if (!name) + return (NULL); + if (value < RST_min) { + return (get_scd_type_name(name, value)); + } + value -= RST_min; + if (value > RST_none) { + strcpy(name, "ERROR!"); + return (name); + } + strcpy(name, rc_scd_type_list[value]); + return (name); +}; + +enum rsbac_rc_scd_type_t get_rc_scd_type_nr(const char *name) +{ + enum rsbac_rc_scd_type_t i; + + if (!name) + return (RC_none); + for (i = 0; i < RC_none - RST_min; i++) { + if (!strcmp(name, rc_scd_type_list[i])) { + return (i + RST_min); + } + } + return (get_scd_type_nr(name)); +}; + +char *get_rc_item_name(char *name, enum rsbac_rc_item_t value) +{ + if (!name) + return (NULL); + if (value > RI_none) + strcpy(name, "ERROR!"); + else + strcpy(name, rc_item_list[value]); + return (name); +}; + +enum rsbac_rc_item_t get_rc_item_nr(const char *name) +{ + enum rsbac_rc_item_t i; + + if (!name) + return (RI_none); + for (i = 0; i < RI_none; i++) { + if (!strcmp(name, rc_item_list[i])) { + return (i); + } + } + return (RI_none); +}; + +#ifndef __KERNEL__ +char *get_rc_item_param(char *name, enum rsbac_rc_item_t value) +{ + if (!name) + return (NULL); + if (value > RI_none) + strcpy(name, "ERROR!"); + else + strcpy(name, rc_item_param_list[value]); + return (name); +}; +#endif + +char *get_rc_special_right_name(char *name, + enum rsbac_rc_special_rights_t value) +{ + if (!name) + return (NULL); + if (value < RSBAC_RC_SPECIAL_RIGHT_BASE) { + return (get_request_name(name, value)); + } + value -= RSBAC_RC_SPECIAL_RIGHT_BASE; + if (value > RCR_NONE) { + strcpy(name, "ERROR!"); + return (name); + } + strcpy(name, rc_special_right_list[value]); + return (name); +}; + +#ifndef __KERNEL__ +enum rsbac_rc_special_rights_t get_rc_special_right_nr(const char *name) +{ + enum rsbac_rc_special_rights_t i; + + if (!name) + return (RCR_NONE); + for (i = 0; i < (RCR_NONE - RSBAC_RC_SPECIAL_RIGHT_BASE); i++) { + if (!strcmp(name, rc_special_right_list[i])) { + return (i + RSBAC_RC_SPECIAL_RIGHT_BASE); + } + } + return (get_request_nr(name)); +} +#endif diff --git a/rsbac/help/res_getname.c b/rsbac/help/res_getname.c new file mode 100644 index 000000000000..0641eb7dac4c --- /dev/null +++ b/rsbac/help/res_getname.c @@ -0,0 +1,62 @@ +/********************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 2002: */ +/* Amon Ott */ +/* Getname functions for RES module */ +/* Last modified: 22/Nov/2002 */ +/********************************** */ + +#ifndef __KERNEL__ + +#include +#include +#include +#include + +#include + +static char res_list[RSBAC_RES_MAX+2][8] = { + "cpu", + "fsize", + "data", + "stack", + "core", + "rss", + "nproc", + "nofile", + "memlock", + "as", + "locks", + "NONE" }; + +/*****************************************/ + +char * get_res_name(char * name, + u_int value) + { + if(!name) + return(NULL); + if(value > RSBAC_RES_MAX) + strcpy(name, "ERROR!"); + else + strcpy(name, res_list[value]); + return(name); + }; + +int get_res_nr(const char * name) + { + int i; + + if(!name) + return(RSBAC_RES_NONE); + for (i = 0; i <= RSBAC_RES_MAX; i++) + { + if (!strcmp(name, res_list[i])) + { + return(i); + } + } + return(RSBAC_RES_NONE); + }; + +#endif /* !__KERNEL__ */ diff --git a/rsbac/help/rkmem.c b/rsbac/help/rkmem.c new file mode 100644 index 000000000000..c19b45b68c86 --- /dev/null +++ b/rsbac/help/rkmem.c @@ -0,0 +1,77 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Author and (c) 1999-2010: Amon Ott */ +/* (a lot copied from mm/slab.c, with other */ +/* copyrights) */ +/* Memory allocation functions for all parts */ +/* Last modified: 24/Jun/2010 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * rsbac_kmalloc - allocate memory + * @size: how many bytes of memory are required. + * + * rsbac_kmalloc is the normal method of allocating memory for RSBAC + * in the kernel. It will always be of type GFP_KERNEL in 2.4 and + * GFP_ATOMIC in 2.6. + * + * rsbac_kmalloc'd memory is freed by rsbac_kfree + */ +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_kmalloc); +#endif +void * rsbac_kmalloc (size_t size) +{ + if(!size) + return NULL; + + return kmalloc(size, GFP_ATOMIC); +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_kmalloc_unlocked); +#endif +void * rsbac_kmalloc_unlocked (size_t size) +{ + if(!size) + return NULL; + + return kmalloc(size, GFP_KERNEL); +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_kmalloc_clear); +#endif +void * rsbac_kmalloc_clear (size_t size) +{ + if(!size) + return NULL; + + return kmalloc(size, GFP_ATOMIC | __GFP_ZERO); +} + +#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT) +EXPORT_SYMBOL(rsbac_kmalloc_clear_unlocked); +#endif +void * rsbac_kmalloc_clear_unlocked (size_t size) +{ + if(!size) + return NULL; + + return kmalloc(size, GFP_KERNEL | __GFP_ZERO); +} + +inline void rsbac_kfree (const void *objp) +{ + kfree(objp); +} diff --git a/rsbac/help/syscalls.c b/rsbac/help/syscalls.c new file mode 100644 index 000000000000..f91edf81ff31 --- /dev/null +++ b/rsbac/help/syscalls.c @@ -0,0 +1,9137 @@ +/*************************************************** */ +/* Rule Set Based Access Control */ +/* Implementation of RSBAC general system calls */ +/* Author and (C) 1999-2017: Amon Ott */ +/* */ +/* Last modified: 11/Jan/2017 */ +/*************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_RSBAC_NET_OBJ +#include +#endif +#ifdef CONFIG_RSBAC_DAZ +#include +#endif +#ifdef CONFIG_RSBAC_UDF +#include +#endif + +/************************************************************************** */ +/* Global Variables */ +/************************************************************************** */ + +extern struct semaphore rsbac_write_sem; + +#ifdef CONFIG_RSBAC_XSTATS +extern __u64 syscall_count[RSYS_none]; +#endif + +/************************************************* */ +/* Declarations */ +/************************************************* */ + +/************************************************* */ +/* General functions */ +/************************************************* */ + +/* All functions return 0, if no error occurred, and a negative error code */ +/* otherwise. The error codes are defined in rsbac/error.h. */ + +int sys_rsbac_stats(void) + { + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_stats(): calling ADF\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + return rsbac_stats(); + } + +long sys_sync(void); + +int sys_rsbac_check(int correct, int check_inode) + { + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + int result; + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_check(): calling ADF\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + rsbac_printk(KERN_INFO + "sys_rsbac_check(): triggering RSBAC consistency check, correct = %u, check_inode = %u!\n", + correct, check_inode); + + result=rsbac_check_lists(correct); + + /* call other checks */ +#if defined(CONFIG_RSBAC_ACL) + if(!result) + result=rsbac_check_acl(correct); +#endif +#if defined(CONFIG_RSBAC_REG) + if(!result) + result=rsbac_check_reg(correct, check_inode); +#endif + + return result; + } + +int sys_rsbac_write(void) + { +#if defined(CONFIG_RSBAC_AUTO_WRITE) + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_write(): calling ADF\n"); + } +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_WRITE, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + return rsbac_write(); +#else + return 0; +#endif /* CONFIG_RSBAC_AUTO_WRITE */ + }; + +/************************************************* */ +/* Attribute functions */ +/************************************************* */ + +int sys_rsbac_get_attr( + rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t __user * tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t __user * value, + int inherit) + { + union rsbac_target_id_t k_tid; + union rsbac_attribute_value_t k_value; + int err = 0; + rsbac_boolean_t i_inherit; + + if(module > SW_NONE) + return -RSBAC_EINVALIDMODULE; + if(!tid || (target >= T_NONE)) + return -RSBAC_EINVALIDTARGET; + if(!value) + return -RSBAC_EINVALIDPOINTER; + if(attr >= A_none) + return -RSBAC_EINVALIDATTR; + + if(module == SW_NONE) + { + module = get_attr_module(attr); + if(module == SW_NONE) + return -RSBAC_EINVALIDMODULE; + } + + /* get values from user space */ + rsbac_get_user(&k_tid, tid, sizeof(k_tid) ); + rsbac_get_user(&k_value, value, sizeof(k_value) ); + + switch (target) { + case T_FD: + return -RSBAC_EINVALIDTARGET; + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + k_tid.file.dentry_p = NULL; + k_tid.dir.dentry_p = NULL; + break; + case T_USER: +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(k_tid.user) == RSBAC_UM_VIRTUAL_KEEP) + k_tid.user = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(k_tid.user)); + else + if ( (RSBAC_UID_SET(k_tid.user) > RSBAC_UM_VIRTUAL_MAX) + && (RSBAC_UID_SET(k_tid.user) != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDTARGET; +#else + k_tid.user = RSBAC_UID_NUM(k_tid.user); +#endif + break; + case T_GROUP: +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(k_tid.group) == RSBAC_UM_VIRTUAL_KEEP) + k_tid.group = RSBAC_GEN_GID (rsbac_get_vset(), RSBAC_GID_NUM(k_tid.group)); + else + if ( (RSBAC_GID_SET(k_tid.group) > RSBAC_UM_VIRTUAL_MAX) + && (RSBAC_GID_SET(k_tid.group) != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDTARGET; +#else + k_tid.group = RSBAC_GID_NUM(k_tid.group); +#endif + break; + case T_PROCESS: + k_tid.process = find_pid_ns(k_tid.uprocess, &init_pid_ns); + if(!k_tid.process) + return -RSBAC_EINVALIDTARGET; + break; + default: + break; + } + + if(inherit) + i_inherit = TRUE; + else + i_inherit = FALSE; + +#ifdef CONFIG_RSBAC_NET_OBJ + /* sanity check before using pointer */ + if( (target == T_NETOBJ) + && ( !k_tid.netobj.sock_p + || k_tid.netobj.remote_addr + || !k_tid.netobj.sock_p->file + || !k_tid.netobj.sock_p->file->f_path.dentry + || !k_tid.netobj.sock_p->file->f_path.dentry->d_inode + || (SOCKET_I(k_tid.netobj.sock_p->file->f_path.dentry->d_inode) != k_tid.netobj.sock_p) + ) + ) + return -RSBAC_EINVALIDTARGET; +#endif + + /* call ADF */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr(): calling ADF\n"); + } +#endif + if (!rsbac_adf_request(R_READ_ATTRIBUTE, + task_pid(current), + target, + k_tid, + attr, + k_value)) + { + return -EPERM; + } + + err = rsbac_ta_get_attr(ta_number, module, target, k_tid, attr, &k_value, i_inherit); + /* put result value to user space */ + if(!err) + { + err = rsbac_put_user(&k_value, value, sizeof(k_value) ); + } + return err; + } /* end of sys_rsbac_get_attr() */ + + +int sys_rsbac_get_attr_n( + rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + char __user * t_name, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t __user * value, + int inherit) + { + union rsbac_attribute_value_t k_value; + struct dentry * t_dentry; + int err = 0; + union rsbac_target_id_t tid; +/* struct passwd * user_description_p; */ + rsbac_boolean_t i_inherit; + struct path path; + + if(module > SW_NONE) + return -RSBAC_EINVALIDMODULE; + if(!t_name || (target >= T_NONE)) + return -RSBAC_EINVALIDTARGET; + if(!value) + return -RSBAC_EINVALIDPOINTER; + if(attr >= A_none) + return -RSBAC_EINVALIDATTR; + + if(module == SW_NONE) + { + module = get_attr_module(attr); + if(module == SW_NONE) + return -RSBAC_EINVALIDMODULE; + } + + if(inherit) + i_inherit = TRUE; + else + i_inherit = FALSE; + + /* get values from user space */ + rsbac_get_user(&k_value, value, sizeof(k_value) ); + switch (target) { + case T_FD: + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + tid.file.dentry_p = NULL; + tid.dir.dentry_p = NULL; + break; + default: + return -RSBAC_EINVALIDTARGET; + } + + /* lookup filename */ + if ((err = user_lpath(t_name, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr_n(): call to user_lpath() returned %i\n", err); + } +#endif + goto out; + } + t_dentry = path.dentry; + if (!t_dentry->d_inode) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr_n(): file not found\n"); + } +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + + switch (target) + { + /* is inode of right type? */ + case T_FD: + if(S_ISREG(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + { + target = T_DIR; + } + else + if(S_ISLNK(t_dentry->d_inode->i_mode)) + { + target = T_SYMLINK; + } + else + if(S_ISFIFO(t_dentry->d_inode->i_mode)) + { + target = T_FIFO; + } + else + if(S_ISBLK(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISCHR(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISSOCK(t_dentry->d_inode->i_mode)) + { + target = T_UNIXSOCK; + } + else + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr_n(): no filesystem object\n"); + } +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_FILE: + if ( !(S_ISREG(t_dentry->d_inode->i_mode)) + && !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr_n(): no file\n"); + } +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_DIR: + if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) ) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr_n(): no dir\n"); + } +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_FIFO: + /* is inode of type fifo? */ + if ( !(S_ISFIFO(t_dentry->d_inode->i_mode))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr_n(): no fifo\n"); + } +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_UNIXSOCK: + /* is inode of type socket? */ + if ( !(S_ISSOCK(t_dentry->d_inode->i_mode))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr_n(): no socket\n"); + } +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_SYMLINK: + if ( !(S_ISLNK(t_dentry->d_inode->i_mode))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr_n(): no symlink\n"); + } +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_DEV: + if ( !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr_n(): no dev\n"); + } +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + default: + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + + if(target == T_DEV) + { + if(S_ISBLK(t_dentry->d_inode->i_mode)) + tid.dev.type = D_block; + else + tid.dev.type = D_char; + tid.dev.major = RSBAC_MAJOR(t_dentry->d_inode->i_rdev); + tid.dev.minor = RSBAC_MINOR(t_dentry->d_inode->i_rdev); + } + else + { + /* fill target id and call internal function */ + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; + } + /* call ADF */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr_n(): calling ADF\n"); + } +#endif + if (!rsbac_adf_request(R_READ_ATTRIBUTE, + task_pid(current), + target, + tid, + attr, + k_value)) + { + err = -EPERM; + } + else + { + err = rsbac_ta_get_attr(ta_number, module, target, tid, attr, &k_value, i_inherit); + /* put result value to user space */ + if(!err) + rsbac_put_user(&k_value, value, sizeof(k_value) ); + } + +out_dput: + path_put(&path); + +out: + return err; + } /* end of sys_rsbac_get_attr_n() */ + +/************************************************************************** */ + +int sys_rsbac_set_attr( + rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + union rsbac_target_id_t __user * tid, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t __user * value) + { + union rsbac_target_id_t k_tid; + union rsbac_attribute_value_t k_value; + int err = 0; + + if(module > SW_NONE) + return -RSBAC_EINVALIDMODULE; + if(!tid || (target >= T_NONE)) + return -RSBAC_EINVALIDTARGET; + if(!value) + return -RSBAC_EINVALIDPOINTER; + if(attr >= A_none) + return -RSBAC_EINVALIDATTR; + + if(module == SW_NONE) + { + module = get_attr_module(attr); + if(module == SW_NONE) + return -RSBAC_EINVALIDMODULE; + } +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_set_attr(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + /* get values from user space */ + rsbac_get_user(&k_tid, tid, sizeof(k_tid) ); + rsbac_get_user(&k_value, value, sizeof(k_value) ); + + + switch(target) + { + case T_PROCESS: + k_tid.process = find_pid_ns(k_tid.uprocess, &init_pid_ns); + if(!k_tid.process) + return -RSBAC_EINVALIDTARGET; + break; + +#ifdef CONFIG_RSBAC_NET_OBJ + /* sanity check before using pointer */ + case T_NETOBJ: + if( !k_tid.netobj.sock_p + || k_tid.netobj.remote_addr + || !k_tid.netobj.sock_p->file + || !k_tid.netobj.sock_p->file->f_path.dentry + || !k_tid.netobj.sock_p->file->f_path.dentry->d_inode + || (SOCKET_I(k_tid.netobj.sock_p->file->f_path.dentry->d_inode) != k_tid.netobj.sock_p) + ) + return -RSBAC_EINVALIDTARGET; +#endif + break; + case T_USER: +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(k_tid.user) == RSBAC_UM_VIRTUAL_KEEP) + k_tid.user = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(k_tid.user)); + else + if ( (RSBAC_UID_SET(k_tid.user) > RSBAC_UM_VIRTUAL_MAX) + && (RSBAC_UID_SET(k_tid.user) != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDTARGET; +#else + k_tid.user = RSBAC_UID_NUM(k_tid.user); +#endif + break; + case T_GROUP: +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(k_tid.group) == RSBAC_UM_VIRTUAL_KEEP) + k_tid.group = RSBAC_GEN_GID (rsbac_get_vset(), RSBAC_GID_NUM(k_tid.group)); + else + if ( (RSBAC_GID_SET(k_tid.group) > RSBAC_UM_VIRTUAL_MAX) + && (RSBAC_GID_SET(k_tid.group) != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDTARGET; +#else + k_tid.group = RSBAC_GID_NUM(k_tid.group); +#endif + break; + + case T_FD: + case T_FILE: + case T_DIR: + case T_FIFO: + case T_SYMLINK: + case T_UNIXSOCK: + return -RSBAC_EINVALIDTARGET; + + default: + break; + } + + /* call ADF */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG + "sys_rsbac_set_attr(): calling ADF\n"); +#endif + if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE, + task_pid(current), + target, + k_tid, + attr, + k_value)) + { + return -EPERM; + } + err = rsbac_ta_set_attr(ta_number, module, target, k_tid, attr, k_value); + return err; + } /* end of sys_rsbac_set_attr() */ + +int sys_rsbac_set_attr_n( + rsbac_list_ta_number_t ta_number, + enum rsbac_switch_target_t module, + enum rsbac_target_t target, + char __user * t_name, + enum rsbac_attribute_t attr, + union rsbac_attribute_value_t __user * value) + { + struct dentry * t_dentry; + int err = 0; + union rsbac_attribute_value_t k_value; + union rsbac_target_id_t tid; + struct path path; + + if(module > SW_NONE) + return -RSBAC_EINVALIDMODULE; + if(!t_name || (target >= T_NONE)) + return -RSBAC_EINVALIDTARGET; + if(!value) + return -RSBAC_EINVALIDPOINTER; + if(attr >= A_none) + return -RSBAC_EINVALIDATTR; + + if(module == SW_NONE) + { + module = get_attr_module(attr); + if(module == SW_NONE) + return -RSBAC_EINVALIDMODULE; + } + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_set_attr_n(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + /* get values from user space */ + rsbac_get_user(&k_value, value, sizeof(k_value) ); + + /* lookup filename */ + if ((err = user_lpath(t_name, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_set_attr_n(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + if (!t_dentry->d_inode) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_set_attr_n(): file not found\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + + switch (target) + { + /* is inode of right type? */ + case T_FD: + if(S_ISREG(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + { + target = T_DIR; + } + else + if(S_ISLNK(t_dentry->d_inode->i_mode)) + { + target = T_SYMLINK; + } + else + if(S_ISFIFO(t_dentry->d_inode->i_mode)) + { + target = T_FIFO; + } + else + if(S_ISSOCK(t_dentry->d_inode->i_mode)) + { + target = T_UNIXSOCK; + } + else + if(S_ISBLK(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISCHR(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_set_attr_n(): no filesystem object\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_FILE: + if ( !(S_ISREG(t_dentry->d_inode->i_mode)) + && !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_set_attr_n(): no file\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_DIR: + if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) ) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr(): no dir\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_FIFO: + /* is inode of type fifo? */ + if ( !(S_ISFIFO(t_dentry->d_inode->i_mode))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_set_attr_n(): no fifo\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_UNIXSOCK: + /* is inode of type fifo? */ + if ( !(S_ISSOCK(t_dentry->d_inode->i_mode))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_set_attr_n(): no socket\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_SYMLINK: + if ( !(S_ISLNK(t_dentry->d_inode->i_mode))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_set_attr_n(): no symlink\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_DEV: + if ( !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) rsbac_printk(KERN_DEBUG "sys_rsbac_set_attr_n(): no dev\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + default: + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + + if(target == T_DEV) + { + if(S_ISBLK(t_dentry->d_inode->i_mode)) + tid.dev.type = D_block; + else + tid.dev.type = D_char; + tid.dev.major = RSBAC_MAJOR(t_dentry->d_inode->i_rdev); + tid.dev.minor = RSBAC_MINOR(t_dentry->d_inode->i_rdev); + } + else + { + /* fill target id and call internal function */ + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; + } + /* call ADF */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) rsbac_printk(KERN_DEBUG "sys_rsbac_set_attr_n(): calling ADF\n"); +#endif + if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE, + task_pid(current), + target, + tid, + attr, + k_value)) + { + err = -EPERM; + } + else + { + err = rsbac_ta_set_attr(ta_number, module, target, tid, attr, k_value); + } + +out_dput: + path_put(&path); + +out: + return err; + } /* end of sys_rsbac_set_attr_n() */ + +/************************************************************************** */ + +int sys_rsbac_remove_target( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t __user * tid) + { + union rsbac_target_id_t k_tid; + int err = 0; + + /* for adf_request */ + union rsbac_attribute_value_t rsbac_attribute_value; + + if(!tid || (target >= T_NONE)) + return -RSBAC_EINVALIDTARGET; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_remove_target(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + /* get values from user space */ + rsbac_get_user(&k_tid, tid, sizeof(k_tid) ); + + switch (target) { + case T_USER: +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(k_tid.user) == RSBAC_UM_VIRTUAL_KEEP) + k_tid.user = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(k_tid.user)); +#else + k_tid.user = RSBAC_UID_NUM(k_tid.user); +#endif + break; + case T_GROUP: +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(k_tid.group) == RSBAC_UM_VIRTUAL_KEEP) + k_tid.group = RSBAC_GEN_GID (rsbac_get_vset(), RSBAC_GID_NUM(k_tid.group)); +#else + k_tid.group = RSBAC_GID_NUM(k_tid.group); +#endif + break; + case T_PROCESS: + k_tid.process = find_pid_ns(k_tid.uprocess, &init_pid_ns); + if(!k_tid.process) + return -RSBAC_EINVALIDTARGET; + break; + + default: + break; + } + + /* call ADF */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) rsbac_printk(KERN_DEBUG "sys_rsbac_remove_target(): calling ADF\n"); +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE, + task_pid(current), + target, + k_tid, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + err = rsbac_ta_remove_target(ta_number, target, k_tid); + return err; + } /* end of sys_rsbac_remove_target() */ + +int sys_rsbac_remove_target_n( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + char __user * t_name) + { + struct dentry * t_dentry; + int err = 0; + union rsbac_target_id_t tid; + + /* for adf_request */ + union rsbac_attribute_value_t rsbac_attribute_value; + +/* struct passwd * user_description_p; */ + + struct path path; + + if(!t_name || (target >= T_NONE)) + return -RSBAC_EINVALIDTARGET; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_remove_target_n(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + /* lookup filename */ + if ((err = user_lpath(t_name, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_remove_target_n(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + if (!t_dentry->d_inode) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_remove_target_n(): file not found\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + + switch (target) + { + /* is inode of right type? */ + case T_FD: + if(S_ISREG(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + { + target = T_DIR; + } + else + if(S_ISLNK(t_dentry->d_inode->i_mode)) + { + target = T_SYMLINK; + } + else + if(S_ISFIFO(t_dentry->d_inode->i_mode)) + { + target = T_FIFO; + } + else + if(S_ISSOCK(t_dentry->d_inode->i_mode)) + { + target = T_UNIXSOCK; + } + else + if(S_ISBLK(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISCHR(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_remove_target_n(): no filesystem object\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_FILE: + if ( !(S_ISREG(t_dentry->d_inode->i_mode)) + && !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_remove_target_n(): no file\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_DIR: + if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) ) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) rsbac_printk(KERN_DEBUG "sys_rsbac_get_attr(): no dir\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_FIFO: + /* is inode of type fifo? */ + if ( !(S_ISFIFO(t_dentry->d_inode->i_mode))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_remove_target_n(): no fifo\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_UNIXSOCK: + /* is inode of type fifo? */ + if ( !(S_ISSOCK(t_dentry->d_inode->i_mode))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_remove_target_n(): no socket\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_SYMLINK: + if ( !(S_ISLNK(t_dentry->d_inode->i_mode))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_remove_target_n(): no symlink\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_DEV: + if ( !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) rsbac_printk(KERN_DEBUG "sys_rsbac_remove_target_n(): no dev\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + default: + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + + if(target == T_DEV) + { + if(S_ISBLK(t_dentry->d_inode->i_mode)) + tid.dev.type = D_block; + else + tid.dev.type = D_char; + tid.dev.major = RSBAC_MAJOR(t_dentry->d_inode->i_rdev); + tid.dev.minor = RSBAC_MINOR(t_dentry->d_inode->i_rdev); + } + else + { + /* fill target id and call internal function */ + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; + } + /* call ADF */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) rsbac_printk(KERN_DEBUG "sys_rsbac_remove_target_n(): calling ADF\n"); +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE, + task_pid(current), + target, + tid, + A_none, + rsbac_attribute_value)) + { + err = -EPERM; + } + else + { + err = rsbac_ta_remove_target(ta_number, target, tid); + } + +out_dput: + path_put(&path); + +out: + return err; + } /* end of sys_rsbac_remove_target_n() */ + +int sys_rsbac_list_all_dev( + rsbac_list_ta_number_t ta_number, + struct rsbac_dev_desc_t __user * id_p, + u_long maxnum) + { + int err = 0; + long count; + + if(id_p && maxnum) + { + struct rsbac_dev_desc_t * k_id_p = NULL; + + count = rsbac_ta_list_all_dev(ta_number, &k_id_p); + if(count <= 0) + return count; + if(count > maxnum) + count = maxnum; + + err = rsbac_put_user(k_id_p, id_p, count * sizeof(*k_id_p) ); + + rsbac_kfree(k_id_p); + + if(unlikely(err < 0)) + return err; + else + return count; + } + else + return rsbac_ta_list_all_dev(ta_number, NULL); + } + +int sys_rsbac_list_all_user( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t __user * id_p, + u_long maxnum) + { + int err = 0; + long count; + + if(id_p && maxnum) + { + rsbac_uid_t * k_id_p = NULL; + + count = rsbac_ta_list_all_user(ta_number, &k_id_p); + if(count <= 0) + return count; + if(count > maxnum) + count = maxnum; + + err = rsbac_put_user(k_id_p, id_p, count * sizeof(*k_id_p) ); + + rsbac_kfree(k_id_p); + + if(unlikely(err < 0)) + return err; + else + return count; + } + else + return rsbac_ta_list_all_user(ta_number, NULL); + } + +int sys_rsbac_list_all_group( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t __user * id_p, + u_long maxnum) + { + int err = 0; + long count; + + if(id_p && maxnum) + { + rsbac_gid_t * k_id_p = NULL; + + count = rsbac_ta_list_all_group(ta_number, &k_id_p); + if(count <= 0) + return count; + if(count > maxnum) + count = maxnum; + + err = rsbac_put_user(k_id_p, id_p, count * sizeof(*k_id_p) ); + + rsbac_kfree(k_id_p); + + if(unlikely(err < 0)) + return err; + else + return count; + } + else + return rsbac_ta_list_all_group(ta_number, NULL); + } + +int sys_rsbac_list_all_ipc(rsbac_list_ta_number_t ta_number, + struct rsbac_ipc_t __user * id_p, u_long maxnum) +{ + int err = 0; + long count; + + if (id_p && maxnum) { + struct rsbac_ipc_t *k_id_p = NULL; + + count = rsbac_ta_list_all_ipc(ta_number, &k_id_p); + if (count <= 0) + return count; + if (count > maxnum) + count = maxnum; + + err = rsbac_put_user(k_id_p, id_p, + count * sizeof(*k_id_p)); + + rsbac_kfree(k_id_p); + + if(unlikely(err < 0)) + return err; + else + return count; + } else + return rsbac_ta_list_all_ipc(ta_number, NULL); +} + +int sys_rsbac_net_list_all_netdev( + rsbac_list_ta_number_t ta_number, + rsbac_netdev_id_t __user * id_p, + u_long maxnum) + { +#ifdef CONFIG_RSBAC_NET_DEV + int err = 0; + long count; + + if(id_p && maxnum) + { + rsbac_netdev_id_t * k_id_p = NULL; + + count = rsbac_ta_net_list_all_netdev(ta_number, &k_id_p); + if(count <= 0) + return count; + if(count > maxnum) + count = maxnum; + + err = rsbac_put_user(k_id_p, id_p, count * sizeof(*k_id_p) ); + + rsbac_kfree(k_id_p); + + if(unlikely(err < 0)) + return err; + else + return count; + } + else + return rsbac_ta_net_list_all_netdev(ta_number, NULL); + +#else + return -RSBAC_EINVALIDREQUEST; +#endif /* CONFIG_RSBAC_NET_DEV */ + } + +int sys_rsbac_net_template(rsbac_list_ta_number_t ta_number, + enum rsbac_net_temp_syscall_t call, + rsbac_net_temp_id_t id, + union rsbac_net_temp_syscall_data_t __user * data_p) +{ +#ifdef CONFIG_RSBAC_NET_OBJ + union rsbac_net_temp_syscall_data_t k_data; + int err = 0; + /* for adf_request */ + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val; + + if (!id) + return -RSBAC_EINVALIDVALUE; + if (!data_p) + return -RSBAC_EINVALIDPOINTER; + + /* get data values from user space */ + switch (call) { + case NTS_set_address: + case NTS_set_address_family: + case NTS_set_type: + case NTS_set_protocol: + case NTS_set_netdev: + case NTS_set_ports: + case NTS_set_name: + case NTS_new_template: + case NTS_copy_template: + case NTS_delete_template: +#ifdef CONFIG_RSBAC_FREEZE + if (rsbac_freeze) { + rsbac_printk(KERN_WARNING "sys_rsbac_net_template(): RSBAC configuration frozen, no administration allowed\n"); + return -EPERM; + } +#endif + if (call != NTS_delete_template) { + err = + rsbac_get_user(&k_data, data_p, sizeof(k_data)); + if(unlikely(err < 0)) + return err; + } + break; + case NTS_check_id: + case NTS_get_address: + case NTS_get_address_family: + case NTS_get_type: + case NTS_get_protocol: + case NTS_get_netdev: + case NTS_get_ports: + case NTS_get_name: + break; + + default: + return -RSBAC_EINVALIDREQUEST; + } + + if ( (call != NTS_new_template) + && (call != NTS_copy_template) + && !rsbac_ta_net_template_exists(ta_number, id) + ) + return -RSBAC_EINVALIDTARGET; + + rsbac_pr_debug(aef, "calling ADF\n"); + i_tid.nettemp = id; + i_attr_val.dummy = 0; + switch (call) { + case NTS_new_template: + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_NETTEMP, + i_tid, A_none, i_attr_val)) +#ifdef CONFIG_RSBAC_SOFTMODE + if (!rsbac_softmode) +#endif + return -EPERM; + break; + + case NTS_copy_template: + if (!rsbac_ta_net_template_exist(ta_number, id)) { + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_NETTEMP, + i_tid, A_none, i_attr_val)) +#ifdef CONFIG_RSBAC_SOFTMODE + if (!rsbac_softmode) +#endif + return -EPERM; + } else { + if (!rsbac_adf_request(R_WRITE, + task_pid(current), + T_NETTEMP, + i_tid, A_none, i_attr_val)) +#ifdef CONFIG_RSBAC_SOFTMODE + if (!rsbac_softmode) +#endif + return -EPERM; + } + i_tid.nettemp = k_data.id; + if (!rsbac_adf_request(R_READ, + task_pid(current), + T_NETTEMP, + i_tid, A_none, i_attr_val)) +#ifdef CONFIG_RSBAC_SOFTMODE + if (!rsbac_softmode) +#endif + return -EPERM; + break; + + case NTS_delete_template: + if (!rsbac_adf_request(R_DELETE, + task_pid(current), + T_NETTEMP, + i_tid, A_none, i_attr_val)) +#ifdef CONFIG_RSBAC_SOFTMODE + if (!rsbac_softmode) +#endif + return -EPERM; + break; + + case NTS_get_address: + case NTS_get_address_family: + case NTS_get_type: + case NTS_get_protocol: + case NTS_get_netdev: + case NTS_get_ports: + if (!rsbac_adf_request(R_READ, + task_pid(current), + T_NETTEMP, + i_tid, A_none, i_attr_val)) +#ifdef CONFIG_RSBAC_SOFTMODE + if (!rsbac_softmode) +#endif + return -EPERM; + break; + + case NTS_set_address: + case NTS_set_address_family: + case NTS_set_type: + case NTS_set_protocol: + case NTS_set_netdev: + case NTS_set_ports: + case NTS_set_name: + if (!rsbac_adf_request(R_WRITE, + task_pid(current), + T_NETTEMP, + i_tid, A_none, i_attr_val)) +#ifdef CONFIG_RSBAC_SOFTMODE + if (!rsbac_softmode) +#endif + return -EPERM; + break; + + default: + break; + } + + err = rsbac_ta_net_template(ta_number, call, id, &k_data); + if (!err) { + /* put data values to user space */ + switch (call) { + case NTS_check_id: + case NTS_get_address: + case NTS_get_address_family: + case NTS_get_type: + case NTS_get_protocol: + case NTS_get_netdev: + case NTS_get_ports: + case NTS_get_name: + err = rsbac_put_user(&k_data, + data_p, + sizeof(k_data)); + break; + default: + break; + } + } + return err; + +#else + return -RSBAC_EINVALIDREQUEST; +#endif /* NET_OBJ */ +} + +int sys_rsbac_net_list_all_template( + rsbac_list_ta_number_t ta_number, + rsbac_net_temp_id_t __user * id_p, + u_long maxnum) + { +#ifdef CONFIG_RSBAC_NET_OBJ + int err = 0; + int count; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val; + + i_tid.nettemp = 0; + i_attr_val.dummy = 0; + if (!rsbac_adf_request(R_READ, + task_pid(current), + T_NETTEMP, + i_tid, + A_none, + i_attr_val)) + return -EPERM; + if(id_p && maxnum) + { + rsbac_net_temp_id_t * k_id_p = NULL; + + count = rsbac_ta_net_list_all_template(ta_number, &k_id_p); + if(count <= 0) + return count; + if(count > maxnum) + count = maxnum; + + err = rsbac_put_user(k_id_p, id_p, count * sizeof(*k_id_p) ); + + rsbac_kfree(k_id_p); + + if(unlikely(err < 0)) + return err; + else + return count; + } + else + return rsbac_ta_net_list_all_template(ta_number, NULL); + +#else + return -RSBAC_EINVALIDREQUEST; +#endif /* CONFIG_RSBAC_NET_OBJ */ + } + + +/************************************************* */ +/* ADF functions */ +/************************************************* */ + +int sys_rsbac_switch(enum rsbac_switch_target_t module, int value) + { +#if defined(CONFIG_RSBAC_SWITCH) || defined(CONFIG_RSBAC_SOFTMODE) + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + char * switch_name; + + /* call ADF */ + if(module >= SW_NONE) + return -RSBAC_EINVALIDTARGET; + if ( (value < 0) +#ifdef CONFIG_RSBAC_SOFTMODE_IND + || (value > 3) +#else + || (value > 1) +#endif + ) + return -RSBAC_EINVALIDVALUE; + +#ifdef CONFIG_RSBAC_SOFTMODE + if( rsbac_softmode_prohibit + && ( ( (value == 1) + && (module == SW_SOFTMODE) + ) +#ifdef CONFIG_RSBAC_SOFTMODE_IND + || (value == 3) +#endif + ) + ) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_switch(): setting of softmode prohibited!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_switch(): calling ADF\n"); +#endif + rsbac_target_id.dummy = 0; + rsbac_attribute_value.switch_target = module; + if (!rsbac_adf_request(R_SWITCH_MODULE, + task_pid(current), + T_NONE, + rsbac_target_id, + A_switch_target, + rsbac_attribute_value)) + { + return -EPERM; + } + + switch(value) + { +#ifdef CONFIG_RSBAC_SOFTMODE_IND + case 2: + case 3: + rsbac_ind_softmode[module] = value - 2; + break; +#endif + + default: + switch (module) + { +#ifdef CONFIG_RSBAC_SOFTMODE + case SW_SOFTMODE: rsbac_softmode = value; + break; +#endif +#ifdef CONFIG_RSBAC_FREEZE + case SW_FREEZE: + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_switch(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } + rsbac_freeze = value; + break; +#endif +#ifdef CONFIG_RSBAC_SWITCH_MAC + case SW_MAC: +#ifndef CONFIG_RSBAC_SWITCH_ON + if(value) + return -RSBAC_EINVALIDMODULE; +#endif + rsbac_switch_mac = value; + break; +#endif +#ifdef CONFIG_RSBAC_SWITCH_DAZ + case SW_DAZ: + rsbac_switch_daz = value; + break; +#endif +#ifdef CONFIG_RSBAC_SWITCH_FF + case SW_FF: + rsbac_switch_ff = value; + break; +#endif +#ifdef CONFIG_RSBAC_SWITCH_RC + case SW_RC: +#ifndef CONFIG_RSBAC_SWITCH_ON + if(value) + return -RSBAC_EINVALIDMODULE; +#endif + rsbac_switch_rc = value; + break; +#endif +#ifdef CONFIG_RSBAC_SWITCH_AUTH + case SW_AUTH: + rsbac_switch_auth = value; + break; +#endif +#ifdef CONFIG_RSBAC_SWITCH_ACL + case SW_ACL: + rsbac_switch_acl = value; + break; +#endif +#ifdef CONFIG_RSBAC_SWITCH_CAP + case SW_CAP: + rsbac_switch_cap = value; + break; +#endif +#ifdef CONFIG_RSBAC_SWITCH_JAIL + case SW_JAIL: + rsbac_switch_jail = value; + break; +#endif +#ifdef CONFIG_RSBAC_SWITCH_RES + case SW_RES: + rsbac_switch_res = value; + break; +#endif +#ifdef CONFIG_RSBAC_SWITCH_PAX + case SW_PAX: + rsbac_switch_pax = value; + break; +#endif +#ifdef CONFIG_RSBAC_SWITCH_UDF + case SW_UDF: + rsbac_switch_udf = value; + break; +#endif +#ifdef CONFIG_RSBAC_SWITCH_MPROTECT + case SW_MPROTECT: + rsbac_switch_mprotect = value; + break; +#endif + default: + return -RSBAC_EINVALIDMODULE; + } + } + + switch_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(switch_name) + { + int show_value = value; + + get_switch_target_name(switch_name, module); +#ifdef CONFIG_RSBAC_SOFTMODE_IND + switch(value) + { + case 2: + case 3: + strcat(switch_name, " softmode"); + show_value -= 2; + break; + default: + break; + } +#endif + rsbac_printk(KERN_WARNING + "sys_rsbac_switch(): user %u switched RSBAC module %s to %i!\n", + __kuid_val(current_uid()), switch_name, show_value); + rsbac_kfree(switch_name); + } + return 0; +#else + return -RSBAC_EINVALIDREQUEST; +#endif /* SWITCH || SOFTMODE*/ + } + +/** + * sys_rsbac_get_switch - get the module status + * (is switchable ? is softmodable ?) + * + * @module: the target module + * @value_p: 0: module is enabled + * 1: module is softmodded + * @switchable_p: 0: module can be turned on + * 1: module can be turned off + * 2: softmode can be turned on, but not off + * 3: softmode can be turned on or off + * + * Returns 0 on success + */ +int sys_rsbac_get_switch(enum rsbac_switch_target_t module, + int __user * value_p, + int __user * switchable_p) +{ + int value = 1; // default if module exists and RSBAC_SWITCH is not compiled + int switchable = 0; + int allow_softmode = 0; + int err = 0; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(module >= SW_NONE) + return -RSBAC_EINVALIDTARGET; + +#ifdef CONFIG_RSBAC_DEBUG + if(rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_get_switch(): calling ADF\n"); +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.dummy = 0; + if(!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + switch(module) + { + case SW_GEN: + allow_softmode = 0; + switchable = 0; + break; +#ifdef CONFIG_RSBAC_UM + case SW_UM: + allow_softmode = 0; + switchable = 0; + break; +#endif +#ifdef CONFIG_RSBAC_REG + case SW_REG: + allow_softmode = 1; + switchable = 0; + break; +#endif +#ifdef CONFIG_RSBAC_SOFTMODE + case SW_SOFTMODE: + allow_softmode = 0; + value = rsbac_softmode; + switchable = (rsbac_softmode_prohibit?2:3); + break; +#endif +#ifdef CONFIG_RSBAC_FREEZE + case SW_FREEZE: + allow_softmode = 0; + value = rsbac_freeze; + switchable = 1; + break; +#endif +#ifdef CONFIG_RSBAC_MAC + case SW_MAC: + allow_softmode = 1; +#ifdef CONFIG_RSBAC_SWITCH_MAC + value = rsbac_switch_mac; +#ifdef CONFIG_RSBAC_SWITCH_ON + switchable = 3; +#else + switchable = 2; +#endif +#else + switchable = 0; +#endif + break; +#endif +#ifdef CONFIG_RSBAC_DAZ + case SW_DAZ: + allow_softmode = 1; +#ifdef CONFIG_RSBAC_SWITCH_DAZ + value = rsbac_switch_daz; + switchable = 3; +#else + switchable = 0; +#endif + break; +#endif +#ifdef CONFIG_RSBAC_FF + case SW_FF: + allow_softmode = 1; +#ifdef CONFIG_RSBAC_SWITCH_FF + value = rsbac_switch_ff; + switchable = 3; +#else + switchable = 0; +#endif + break; +#endif +#ifdef CONFIG_RSBAC_RC + case SW_RC: + allow_softmode = 1; +#ifdef CONFIG_RSBAC_SWITCH_RC + value = rsbac_switch_rc; +#ifdef CONFIG_RSBAC_SWITCH_ON + switchable = 3; +#else + switchable = 2; +#endif +#else + switchable = 0; +#endif + break; +#endif +#ifdef CONFIG_RSBAC_AUTH + case SW_AUTH: + allow_softmode = 1; +#ifdef CONFIG_RSBAC_SWITCH_AUTH + value = rsbac_switch_auth; + switchable = 3; +#else + switchable = 0; +#endif + break; +#endif +#ifdef CONFIG_RSBAC_ACL + case SW_ACL: + allow_softmode = 1; +#ifdef CONFIG_RSBAC_SWITCH_ACL + value = rsbac_switch_acl; + switchable = 3; +#else + switchable = 0; +#endif + break; +#endif +#ifdef CONFIG_RSBAC_CAP + case SW_CAP: + allow_softmode = 1; +#ifdef CONFIG_RSBAC_SWITCH_CAP + value = rsbac_switch_cap; + switchable = 3; +#else + switchable = 0; +#endif + break; +#endif +#ifdef CONFIG_RSBAC_JAIL + case SW_JAIL: + allow_softmode = 1; +#ifdef CONFIG_RSBAC_SWITCH_JAIL + value = rsbac_switch_jail; + switchable = 3; +#else + switchable = 0; +#endif + break; +#endif +#ifdef CONFIG_RSBAC_RES + case SW_RES: + allow_softmode = 1; +#ifdef CONFIG_RSBAC_SWITCH_RES + value = rsbac_switch_res; + switchable = 3; +#else + switchable = 0; +#endif + break; +#endif +#ifdef CONFIG_RSBAC_PAX + case SW_PAX: + allow_softmode = 1; +#ifdef CONFIG_RSBAC_SWITCH_PAX + value = rsbac_switch_pax; + switchable = 3; +#else + switchable = 0; +#endif + break; +#endif +#ifdef CONFIG_RSBAC_UDF + case SW_UDF: + allow_softmode = 1; +#ifdef CONFIG_RSBAC_SWITCH_UDF + value = rsbac_switch_udf; + switchable = 3; +#else + switchable = 0; +#endif + break; +#endif +#ifdef CONFIG_RSBAC_MPROTECT + case SW_MPROTECT: + allow_softmode = 1; +#ifdef CONFIG_RSBAC_SWITCH_MPROTECT + value = rsbac_switch_mprotect; + switchable = 3; +#else + switchable = 0; +#endif + break; +#endif + default: + return -RSBAC_EINVALIDMODULE; + } + +#ifdef CONFIG_RSBAC_SOFTMODE_IND + if(allow_softmode) { + value |= rsbac_ind_softmode[module] << 1; + switchable |= (rsbac_softmode_prohibit?2:3) << 2; + } +#endif + if(value_p) + err = rsbac_put_user(&value, value_p, sizeof(int)); + if(!err && switchable_p) + err = rsbac_put_user(&switchable, switchable_p, sizeof(int)); + return err; +} + +/************** MAC ***************/ + +#ifdef CONFIG_RSBAC_MAC +int sys_rsbac_mac_set_curr_level(rsbac_security_level_t level, + rsbac_mac_category_vector_t __user * categories_p) + { + rsbac_mac_category_vector_t k_categories; + int err; + + if(!categories_p) + return -RSBAC_EINVALIDPOINTER; + err = rsbac_get_user(&k_categories, categories_p, sizeof(k_categories)); + if(unlikely(err < 0)) + return err; + return rsbac_mac_set_curr_level(level, k_categories); + } + +int sys_rsbac_mac_get_curr_level(rsbac_security_level_t __user * level_p, + rsbac_mac_category_vector_t __user * categories_p) + { + int err = 0; + rsbac_security_level_t k_level; + rsbac_mac_category_vector_t k_categories; + + err = rsbac_mac_get_curr_level(&k_level, &k_categories); + if(unlikely(err < 0)) + return err; + if(level_p) + { + err = rsbac_put_user(&k_level, level_p, sizeof(k_level)); + if(unlikely(err < 0)) + return err; + } + if(categories_p) + { + err = rsbac_put_user(&k_categories, categories_p, sizeof(k_categories)); + } + return err; + } + +int sys_rsbac_mac_get_max_level(rsbac_security_level_t __user * level_p, + rsbac_mac_category_vector_t __user * categories_p) + { + int err = 0; + rsbac_security_level_t k_level; + rsbac_mac_category_vector_t k_categories; + + err = rsbac_mac_get_max_level(&k_level, &k_categories); + if(unlikely(err < 0)) + return err; + if(level_p) + { + err = rsbac_put_user(&k_level, level_p, sizeof(k_level)); + if(unlikely(err < 0)) + return err; + } + if(categories_p) + { + err = rsbac_put_user(&k_categories, categories_p, sizeof(k_categories)); + } + return err; + } + +int sys_rsbac_mac_get_min_level(rsbac_security_level_t __user * level_p, + rsbac_mac_category_vector_t __user * categories_p) + { + int err = 0; + rsbac_security_level_t k_level; + rsbac_mac_category_vector_t k_categories; + + err = rsbac_mac_get_min_level(&k_level, &k_categories); + if(unlikely(err < 0)) + return err; + if(level_p) + { + err = rsbac_put_user(&k_level, level_p, sizeof(k_level)); + if(unlikely(err < 0)) + return err; + } + if(categories_p) + { + err = rsbac_put_user(&k_categories, categories_p, sizeof(k_categories)); + } + return err; + } + +/* Provide means for adding and removing of capabilities */ +int sys_rsbac_mac_add_p_tru( + rsbac_list_ta_number_t ta_number, + rsbac_upid_t upid, + rsbac_uid_t uid, + rsbac_time_t ttl) + { + rsbac_pid_t pid; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_mac_add_p_tru(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(uid)); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + + pid = find_pid_ns(upid, &init_pid_ns); + if(!pid) + return -RSBAC_EINVALIDTARGET; + + return rsbac_mac_add_p_tru(ta_number, pid, uid, ttl); + } + +int sys_rsbac_mac_remove_p_tru( + rsbac_list_ta_number_t ta_number, + rsbac_upid_t upid, + rsbac_uid_t uid) + { + rsbac_pid_t pid; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_mac_remove_p_tru(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(uid)); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + + pid = find_pid_ns(upid, &init_pid_ns); + if(!pid) + return -RSBAC_EINVALIDTARGET; + return rsbac_mac_remove_p_tru(ta_number, pid, uid); + } + +int sys_rsbac_mac_add_f_tru( + rsbac_list_ta_number_t ta_number, + char __user * filename, + rsbac_uid_t uid, + rsbac_time_t ttl) + { + struct dentry * t_dentry; + int err = 0; + enum rsbac_target_t target; + union rsbac_target_id_t tid; + + struct path path; + + if(!filename) + return -RSBAC_EINVALIDTARGET; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_mac_add_f_tru(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(uid)); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + + if ((err = user_lpath(filename, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_mac) + rsbac_printk(KERN_DEBUG "sys_rsbac_mac_add_f_tru(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type file? */ + if(S_ISREG(t_dentry->d_inode->i_mode)) + target = T_FILE; + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + target = T_DIR; + else + { /* This is no file or dir */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; + + err = rsbac_mac_add_f_tru(ta_number, tid.file, uid, ttl); + +out_dput: + path_put(&path); + +out: + return err; + } + +int sys_rsbac_mac_remove_f_tru( + rsbac_list_ta_number_t ta_number, + char __user * filename, + rsbac_uid_t uid) + { + struct dentry * t_dentry; + int err = 0; + enum rsbac_target_t target; + union rsbac_target_id_t tid; + + struct path path; + + if(!filename) + return -RSBAC_EINVALIDTARGET; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_mac_remove_f_tru(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(uid)); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + + if ((err = user_lpath(filename, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_mac) + rsbac_printk(KERN_DEBUG "sys_rsbac_mac_remove_f_tru(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type file or dir? */ + if(S_ISREG(t_dentry->d_inode->i_mode)) + target = T_FILE; + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + target = T_DIR; + else + { /* This is no file or dir */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; + + err = rsbac_mac_remove_f_tru(ta_number, tid.file, uid); + +out_dput: + path_put(&path); +out: + return err; + } + +/* trulist must have space for maxnum rsbac_uid_t entries! */ +int sys_rsbac_mac_get_f_trulist( + rsbac_list_ta_number_t ta_number, + char __user * filename, + rsbac_uid_t __user trulist[], + rsbac_time_t __user ttllist[], + u_int maxnum) + { + struct dentry * t_dentry; + int err = 0, tmperr = 0; + enum rsbac_target_t target; + union rsbac_target_id_t tid; + rsbac_uid_t * k_trulist; + rsbac_time_t * k_ttllist; + + struct path path; + + if(!filename) + return -RSBAC_EINVALIDTARGET; + if(!trulist) + return -RSBAC_EINVALIDPOINTER; + if(maxnum <= 0) + return -RSBAC_EINVALIDVALUE; + if(maxnum > RSBAC_MAC_MAX_MAXNUM) + maxnum = RSBAC_MAC_MAX_MAXNUM; + + if ((err = user_lpath(filename, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_mac) + rsbac_printk(KERN_DEBUG "sys_rsbac_mac_get_f_trulist(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type file or dir? */ + if(S_ISREG(t_dentry->d_inode->i_mode)) + target = T_FILE; + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + target = T_DIR; + else + { /* This is no file or dir */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; + + err = rsbac_mac_get_f_trulist(ta_number, tid.file, &k_trulist, &k_ttllist); + if(err>0) + { + if(err > maxnum) + err = maxnum; + tmperr = rsbac_put_user(k_trulist, trulist, + sizeof(rsbac_uid_t) * err); + if(tmperr < 0) + err = tmperr; + else + { + if(ttllist) + { + tmperr = rsbac_put_user(k_ttllist, ttllist, + sizeof(rsbac_time_t) * err); + if(tmperr < 0) + err = tmperr; + } + } + rsbac_kfree(k_trulist); + rsbac_kfree(k_ttllist); + } + +out_dput: + path_put(&path); +out: + return err; + } + +int sys_rsbac_mac_get_p_trulist( + rsbac_list_ta_number_t ta_number, + rsbac_upid_t upid, + rsbac_uid_t __user trulist[], + rsbac_time_t __user ttllist[], + u_int maxnum) + { + int err = 0, tmperr = 0; + union rsbac_target_id_t tid; + rsbac_uid_t * k_trulist; + rsbac_time_t * k_ttllist; + + if(!upid) + return -RSBAC_EINVALIDTARGET; + if(!trulist) + return -RSBAC_EINVALIDPOINTER; + if(maxnum <= 0) + return -RSBAC_EINVALIDVALUE; + if(maxnum > RSBAC_MAC_MAX_MAXNUM) + maxnum = RSBAC_MAC_MAX_MAXNUM; + + tid.process = find_pid_ns(upid, &init_pid_ns); + if(!tid.process) + return -RSBAC_EINVALIDTARGET; + + err = rsbac_mac_get_p_trulist(ta_number, tid.process, &k_trulist, &k_ttllist); + if(err>0) + { + if(err > maxnum) + err = maxnum; + tmperr = rsbac_put_user(k_trulist, trulist, + sizeof(rsbac_uid_t) * err); + if(tmperr < 0) + err = tmperr; + else + { + if(ttllist) + { + tmperr = rsbac_put_user(k_ttllist, ttllist, + sizeof(rsbac_time_t) * err); + if(tmperr < 0) + err = tmperr; + } + } + rsbac_kfree(k_trulist); + rsbac_kfree(k_ttllist); + } + + return err; + } +#endif + +/************** DAZ ***************/ + +#ifdef CONFIG_RSBAC_DAZ +int sys_rsbac_daz_flush_cache(void) + { +#ifndef CONFIG_RSBAC_DAZ_CACHE + return 0; +#else + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + /* Security Officer or admin? */ + i_tid.user = __kuid_val(current_uid()); + if (rsbac_get_attr(SW_DAZ, + T_USER, + i_tid, + A_daz_role, + &i_attr_val1, + TRUE)) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_daz_flush_cache(): rsbac_get_attr() returned error!\n"); + return -EPERM; + } + /* if not sec_officer or admin, deny */ + if ( (i_attr_val1.system_role != SR_security_officer) + && (i_attr_val1.system_role != SR_administrator) + ) + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_DAZ] + #endif + ) + #endif + return -EPERM; + + rsbac_printk(KERN_INFO + "sys_rsbac_daz_flush_cache(): flushing DAZuko result cache!\n"); + + return rsbac_daz_flush_cache(); +#endif + } +#endif + +/************** RC ***************/ + +#ifdef CONFIG_RSBAC_RC +int sys_rsbac_rc_copy_role( + rsbac_list_ta_number_t ta_number, + rsbac_rc_role_id_t from_role, + rsbac_rc_role_id_t to_role) + { + if( (from_role > RC_role_max_value) + || (from_role > RC_role_max_value)) + return -RSBAC_EINVALIDVALUE; +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_rc) + rsbac_printk(KERN_DEBUG + "sys_rsbac_rc_copy_role(): from %i, to %i!\n", + from_role, to_role); +#endif +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_rc_copy_role(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + /* call rc function and return its result */ + return rsbac_rc_sys_copy_role(ta_number, from_role, to_role); + } + +int sys_rsbac_rc_copy_type( + rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + rsbac_rc_type_id_t from_type, + rsbac_rc_type_id_t to_type) + { + if( (from_type > RC_type_max_value) + || (from_type > RC_type_max_value)) + return -RSBAC_EINVALIDVALUE; +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_rc) + rsbac_printk(KERN_DEBUG + "sys_rsbac_rc_copy_type(): from %i, to %i!\n", + from_type, to_type); +#endif +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_rc_copy_type(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + /* call rc function and return its result */ + return rsbac_rc_sys_copy_type(ta_number, target, from_type, to_type); + } + +/* Getting values */ +int sys_rsbac_rc_get_item ( + rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t __user * tid_p, + union rsbac_rc_target_id_t __user * subtid_p, + enum rsbac_rc_item_t item, + union rsbac_rc_item_value_t __user * value_p, + rsbac_time_t __user * ttl_p) + { + union rsbac_rc_target_id_t k_tid; + union rsbac_rc_target_id_t k_subtid; + union rsbac_rc_item_value_t k_value; + rsbac_time_t k_ttl; + int err = 0; + + if( (target >= RT_NONE) + || (item >= RI_none)) + return -RSBAC_EINVALIDVALUE; + /* get values from user space */ + rsbac_get_user(&k_tid, tid_p, sizeof(k_tid) ); + rsbac_get_user(&k_subtid, subtid_p, sizeof(k_subtid) ); + rsbac_get_user(&k_value, value_p, sizeof(k_value) ); +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_rc) + rsbac_printk(KERN_DEBUG + "sys_rsbac_rc_get_item(): target %i, item %i!\n", + target, item); +#endif + /* call rc function and return its result */ + err = rsbac_rc_sys_get_item(ta_number, target, k_tid, k_subtid, + item, &k_value, &k_ttl); + /* put result value to user space */ + if(!err) + { + err = rsbac_put_user(&k_value, value_p, sizeof(k_value) ); + if(!err && ttl_p) + err = rsbac_put_user(&k_ttl, ttl_p, sizeof(k_ttl) ); + } + return err; + } + +/* Setting values */ +int sys_rsbac_rc_set_item( + rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t __user * tid_p, + union rsbac_rc_target_id_t __user * subtid_p, + enum rsbac_rc_item_t item, + union rsbac_rc_item_value_t __user * value_p, + rsbac_time_t ttl) + { + union rsbac_rc_target_id_t k_tid; + union rsbac_rc_target_id_t k_subtid; + union rsbac_rc_item_value_t k_value; + + if( (target >= RT_NONE) + || (item >= RI_none)) + return -RSBAC_EINVALIDVALUE; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_rc_set_item(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + /* get values from user space */ + rsbac_get_user(&k_tid, tid_p, sizeof(k_tid) ); + rsbac_get_user(&k_subtid, subtid_p, sizeof(k_subtid) ); + rsbac_get_user(&k_value, value_p, sizeof(k_value) ); +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_rc) + rsbac_printk(KERN_DEBUG + "sys_rsbac_rc_set_item(): target %i, item %i!\n", + target, item); +#endif + /* call rc function and return its result */ + return rsbac_rc_sys_set_item(ta_number, target, k_tid, k_subtid, item, k_value, ttl); + } + +int sys_rsbac_rc_get_list( + rsbac_list_ta_number_t ta_number, + enum rsbac_rc_target_t target, + union rsbac_rc_target_id_t __user * tid_p, + enum rsbac_rc_item_t item, + u_int maxnum, + __u32 __user * array_p, + rsbac_time_t __user * ttl_array_p) + { + union rsbac_rc_target_id_t k_tid; + int err; + + rsbac_get_user(&k_tid, tid_p, sizeof(k_tid)); + if(array_p) + { + __u32 * k_array_p; + rsbac_time_t * k_ttl_array_p; + + if(!maxnum) + return -RSBAC_EINVALIDVALUE; + /* call rc function and return its result */ + err = rsbac_rc_get_list(ta_number, target, k_tid, item, + &k_array_p, &k_ttl_array_p); + /* put result value to user space */ + if(err > 0) + { + int tmperr; + + if(err > maxnum) + err = maxnum; + tmperr = rsbac_put_user(k_array_p, array_p, err * sizeof(*k_array_p) ); + if(tmperr) + err = tmperr; + rsbac_kfree(k_array_p); + if(k_ttl_array_p && ttl_array_p) + { + tmperr = rsbac_put_user(k_ttl_array_p, ttl_array_p, err * sizeof(*k_ttl_array_p) ); + if(tmperr) + err = tmperr; + } + rsbac_kfree(k_ttl_array_p); + } + return err; + } + else + return rsbac_rc_get_list(ta_number, target, k_tid, item, NULL, NULL); + } + +/* Set own role */ +int sys_rsbac_rc_change_role (rsbac_rc_role_id_t role, char __user * pass) + { + if(role > RC_role_max_value) + return -RSBAC_EINVALIDVALUE; +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_rc) + rsbac_printk(KERN_DEBUG + "sys_rsbac_rc_change_role(): role %i!\n", + role); +#endif + /* call rc function and return its result */ + return rsbac_rc_sys_change_role(role, pass); + } + +/* Getting own effective rights */ +int sys_rsbac_rc_get_eff_rights_n( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + char __user * t_name, + rsbac_rc_request_vector_t __user * request_vector_p, + rsbac_time_t __user * ttl_p) + { + struct dentry * t_dentry; + int err = 0; + rsbac_rc_request_vector_t k_req_vec; + rsbac_time_t k_ttl; + union rsbac_target_id_t tid; + + struct path path; + + if(!t_name || (target >= T_NONE)) + return -RSBAC_EINVALIDTARGET; + + if ((err = user_lpath(t_name, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_rc) + rsbac_printk(KERN_DEBUG "sys_rsbac_rc_get_eff_rights_n(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + + switch (target) + { + case T_FD: + if(S_ISREG(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + { + target = T_DIR; + } + else + if(S_ISLNK(t_dentry->d_inode->i_mode)) + { + target = T_SYMLINK; + } + else + if(S_ISFIFO(t_dentry->d_inode->i_mode)) + { + target = T_FIFO; + } + else + if(S_ISSOCK(t_dentry->d_inode->i_mode)) + { + target = T_UNIXSOCK; + } + else + if(S_ISBLK(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISCHR(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_rc_get_eff_rights_n(): no filesystem object\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_FILE: + /* is inode of type file, symlink or block/char device? */ + if ( !(S_ISREG(t_dentry->d_inode->i_mode)) + && !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_DIR: + if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) ) + { /* This is no file */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_FIFO: + /* is inode of type fifo? */ + if ( !(S_ISFIFO(t_dentry->d_inode->i_mode))) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_UNIXSOCK: + /* is inode of type fifo? */ + if ( !(S_ISSOCK(t_dentry->d_inode->i_mode))) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_SYMLINK: + /* is inode of type symlink? */ + if ( !(S_ISLNK(t_dentry->d_inode->i_mode))) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + case T_DEV: + /* is inode of type block/char device? */ + if ( !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { /* This is no dev */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + + default: + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + + if(target == T_DEV) + { + if(S_ISBLK(t_dentry->d_inode->i_mode)) + tid.dev.type = D_block; + else + tid.dev.type = D_char; + tid.dev.major = RSBAC_MAJOR(t_dentry->d_inode->i_rdev); + tid.dev.minor = RSBAC_MINOR(t_dentry->d_inode->i_rdev); + } + else + { + /* fill target id and call internal function */ + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; + } + err = rsbac_rc_sys_get_eff_rights(ta_number, target, tid, &k_req_vec, &k_ttl); + /* put result value to user space */ + if(!err) + { + err = rsbac_put_user(&k_req_vec, request_vector_p, sizeof(k_req_vec) ); + if(!err && ttl_p) + err = rsbac_put_user(&k_ttl, ttl_p, sizeof(k_ttl) ); + } + + out_dput: + path_put(&path); + + out: + return err; + } + +/* Get current process role */ +int sys_rsbac_rc_get_current_role (rsbac_rc_role_id_t __user * role_p) + { + rsbac_rc_role_id_t k_role; + int err; + + if(!role_p) + return -RSBAC_EINVALIDPOINTER; + /* call rc function and return its result */ + err = rsbac_rc_sys_get_current_role(&k_role); + if(!err) + { + err = rsbac_put_user(&k_role, role_p, sizeof(k_role) ); + } + return err; + } + +int sys_rsbac_rc_select_fd_create_type(rsbac_rc_type_id_t type) +{ + int err; + + err = rsbac_rc_select_fd_create_type(type); + + return err; +} +#endif + +/************** AUTH ***************/ + +#ifdef CONFIG_RSBAC_AUTH +/* Provide means for adding and removing of capabilities */ +int sys_rsbac_auth_add_p_cap( + rsbac_list_ta_number_t ta_number, + rsbac_upid_t upid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range, + rsbac_time_t ttl) + { + rsbac_pid_t pid; + + if(cap_type >= ACT_none) + return -RSBAC_EINVALIDTARGET; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_range.first) == RSBAC_UM_VIRTUAL_KEEP) + cap_range.first = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(cap_range.first)); + else + if ( (RSBAC_UID_SET(cap_range.first) > RSBAC_UM_VIRTUAL_MAX) + && (RSBAC_UID_SET(cap_range.first) != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDVALUE; + if (RSBAC_UID_SET(cap_range.last) == RSBAC_UM_VIRTUAL_KEEP) + cap_range.last = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(cap_range.last)); + else + if ( (RSBAC_UID_SET(cap_range.last) > RSBAC_UM_VIRTUAL_MAX) + && (RSBAC_UID_SET(cap_range.last) != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDVALUE; +#else + cap_range.first = RSBAC_UID_NUM(cap_range.first); + cap_range.last = RSBAC_UID_NUM(cap_range.last); +#endif + + if(cap_range.first > cap_range.last) + return -RSBAC_EINVALIDVALUE; + if( (RSBAC_UID_NUM(cap_range.first) > RSBAC_AUTH_MAX_RANGE_UID) + || (RSBAC_UID_NUM(cap_range.last) > RSBAC_AUTH_MAX_RANGE_UID) + ) + return -RSBAC_EINVALIDVALUE; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_auth_add_p_cap(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + pid = find_pid_ns(upid, &init_pid_ns); + if(!pid) + return -RSBAC_EINVALIDTARGET; + + /* call auth function and return its result */ + /* permission checking is done there */ + return rsbac_auth_add_p_cap(ta_number, pid, cap_type, cap_range, ttl); + } + +int sys_rsbac_auth_remove_p_cap( + rsbac_list_ta_number_t ta_number, + rsbac_upid_t upid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range) + { + rsbac_pid_t pid; + + if(cap_type >= ACT_none) + return -RSBAC_EINVALIDTARGET; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_range.first) == RSBAC_UM_VIRTUAL_KEEP) + cap_range.first = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(cap_range.first)); + else + if ( (RSBAC_UID_SET(cap_range.first) > RSBAC_UM_VIRTUAL_MAX) + && (RSBAC_UID_SET(cap_range.first) != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDVALUE; + if (RSBAC_UID_SET(cap_range.last) == RSBAC_UM_VIRTUAL_KEEP) + cap_range.last = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(cap_range.last)); + else + if ( (RSBAC_UID_SET(cap_range.last) > RSBAC_UM_VIRTUAL_MAX) + && (RSBAC_UID_SET(cap_range.last) != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDVALUE; +#else + cap_range.first = RSBAC_UID_NUM(cap_range.first); + cap_range.last = RSBAC_UID_NUM(cap_range.last); +#endif + if(cap_range.first > cap_range.last) + return -RSBAC_EINVALIDVALUE; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_auth_remove_p_cap(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + pid = find_pid_ns(upid, &init_pid_ns); + if(!pid) + return -RSBAC_EINVALIDTARGET; + /* call auth function and return its result */ + /* permission checking is done there */ + return rsbac_auth_remove_p_cap(ta_number, pid, cap_type, cap_range); + } + +int sys_rsbac_auth_add_f_cap( + rsbac_list_ta_number_t ta_number, + char __user * filename, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range, + rsbac_time_t ttl) + { + struct dentry * t_dentry; + int err = 0; + enum rsbac_target_t target; + union rsbac_target_id_t tid; +#if defined(CONFIG_RSBAC_AUTH) + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + + struct path path; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_range.first) == RSBAC_UM_VIRTUAL_KEEP) + cap_range.first = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(cap_range.first)); + else + if ( (RSBAC_UID_SET(cap_range.first) > RSBAC_UM_VIRTUAL_MAX) + && (RSBAC_UID_SET(cap_range.first) != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDVALUE; + if (RSBAC_UID_SET(cap_range.last) == RSBAC_UM_VIRTUAL_KEEP) + cap_range.last = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(cap_range.last)); + else + if ( (RSBAC_UID_SET(cap_range.last) > RSBAC_UM_VIRTUAL_MAX) + && (RSBAC_UID_SET(cap_range.last) != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDVALUE; +#else + cap_range.first = RSBAC_UID_NUM(cap_range.first); + cap_range.last = RSBAC_UID_NUM(cap_range.last); +#endif + if(cap_range.first > cap_range.last) + return -RSBAC_EINVALIDVALUE; + + if(!filename) + return -RSBAC_EINVALIDTARGET; + if(cap_type >= ACT_none) + return -RSBAC_EINVALIDTARGET; + if(cap_range.first > cap_range.last) + return -RSBAC_EINVALIDVALUE; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_auth_add_f_cap(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + if ((err = user_lpath(filename, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_auth) + rsbac_printk(KERN_DEBUG "sys_rsbac_auth_add_f_cap(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type file? */ + if(S_ISREG(t_dentry->d_inode->i_mode)) + target = T_FILE; + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + target = T_DIR; + else + { /* This is no file or dir */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; +#if defined(CONFIG_RSBAC_AUTH) + /* call ADF */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_auth_add_f_cap(): calling ADF\n"); +#endif + rsbac_attribute_value.auth_cap_range = cap_range; + if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE, + task_pid(current), + target, + tid, + A_auth_add_f_cap, + rsbac_attribute_value)) + { + err = -EPERM; + } + else +#endif + err = rsbac_auth_add_f_cap(ta_number, tid.file, cap_type, cap_range, ttl); + +out_dput: + path_put(&path); +out: + return err; + } + +int sys_rsbac_auth_remove_f_cap( + rsbac_list_ta_number_t ta_number, + char __user * filename, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t cap_range) + { + struct dentry * t_dentry; + int err = 0; + enum rsbac_target_t target; + union rsbac_target_id_t tid; + + /* for adf_request */ +#if defined(CONFIG_RSBAC_AUTH) + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + + struct path path; + + if(!filename) + return -RSBAC_EINVALIDTARGET; + if(cap_type >= ACT_none) + return -RSBAC_EINVALIDTARGET; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(cap_range.first) == RSBAC_UM_VIRTUAL_KEEP) + cap_range.first = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(cap_range.first)); + else + if ( (RSBAC_UID_SET(cap_range.first) > RSBAC_UM_VIRTUAL_MAX) + && (RSBAC_UID_SET(cap_range.first) != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDVALUE; + if (RSBAC_UID_SET(cap_range.last) == RSBAC_UM_VIRTUAL_KEEP) + cap_range.last = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(cap_range.last)); + else + if ( (RSBAC_UID_SET(cap_range.last) > RSBAC_UM_VIRTUAL_MAX) + && (RSBAC_UID_SET(cap_range.last) != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDVALUE; +#else + cap_range.first = RSBAC_UID_NUM(cap_range.first); + cap_range.last = RSBAC_UID_NUM(cap_range.last); +#endif + if(cap_range.first > cap_range.last) + return -RSBAC_EINVALIDVALUE; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_auth_remove_f_cap(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + if ((err = user_lpath(filename, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_auth) + rsbac_printk(KERN_DEBUG "sys_rsbac_auth_remove_f_cap(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type file or dir? */ + if(S_ISREG(t_dentry->d_inode->i_mode)) + target = T_FILE; + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + target = T_DIR; + else + { /* This is no file or dir */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; +#if defined(CONFIG_RSBAC_AUTH) + /* call ADF */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) rsbac_printk(KERN_DEBUG "sys_rsbac_auth_add_f_cap(): calling ADF\n"); +#endif + rsbac_attribute_value.auth_cap_range = cap_range; + if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE, + task_pid(current), + target, + tid, + A_auth_remove_f_cap, + rsbac_attribute_value)) + { + err = -EPERM; + } + else +#endif + err = rsbac_auth_remove_f_cap(ta_number, tid.file, cap_type, cap_range); + +out_dput: + path_put(&path); +out: + return err; + } + +/* caplist must have space for maxnum auth_cap_range entries - first and last each! */ +int sys_rsbac_auth_get_f_caplist( + rsbac_list_ta_number_t ta_number, + char __user * filename, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t __user caplist[], + rsbac_time_t __user ttllist[], + u_int maxnum) + { + struct dentry * t_dentry; + int err = 0, tmperr = 0; + enum rsbac_target_t target; + union rsbac_target_id_t tid; + struct rsbac_auth_cap_range_t * k_caplist; + rsbac_time_t * k_ttllist; + + /* for adf_request */ +#if defined(CONFIG_RSBAC_AUTH) + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + + struct path path; + + if(!filename) + return -RSBAC_EINVALIDTARGET; + if(cap_type >= ACT_none) + return -RSBAC_EINVALIDTARGET; + if(!caplist) + return -RSBAC_EINVALIDPOINTER; + if(maxnum <= 0) + return -RSBAC_EINVALIDVALUE; + if(maxnum > RSBAC_AUTH_MAX_MAXNUM) + maxnum = RSBAC_AUTH_MAX_MAXNUM; + + if ((err = user_lpath(filename, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_auth) + rsbac_printk(KERN_DEBUG "sys_rsbac_auth_get_f_caplist(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type file or dir? */ + if(S_ISREG(t_dentry->d_inode->i_mode)) + target = T_FILE; + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + target = T_DIR; + else + { /* This is no file or dir */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; +#if defined(CONFIG_RSBAC_AUTH) + /* call ADF */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) rsbac_printk(KERN_DEBUG "sys_rsbac_auth_get_f_caplist(): calling ADF\n"); +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_READ_ATTRIBUTE, + task_pid(current), + target, + tid, + A_auth_get_caplist, + rsbac_attribute_value)) + { + err = -EPERM; + goto out_dput; + } +#endif + err = rsbac_auth_get_f_caplist(ta_number, tid.file, cap_type, &k_caplist, &k_ttllist); + if(err>0) + { + if(err > maxnum) + err = maxnum; + tmperr = rsbac_put_user(k_caplist, caplist, + sizeof(struct rsbac_auth_cap_range_t) * err); + if(tmperr < 0) + err = tmperr; + else + { + if(ttllist) + { + tmperr = rsbac_put_user(k_ttllist, ttllist, + sizeof(rsbac_time_t) * err); + if(tmperr < 0) + err = tmperr; + } + } + rsbac_kfree(k_caplist); + rsbac_kfree(k_ttllist); + } + +out_dput: + path_put(&path); +out: + return err; + } + +int sys_rsbac_auth_get_p_caplist( + rsbac_list_ta_number_t ta_number, + rsbac_upid_t upid, + enum rsbac_auth_cap_type_t cap_type, + struct rsbac_auth_cap_range_t __user caplist[], + rsbac_time_t __user ttllist[], + u_int maxnum) + { + int err = 0, tmperr = 0; + union rsbac_target_id_t tid; + struct rsbac_auth_cap_range_t * k_caplist; + rsbac_time_t * k_ttllist; + + /* for adf_request */ +#if defined(CONFIG_RSBAC_AUTH) + union rsbac_attribute_value_t rsbac_attribute_value; +#endif + + if(!upid) + return -RSBAC_EINVALIDTARGET; + if(cap_type >= ACT_none) + return -RSBAC_EINVALIDVALUE; + if(!caplist) + return -RSBAC_EINVALIDPOINTER; + if(maxnum <= 0) + return -RSBAC_EINVALIDVALUE; + if(maxnum > RSBAC_AUTH_MAX_MAXNUM) + maxnum = RSBAC_AUTH_MAX_MAXNUM; + + tid.process = find_pid_ns(upid, &init_pid_ns); + if (!tid.process) + return -RSBAC_EINVALIDTARGET; +#if defined(CONFIG_RSBAC_AUTH) + /* call ADF */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) rsbac_printk(KERN_DEBUG "sys_rsbac_auth_get_p_caplist(): calling ADF\n"); +#endif + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_READ_ATTRIBUTE, + task_pid(current), + T_PROCESS, + tid, + A_auth_get_caplist, + rsbac_attribute_value)) + { + return -EPERM; + } +#endif + err = rsbac_auth_get_p_caplist(ta_number, tid.process, cap_type, + &k_caplist, &k_ttllist); + if(err>0) + { + if(err > maxnum) + err = maxnum; + tmperr = rsbac_put_user(k_caplist, caplist, + sizeof(struct rsbac_auth_cap_range_t) * err); + if(tmperr < 0) + err = tmperr; + else + { + if(ttllist) + { + tmperr = rsbac_put_user(k_ttllist, ttllist, + sizeof(rsbac_time_t) * err); + if(tmperr < 0) + err = tmperr; + } + } + rsbac_kfree(k_caplist); + rsbac_kfree(k_ttllist); + } + + return err; + } +#endif + +/**********************************/ +/************** REG ***************/ + +#ifdef CONFIG_RSBAC_REG +int sys_rsbac_reg(rsbac_reg_handle_t handle, + void __user * arg) + { + return rsbac_reg_syscall(handle, arg); + } +#endif + +/**********************************/ +/************** ACL ***************/ + +#ifdef CONFIG_RSBAC_ACL +int sys_rsbac_acl( + rsbac_list_ta_number_t ta_number, + enum rsbac_acl_syscall_type_t call, + struct rsbac_acl_syscall_arg_t __user * arg) + { + struct rsbac_acl_syscall_arg_t k_arg; + int err = 0; + + if(call >= ACLC_none) + return -RSBAC_EINVALIDREQUEST; + if(!arg) + return -RSBAC_EINVALIDPOINTER; + + /* get values from user space */ + err = rsbac_get_user(&k_arg, arg, sizeof(k_arg)); + if(err < 0) + return err; + + if(k_arg.target >= T_NONE) + return -RSBAC_EINVALIDTARGET; +/* rsbac_printk(KERN_DEBUG "sys_rsbac_acl(): target = %u, call = %u, subj_type = %u, subj_id = %u!\n", + k_arg.target, call, k_arg.subj_type, k_arg.subj_id); */ + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_acl(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + if(call != ACLC_set_mask) + { + switch(k_arg.subj_type) + { + case ACLS_USER: +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(k_arg.subj_id) == RSBAC_UM_VIRTUAL_KEEP) + k_arg.subj_id = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(k_arg.subj_id)); + else + if (RSBAC_UID_SET(k_arg.subj_id) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + k_arg.subj_id = RSBAC_UID_NUM(k_arg.subj_id); +#endif + break; + case ACLS_GROUP: + if(k_arg.subj_id != RSBAC_ACL_GROUP_EVERYONE) + { + struct rsbac_acl_group_entry_t entry; + rsbac_uid_t caller; + + if( rsbac_acl_get_group_entry(ta_number, k_arg.subj_id, &entry) + || rsbac_get_owner(&caller) + || ( (entry.owner != caller) + && (entry.type != ACLG_GLOBAL) + ) + ) + return -RSBAC_EINVALIDVALUE; + } + break; + #if defined(CONFIG_RSBAC_RC) + case ACLS_ROLE: + if(k_arg.subj_id > RC_role_max_value) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_acl(): Invalid role %u!\n", k_arg.subj_id); + return -RSBAC_EINVALIDVALUE; + } + break; + #endif + default: + rsbac_printk(KERN_DEBUG "sys_rsbac_acl(): Invalid subject type %u!\n", k_arg.subj_type); + return -RSBAC_EINVALIDVALUE; + } + if( (call == ACLC_remove_user) + && (k_arg.target != T_USER) + ) + return -RSBAC_EINVALIDTARGET; + + } + + /* call acl function */ + switch(call) + { + case ACLC_set_acl_entry: + err = rsbac_acl_sys_set_acl_entry(ta_number, + k_arg.target, + k_arg.tid, + k_arg.subj_type, + k_arg.subj_id, + k_arg.rights, + k_arg.ttl); + break; + case ACLC_remove_acl_entry: + err = rsbac_acl_sys_remove_acl_entry(ta_number, + k_arg.target, + k_arg.tid, + k_arg.subj_type, + k_arg.subj_id); + break; + case ACLC_remove_acl: + err = rsbac_acl_sys_remove_acl(ta_number, + k_arg.target, + k_arg.tid); + break; + case ACLC_add_to_acl_entry: + err = rsbac_acl_sys_add_to_acl_entry(ta_number, + k_arg.target, + k_arg.tid, + k_arg.subj_type, + k_arg.subj_id, + k_arg.rights, + k_arg.ttl); + break; + case ACLC_remove_from_acl_entry: + err = rsbac_acl_sys_remove_from_acl_entry(ta_number, + k_arg.target, + k_arg.tid, + k_arg.subj_type, + k_arg.subj_id, + k_arg.rights); + break; + case ACLC_set_mask: + err = rsbac_acl_sys_set_mask(ta_number, + k_arg.target, + k_arg.tid, + k_arg.rights); + break; + case ACLC_remove_user: + err = rsbac_acl_sys_remove_user(ta_number, + k_arg.tid.user); + break; + + default: + err = -RSBAC_EINVALIDREQUEST; + } + return err; + } /* end of sys_rsbac_acl() */ + + +int sys_rsbac_acl_n( + rsbac_list_ta_number_t ta_number, + enum rsbac_acl_syscall_type_t call, + struct rsbac_acl_syscall_n_arg_t __user * arg) + { + struct dentry * t_dentry = NULL; + int err = 0; + union rsbac_target_id_t tid; + struct rsbac_acl_syscall_n_arg_t k_arg; + + struct path path; + + if(call >= ACLC_none) + return -RSBAC_EINVALIDREQUEST; + if(!arg) + return -RSBAC_EINVALIDPOINTER; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_acl_n(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + /* get values from user space */ +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) + if((current->thread.status & TS_COMPAT) || test_thread_flag(TIF_IA32)) { + struct rsbac_acl_syscall_n_arg_ia32_t k_arg_ia32; + + err = rsbac_get_user(&k_arg_ia32, arg, sizeof(k_arg_ia32) ); + if(err < 0) + return err; + memset(&k_arg, 0, sizeof(k_arg)); + k_arg.target = k_arg_ia32.target; + k_arg.name = (void __user *)(long)k_arg_ia32.name; + k_arg.subj_type = k_arg_ia32.subj_type; + k_arg.subj_id = k_arg_ia32.subj_id; + k_arg.rights = k_arg_ia32.rights; + k_arg.ttl = k_arg_ia32.ttl; + } else { +#endif + err = rsbac_get_user(&k_arg, arg, sizeof(k_arg) ); + if(err < 0) + return err; +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) + } +#endif + + if(k_arg.target >= T_NONE) + return -RSBAC_EINVALIDTARGET; + if(call != ACLC_set_mask) + { + switch(k_arg.subj_type) + { + case ACLS_USER: +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(k_arg.subj_id) == RSBAC_UM_VIRTUAL_KEEP) + k_arg.subj_id = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(k_arg.subj_id)); + else + if (RSBAC_UID_SET(k_arg.subj_id) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + k_arg.subj_id = RSBAC_UID_NUM(k_arg.subj_id); +#endif + break; + case ACLS_GROUP: + if(k_arg.subj_id != RSBAC_ACL_GROUP_EVERYONE) + { + struct rsbac_acl_group_entry_t entry; + rsbac_uid_t caller; + + if( rsbac_acl_get_group_entry(ta_number, k_arg.subj_id, &entry) + || rsbac_get_owner(&caller) + || ( (entry.owner != caller) + && (entry.type != ACLG_GLOBAL) + ) + ) + return -RSBAC_EINVALIDVALUE; + } + break; + #if defined(CONFIG_RSBAC_RC) + case ACLS_ROLE: + if(k_arg.subj_id > RC_role_max_value) + return -RSBAC_EINVALIDVALUE; + break; + #endif + default: + return -RSBAC_EINVALIDVALUE; + } + } + + if(k_arg.name) + { + /* lookup filename */ + if ((err = user_lpath(k_arg.name, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_acl_n(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + if (!t_dentry->d_inode) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_acl_n(): file not found\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; + } + else + { + tid.file.device = RSBAC_ZERO_DEV; + tid.file.inode = 0; + tid.file.dentry_p = NULL; + } + + switch (k_arg.target) + { + case T_FD: + if(k_arg.name) + { + if(S_ISREG(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_FILE; + } + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_DIR; + } + else + if(S_ISLNK(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_SYMLINK; + } + else + if(S_ISFIFO(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_FIFO; + } + else + if(S_ISSOCK(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_UNIXSOCK; + } + else + if(S_ISBLK(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_FILE; + } + else + if(S_ISCHR(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_FILE; + } + else + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_acl_n(): no filesystem object\n"); +#endif + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + } + else + k_arg.target = T_FILE; + break; + + case T_FILE: + if(k_arg.name) + { + /* is inode of type file, symlink or block/char device? */ + if ( !(S_ISREG(t_dentry->d_inode->i_mode)) + && !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + } + break; + + case T_DIR: + if(k_arg.name) + { + if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) ) + { /* This is no dir */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + } + break; + + case T_FIFO: + if(k_arg.name) + { + /* is inode of type fifo? */ + if ( !(S_ISFIFO(t_dentry->d_inode->i_mode))) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + } + break; + + case T_UNIXSOCK: + if(k_arg.name) + { + /* is inode of type fifo? */ + if ( !(S_ISSOCK(t_dentry->d_inode->i_mode))) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + } + break; + + case T_SYMLINK: + if(k_arg.name) + { + /* is inode of type symlink? */ + if ( !(S_ISLNK(t_dentry->d_inode->i_mode))) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + } + break; + + case T_DEV: + if(k_arg.name) + { + /* is inode of type block/char device? */ + if ( !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* fill target id and call internal function */ + if(S_ISBLK(t_dentry->d_inode->i_mode)) + tid.dev.type = D_block; + else + tid.dev.type = D_char; + tid.dev.major = RSBAC_MAJOR(t_dentry->d_inode->i_rdev); + tid.dev.minor = RSBAC_MINOR(t_dentry->d_inode->i_rdev); + } + else + { + tid.dev = RSBAC_ZERO_DEV_DESC; + } + break; + + default: + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* call acl function */ + switch(call) + { + case ACLC_set_acl_entry: + err = rsbac_acl_sys_set_acl_entry(ta_number, + k_arg.target, + tid, + k_arg.subj_type, + k_arg.subj_id, + k_arg.rights, + k_arg.ttl); + break; + case ACLC_remove_acl_entry: + err = rsbac_acl_sys_remove_acl_entry(ta_number, + k_arg.target, + tid, + k_arg.subj_type, + k_arg.subj_id); + break; + case ACLC_remove_acl: + err = rsbac_acl_sys_remove_acl(ta_number, + k_arg.target, + tid); + break; + case ACLC_add_to_acl_entry: + err = rsbac_acl_sys_add_to_acl_entry(ta_number, + k_arg.target, + tid, + k_arg.subj_type, + k_arg.subj_id, + k_arg.rights, + k_arg.ttl); + break; + case ACLC_remove_from_acl_entry: + err = rsbac_acl_sys_remove_from_acl_entry(ta_number, + k_arg.target, + tid, + k_arg.subj_type, + k_arg.subj_id, + k_arg.rights); + break; + case ACLC_set_mask: + err = rsbac_acl_sys_set_mask(ta_number, + k_arg.target, + tid, + k_arg.rights); + break; + + default: + err = -RSBAC_EINVALIDREQUEST; + } + +out_dput: + if(k_arg.name) + { + path_put(&path); + } + +out: + return err; + } /* end of sys_rsbac_acl_n() */ + +/************************************************************************** */ + +int sys_rsbac_acl_get_rights( + rsbac_list_ta_number_t ta_number, + struct rsbac_acl_syscall_arg_t __user * arg, + rsbac_acl_rights_vector_t __user * rights_p, + u_int effective) + { + struct rsbac_acl_syscall_arg_t k_arg; + rsbac_acl_rights_vector_t k_rights = 0; + int err = 0; + + if(!arg || !rights_p) + return -RSBAC_EINVALIDPOINTER; + /* get values from user space */ + rsbac_get_user(&k_arg, arg, sizeof(k_arg) ); + + if(k_arg.target >= T_NONE) + return -RSBAC_EINVALIDTARGET; +/* printk(KERN_DEBUG "sys_rsbac_acl_get_rights(): target = %u, subj_type = %u, subj_id = %u!\n", + k_arg.target, k_arg.subj_type, k_arg.subj_id); */ + switch(k_arg.subj_type) + { + case ACLS_USER: +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(k_arg.subj_id) == RSBAC_UM_VIRTUAL_KEEP) + k_arg.subj_id = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(k_arg.subj_id)); + else + if (RSBAC_UID_SET(k_arg.subj_id) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + k_arg.subj_id = RSBAC_UID_NUM(k_arg.subj_id); +#endif + break; + case ACLS_GROUP: + if(k_arg.subj_id != RSBAC_ACL_GROUP_EVERYONE) + { + struct rsbac_acl_group_entry_t entry; + rsbac_uid_t caller; + + if( rsbac_acl_get_group_entry(ta_number, k_arg.subj_id, &entry) + || rsbac_get_owner(&caller) + || ( (entry.owner != caller) + && (entry.type != ACLG_GLOBAL) + ) + ) + return -RSBAC_EINVALIDVALUE; + } + break; + case ACLS_ROLE: + #if defined(CONFIG_RSBAC_RC) + if(k_arg.subj_id > RC_role_max_value) + return -RSBAC_EINVALIDVALUE; + #endif + break; + default: + rsbac_printk(KERN_DEBUG "sys_rsbac_acl_get_rights(): Invalid subject type %u!\n", k_arg.subj_type); + return -RSBAC_EINVALIDVALUE; + } + + /* call acl function */ + err = rsbac_acl_sys_get_rights(ta_number, + k_arg.target, + k_arg.tid, + k_arg.subj_type, + k_arg.subj_id, + &k_rights, + effective); + if(!err) + { + err = rsbac_put_user(&k_rights, rights_p, sizeof(k_rights) ); + } + return err; + } /* end of sys_rsbac_acl_get_rights() */ + + +int sys_rsbac_acl_get_rights_n( + rsbac_list_ta_number_t ta_number, + struct rsbac_acl_syscall_n_arg_t __user * arg, + rsbac_acl_rights_vector_t __user * rights_p, + u_int effective) + { + struct dentry * t_dentry = NULL; + rsbac_boolean_t need_put = FALSE; + int err = 0; + union rsbac_target_id_t tid; + struct rsbac_acl_syscall_n_arg_t k_arg; + rsbac_acl_rights_vector_t k_rights = 0; + + struct path path; + + if(!arg || !rights_p) + return -RSBAC_EINVALIDPOINTER; + /* get values from user space */ + rsbac_get_user(&k_arg, arg, sizeof(k_arg) ); + + if(k_arg.target >= T_NONE) + return -RSBAC_EINVALIDTARGET; + switch(k_arg.subj_type) + { + case ACLS_USER: +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(k_arg.subj_id) == RSBAC_UM_VIRTUAL_KEEP) + k_arg.subj_id = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(k_arg.subj_id)); + else + if (RSBAC_UID_SET(k_arg.subj_id) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + k_arg.subj_id = RSBAC_UID_NUM(k_arg.subj_id); +#endif + break; + case ACLS_GROUP: + if(k_arg.subj_id != RSBAC_ACL_GROUP_EVERYONE) + { + struct rsbac_acl_group_entry_t entry; + rsbac_uid_t caller; + + if( rsbac_acl_get_group_entry(ta_number, k_arg.subj_id, &entry) + || rsbac_get_owner(&caller) + || ( (entry.owner != caller) + && (entry.type != ACLG_GLOBAL) + ) + ) + return -RSBAC_EINVALIDVALUE; + } + break; + case ACLS_ROLE: + #if defined(CONFIG_RSBAC_RC) + if(k_arg.subj_id > RC_role_max_value) + return -RSBAC_EINVALIDVALUE; + #endif + break; + default: + return -RSBAC_EINVALIDVALUE; + } + + switch (k_arg.target) + { + case T_FD: + case T_FILE: + case T_DIR: + case T_FIFO: + case T_UNIXSOCK: + case T_SYMLINK: + if(k_arg.name) + { + if ((err = user_lpath(k_arg.name, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_acl) + rsbac_printk(KERN_DEBUG "sys_rsbac_acl_get_rights_n(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + need_put = TRUE; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type file, symlink or block/char device? */ + switch(k_arg.target) + { + case T_FD: + if(S_ISREG(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_FILE; + } + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_DIR; + } + else + if(S_ISLNK(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_SYMLINK; + } + else + if(S_ISFIFO(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_FIFO; + } + else + if(S_ISSOCK(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_UNIXSOCK; + } + else + if(S_ISBLK(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_FILE; + } + else + if(S_ISCHR(t_dentry->d_inode->i_mode)) + { + k_arg.target = T_FILE; + } + else + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_FILE: + if ( !(S_ISREG(t_dentry->d_inode->i_mode)) + && !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_DIR: + if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) ) + { /* This is no dir */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_FIFO: + /* is inode of type fifo? */ + if ( !(S_ISFIFO(t_dentry->d_inode->i_mode))) + { /* This is no fifo */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_UNIXSOCK: + if ( !(S_ISSOCK(t_dentry->d_inode->i_mode))) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_SYMLINK: + /* is inode of type symlink? */ + if ( !(S_ISLNK(t_dentry->d_inode->i_mode))) + { /* This is no symlink */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + default: + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; + } + else + { + if(k_arg.target == T_FD) + k_arg.target = T_FILE; + tid.file.device = RSBAC_ZERO_DEV; + tid.file.inode = 0; + tid.file.dentry_p = NULL; + } + break; + + case T_DEV: + if(k_arg.name) + { + if ((err = user_lpath(k_arg.name, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_acl) + rsbac_printk(KERN_DEBUG "sys_rsbac_acl_get_rights_n(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + need_put = TRUE; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type file, symlink or block/char device? */ + if ( !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* fill target id and call internal function */ + if(S_ISBLK(t_dentry->d_inode->i_mode)) + tid.dev.type = D_block; + else + tid.dev.type = D_char; + tid.dev.major = RSBAC_MAJOR(t_dentry->d_inode->i_rdev); + tid.dev.minor = RSBAC_MINOR(t_dentry->d_inode->i_rdev); + } + else + { + tid.dev = RSBAC_ZERO_DEV_DESC; + } + break; + + default: + return -RSBAC_EINVALIDTARGET; + } + + /* call acl function */ + err = rsbac_acl_sys_get_rights(ta_number, + k_arg.target, + tid, + k_arg.subj_type, + k_arg.subj_id, + &k_rights, + effective); + +out_dput: + if(need_put) + path_put(&path); +out: + if(!err) + { + rsbac_put_user(&k_rights, rights_p, sizeof(k_rights) ); + } + return err; + } /* end of sys_rsbac_acl_get_rights_n() */ + +/************************************************************************** */ + +int sys_rsbac_acl_get_tlist ( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t __user * tid, + struct rsbac_acl_entry_t __user entry_array[], + rsbac_time_t __user ttl_array[], + u_int maxnum) + { + union rsbac_target_id_t k_tid; + struct rsbac_acl_entry_t * k_entry_p; + rsbac_time_t * k_ttl_p; + int err = 0; + + if(!tid || (target >= T_NONE)) + return -RSBAC_EINVALIDTARGET; + if(!entry_array) + return -RSBAC_EINVALIDPOINTER; + if(!maxnum) + return -RSBAC_EINVALIDVALUE; + if(maxnum > RSBAC_ACL_MAX_MAXNUM) + maxnum = RSBAC_ACL_MAX_MAXNUM; + + /* get values from user space */ + err = rsbac_get_user(&k_tid, tid, sizeof(k_tid) ); + if(unlikely(err < 0)) + return err; + switch (target) { + case T_FD: + return -RSBAC_EINVALIDTARGET; + case T_FILE: + case T_DIR: + case T_FIFO: + case T_UNIXSOCK: + case T_SYMLINK: + k_tid.file.dentry_p = NULL; + k_tid.dir.dentry_p = NULL; + break; + case T_PROCESS: + k_tid.process = find_pid_ns(k_tid.uprocess, &init_pid_ns); + if(!k_tid.process) + return -RSBAC_EINVALIDTARGET; + break; + default: + break; + } + + /* call acl function */ + err = rsbac_acl_sys_get_tlist(ta_number, target, k_tid, &k_entry_p, &k_ttl_p); + if(err>0) + { + if(err > maxnum) + err = maxnum; + rsbac_put_user(k_entry_p, + entry_array, + err * sizeof(*k_entry_p) ); + if(ttl_array) + { + rsbac_put_user(k_ttl_p, + ttl_array, + err * sizeof(*k_ttl_p) ); + } + rsbac_kfree(k_entry_p); + rsbac_kfree(k_ttl_p); + } + return err; + } /* end of sys_rsbac_acl_get_tlist() */ + +int sys_rsbac_acl_get_tlist_n( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + char __user * t_name, + struct rsbac_acl_entry_t __user entry_array[], + rsbac_time_t __user ttl_array[], + u_int maxnum) + { + struct dentry * t_dentry = NULL; + struct rsbac_acl_entry_t * k_entry_p; + rsbac_time_t * k_ttl_p; + rsbac_boolean_t need_put = FALSE; + int err = 0; + union rsbac_target_id_t tid; + + struct path path; + + if(target >= T_NONE) + return -RSBAC_EINVALIDTARGET; + if(!entry_array) + return -RSBAC_EINVALIDPOINTER; + + switch (target) + { + case T_FD: + case T_FILE: + case T_DIR: + case T_FIFO: + case T_UNIXSOCK: + case T_SYMLINK: + if(t_name) + { + if ((err = user_lpath(t_name, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_acl) + rsbac_printk(KERN_DEBUG "sys_rsbac_acl_get_tlist_n(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + need_put = TRUE; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type file, symlink or block/char device? */ + switch(target) + { + case T_FD: + if(S_ISREG(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + { + target = T_DIR; + } + else + if(S_ISLNK(t_dentry->d_inode->i_mode)) + { + target = T_SYMLINK; + } + else + if(S_ISFIFO(t_dentry->d_inode->i_mode)) + { + target = T_FIFO; + } + else + if(S_ISSOCK(t_dentry->d_inode->i_mode)) + { + target = T_UNIXSOCK; + } + else + if(S_ISBLK(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISCHR(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_FILE: + if ( !(S_ISREG(t_dentry->d_inode->i_mode)) + && !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_DIR: + if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) ) + { /* This is no dir */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_FIFO: + /* is inode of type fifo? */ + if ( !(S_ISFIFO(t_dentry->d_inode->i_mode))) + { /* This is no fifo */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_UNIXSOCK: + if ( !(S_ISSOCK(t_dentry->d_inode->i_mode))) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_SYMLINK: + /* is inode of type symlink? */ + if ( !(S_ISLNK(t_dentry->d_inode->i_mode))) + { /* This is no symlink */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + default: + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; + } + else + { + if(target == T_FD) + target = T_FILE; + tid.file.device = RSBAC_ZERO_DEV; + tid.file.inode = 0; + tid.file.dentry_p = NULL; + } + break; + + case T_DEV: + if(t_name) + { + if ((err = user_lpath(t_name, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_acl) + rsbac_printk(KERN_DEBUG "sys_rsbac_acl_get_tlist_n(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + need_put = TRUE; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type file, symlink or block/char device? */ + if ( !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* fill target id and call internal function */ + if(S_ISBLK(t_dentry->d_inode->i_mode)) + tid.dev.type = D_block; + else + tid.dev.type = D_char; + tid.dev.major = RSBAC_MAJOR(t_dentry->d_inode->i_rdev); + tid.dev.minor = RSBAC_MINOR(t_dentry->d_inode->i_rdev); + } + else + { + tid.dev = RSBAC_ZERO_DEV_DESC; + } + break; + + default: + return -RSBAC_EINVALIDTARGET; + } + /* call ACL function */ + err = rsbac_acl_sys_get_tlist(ta_number, target, tid, + &k_entry_p, &k_ttl_p); + +out_dput: + if(need_put) + path_put(&path); +out: + if(err>0) + { + if(err > maxnum) + err = maxnum; + rsbac_put_user(k_entry_p, + entry_array, + err * sizeof(*k_entry_p) ); + if(ttl_array) + { + rsbac_put_user(k_ttl_p, + ttl_array, + err * sizeof(*k_ttl_p) ); + } + rsbac_kfree(k_entry_p); + rsbac_kfree(k_ttl_p); + } + return err; + } /* end of sys_rsbac_acl_get_tlist_n() */ + +/************************************************************************** */ + +int sys_rsbac_acl_get_mask ( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + union rsbac_target_id_t __user * tid, + rsbac_acl_rights_vector_t __user * mask_p) + { + union rsbac_target_id_t k_tid; + rsbac_acl_rights_vector_t k_mask; + int err = 0; + + if(!tid || (target >= T_NONE)) + return -RSBAC_EINVALIDTARGET; + if(!mask_p) + return -RSBAC_EINVALIDPOINTER; + + /* get values from user space */ + rsbac_get_user(&k_tid, tid, sizeof(k_tid) ); + switch (target) { + case T_FD: + return -RSBAC_EINVALIDTARGET; + case T_FILE: + case T_DIR: + case T_FIFO: + case T_UNIXSOCK: + case T_SYMLINK: + k_tid.file.dentry_p = NULL; + k_tid.dir.dentry_p = NULL; + break; + case T_PROCESS: + k_tid.process = find_pid_ns(k_tid.uprocess, &init_pid_ns); + if(!k_tid.process) + return -RSBAC_EINVALIDTARGET; + break; + default: + break; + } + /* call acl function */ + err = rsbac_acl_sys_get_mask(ta_number, target, k_tid, &k_mask); + if(!err) + { + rsbac_put_user(&k_mask, + mask_p, + sizeof(k_mask) ); + } + return err; + } /* end of sys_rsbac_acl_get_mask() */ + +int sys_rsbac_acl_get_mask_n( + rsbac_list_ta_number_t ta_number, + enum rsbac_target_t target, + char __user * t_name, + rsbac_acl_rights_vector_t __user * mask_p) + { + struct dentry * t_dentry = NULL; + rsbac_acl_rights_vector_t k_mask; + rsbac_boolean_t need_put = FALSE; + int err = 0; + union rsbac_target_id_t tid; + + struct path path; + + if(target >= T_NONE) + return -RSBAC_EINVALIDTARGET; + if(!mask_p) + return -RSBAC_EINVALIDPOINTER; + + switch (target) + { + case T_FD: + case T_FILE: + case T_DIR: + case T_FIFO: + case T_UNIXSOCK: + case T_SYMLINK: + if(t_name) + { + if ((err = user_lpath(t_name, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_acl) + rsbac_printk(KERN_DEBUG "sys_rsbac_acl_get_mask_n(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + need_put = TRUE; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type file, symlink or block/char device? */ + switch(target) + { + case T_FD: + if(S_ISREG(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISDIR(t_dentry->d_inode->i_mode)) + { + target = T_DIR; + } + else + if(S_ISLNK(t_dentry->d_inode->i_mode)) + { + target = T_SYMLINK; + } + else + if(S_ISFIFO(t_dentry->d_inode->i_mode)) + { + target = T_FIFO; + } + else + if(S_ISSOCK(t_dentry->d_inode->i_mode)) + { + target = T_UNIXSOCK; + } + else + if(S_ISBLK(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + if(S_ISCHR(t_dentry->d_inode->i_mode)) + { + target = T_FILE; + } + else + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_FILE: + if ( !(S_ISREG(t_dentry->d_inode->i_mode)) + && !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_DIR: + if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) ) + { /* This is no dir */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_FIFO: + if ( !(S_ISFIFO(t_dentry->d_inode->i_mode))) + { /* This is no fifo */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_UNIXSOCK: + if ( !(S_ISSOCK(t_dentry->d_inode->i_mode))) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + case T_SYMLINK: + if ( !(S_ISLNK(t_dentry->d_inode->i_mode))) + { /* This is no symlink */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + break; + default: + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + tid.file.device = t_dentry->d_sb->s_dev; + tid.file.inode = t_dentry->d_inode->i_ino; + tid.file.dentry_p = t_dentry; + } + else + { + if(target == T_FD) + target = T_FILE; + tid.file.device = RSBAC_ZERO_DEV; + tid.file.inode = 0; + tid.file.dentry_p = NULL; + } + break; + + case T_DEV: + if(t_name) + { + if ((err = user_lpath(t_name, &path))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_acl) + rsbac_printk(KERN_DEBUG "sys_rsbac_acl_get_mask_n(): call to user_lpath() returned %i\n", err); +#endif + goto out; + } + t_dentry = path.dentry; + need_put = TRUE; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type block/char device? */ + if ( !(S_ISBLK(t_dentry->d_inode->i_mode)) + && !(S_ISCHR(t_dentry->d_inode->i_mode)) ) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* fill target id and call internal function */ + if(S_ISBLK(t_dentry->d_inode->i_mode)) + tid.dev.type = D_block; + else + tid.dev.type = D_char; + tid.dev.major = RSBAC_MAJOR(t_dentry->d_inode->i_rdev); + tid.dev.minor = RSBAC_MINOR(t_dentry->d_inode->i_rdev); + } + else + { + tid.dev = RSBAC_ZERO_DEV_DESC; + } + break; + + default: + return -RSBAC_EINVALIDTARGET; + } + /* call ACL function */ + err = rsbac_acl_sys_get_mask(ta_number, target, tid, &k_mask); + +out_dput: + if(need_put) + path_put(&path); +out: + if(!err) + { + rsbac_put_user(&k_mask, + mask_p, + sizeof(k_mask) ); + } + return err; + } /* end of sys_rsbac_acl_get_mask_n() */ + +/******** ACL groups *********/ + +int sys_rsbac_acl_group( + rsbac_list_ta_number_t ta_number, + enum rsbac_acl_group_syscall_type_t call, + union rsbac_acl_group_syscall_arg_t __user * arg_p) + { + union rsbac_acl_group_syscall_arg_t k_arg; + int err = 0; + + if(call >= ACLGS_none) + return -RSBAC_EINVALIDREQUEST; + if(!arg_p) + return -RSBAC_EINVALIDPOINTER; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + switch(call) + { + case ACLGS_add_group: + case ACLGS_change_group: + case ACLGS_remove_group: + case ACLGS_add_member: + case ACLGS_remove_member: + rsbac_printk(KERN_WARNING + "sys_rsbac_acl_group(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + + default: + break; + } + } +#endif + + /* get values from user space */ + err = rsbac_get_user(&k_arg, arg_p, sizeof(k_arg) ); + + /* call acl function */ + if(err >= 0) + err = rsbac_acl_sys_group(ta_number, call, k_arg); + return err; + } /* end of sys_rsbac_acl() */ + +int sys_rsbac_acl_list_all_dev( + rsbac_list_ta_number_t ta_number, + struct rsbac_dev_desc_t __user * id_p, + u_long maxnum) + { + int err = 0; + long count; + long count2; + + if(id_p && maxnum) + { + struct rsbac_dev_desc_t * k_id_p = NULL; + + count = rsbac_acl_list_all_major_dev(ta_number, &k_id_p); + if(count < 0) + return count; + if(count > maxnum) + count = maxnum; + + if(count) + { + err = rsbac_put_user(k_id_p, id_p, count * sizeof(*k_id_p) ); + rsbac_kfree(k_id_p); + if(unlikely(err < 0)) + return err; + id_p += count; + maxnum -= count; + if(!maxnum) + return count; + } + + count2 = rsbac_acl_list_all_dev(ta_number, &k_id_p); + if(count2 < 0) + return count2; + if(count2 > maxnum) + count2 = maxnum; + + if(count2) + { + err = rsbac_put_user(k_id_p, id_p, count2 * sizeof(*k_id_p) ); + rsbac_kfree(k_id_p); + if(unlikely(err < 0)) + return err; + count += count2; + } + return count; + } + else + { + count = rsbac_acl_list_all_major_dev(ta_number, NULL); + if(count < 0) + return count; + count2 = rsbac_acl_list_all_dev(ta_number, NULL); + if(count2 < 0) + return count2; + else + return count + count2; + } + } + +int sys_rsbac_acl_list_all_user( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t __user * id_p, + u_long maxnum) + { + int err = 0; + long count; + + if(id_p && maxnum) + { + rsbac_uid_t * k_id_p = NULL; + + count = rsbac_acl_list_all_user(ta_number, &k_id_p); + if(count < 0) + return count; + if(count > maxnum) + count = maxnum; + + if(count) + { + err = rsbac_put_user(k_id_p, id_p, count * sizeof(*k_id_p) ); + rsbac_kfree(k_id_p); + if(unlikely(err < 0)) + return err; + } + return count; + } + else + { + return rsbac_acl_list_all_user(ta_number, NULL); + } + } + +int sys_rsbac_acl_list_all_group( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t __user * id_p, + u_long maxnum) + { +#ifdef CONFIG_RSBAC_ACL_UM_PROT + int err = 0; + long count; + + if(id_p && maxnum) + { + rsbac_gid_t * k_id_p = NULL; + + count = rsbac_acl_list_all_group(ta_number, &k_id_p); + if(count < 0) + return count; + if(count > maxnum) + count = maxnum; + + if(count) + { + err = rsbac_put_user(k_id_p, id_p, count * sizeof(*k_id_p) ); + rsbac_kfree(k_id_p); + if(unlikely(err < 0)) + return err; + } + return count; + } + else + { + return rsbac_acl_list_all_group(ta_number, NULL); + } +#else + return -RSBAC_EINVALIDMODULE; +#endif + } +#endif + +/******** JAIL *********/ + +#ifdef CONFIG_RSBAC_JAIL +int sys_rsbac_jail(rsbac_version_t version, + char __user * path, + rsbac_jail_ip_t ip, + rsbac_jail_flags_t flags, + rsbac_cap_vector_t max_caps, + rsbac_jail_scd_vector_t scd_get, + rsbac_jail_scd_vector_t scd_modify) + { + return rsbac_jail_sys_jail(version, path, ip, flags, + max_caps, scd_get, scd_modify); + } +#endif + +/******** UM *********/ + +#ifdef CONFIG_RSBAC_UM +int sys_rsbac_um_auth_name( + char __user * name, + char __user * pass) + { + rsbac_uid_t uid = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, RSBAC_NO_USER); + int err; + char * k_name; + char * k_pass; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val; + + if(!name || !pass) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_auth_name(): NULL name or pass\n"); + } +#endif + return -RSBAC_EINVALIDPOINTER; + } + k_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_name) + return -RSBAC_ENOMEM; + k_pass = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_pass) + { + rsbac_kfree(k_name); + return -RSBAC_ENOMEM; + } + err = strncpy_from_user(k_name, name, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + goto out_free; + k_name[RSBAC_MAXNAMELEN-1] = 0; + err = strncpy_from_user(k_pass, pass, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + goto out_free; + k_pass[RSBAC_MAXNAMELEN-1] = 0; +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_auth_name(): authenticating user %s\n", + k_name); + } +#endif + err = rsbac_um_get_uid(0, k_name, &uid); + if(err) { + if(err == -RSBAC_ENOTFOUND) { + err = -EPERM; + ssleep(1); + } + goto out_free; + } + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_auth_name(): calling ADF\n"); + } +#endif + i_tid.user = uid; + i_attr_val.dummy = 0; + if (!rsbac_adf_request(R_AUTHENTICATE, + task_pid(current), + T_USER, + i_tid, + A_none, + i_attr_val)) + { + err = -EPERM; + ssleep(1); + goto out_free; + } + + err = rsbac_um_check_pass(uid, k_pass); + if(err) { + if(err == -RSBAC_ENOTFOUND) { + err = -EPERM; + } +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_printk(KERN_DEBUG "sys_rsbac_um_auth_uid(): authenticating user %u/%u failed\n", + RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_printk(KERN_DEBUG "sys_rsbac_um_auth_uid(): authenticating user %u failed\n", + RSBAC_UID_NUM(uid)); + } +#endif + ssleep(1); + goto out_free; + } + +#ifdef CONFIG_RSBAC_AUTH + /* set auth_last_auth for this process */ + i_tid.process = task_pid(current); + i_attr_val.auth_last_auth = uid; + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_last_auth, + i_attr_val)) + { + rsbac_ds_set_error("sys_rsbac_um_auth_name()", A_auth_last_auth); + } +#endif /* AUTH */ +#ifdef CONFIG_RSBAC_UM_VIRTUAL +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_auth_name(): setting process %u vset to %u\n", + current->pid, RSBAC_UID_SET(uid)); + } +#endif + /* set vset for this process */ + i_tid.process = task_pid(current); + i_attr_val.vset = RSBAC_UID_SET(uid); + if (rsbac_set_attr(SW_GEN, + T_PROCESS, + i_tid, + A_vset, + i_attr_val)) + { + rsbac_ds_set_error("sys_rsbac_um_auth_name()", A_vset); + } +#endif + +out_free: + rsbac_kfree(k_name); + memset(k_pass, 0, RSBAC_MAXNAMELEN); + rsbac_kfree(k_pass); + return err; + } + +int sys_rsbac_um_auth_uid(rsbac_uid_t uid, + char __user * pass) + { + int err; + char * k_pass; + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val; + + if(!pass) + return -RSBAC_EINVALIDPOINTER; + k_pass = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_pass) + return -RSBAC_ENOMEM; + err = strncpy_from_user(k_pass, pass, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + goto out_free; + k_pass[RSBAC_MAXNAMELEN-1] = 0; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_printk(KERN_DEBUG "sys_rsbac_um_auth_uid(): authenticating user %u/%u\n", + RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_printk(KERN_DEBUG "sys_rsbac_um_auth_uid(): authenticating user %u\n", + RSBAC_UID_NUM(uid)); + } +#endif +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_auth_uid(): calling ADF\n"); + } +#endif + i_tid.user = uid; + i_attr_val.dummy = 0; + if (!rsbac_adf_request(R_AUTHENTICATE, + task_pid(current), + T_USER, + i_tid, + A_none, + i_attr_val)) + { + err = -EPERM; + ssleep(1); + goto out_free; + } + + err = rsbac_um_check_pass(uid, k_pass); + if(err) { + if(err == -RSBAC_ENOTFOUND) { + err = -EPERM; + } +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_printk(KERN_DEBUG "sys_rsbac_um_auth_uid(): authenticating user %u/%u failed\n", + RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_printk(KERN_DEBUG "sys_rsbac_um_auth_uid(): authenticating user %u failed\n", + RSBAC_UID_NUM(uid)); + } +#endif + goto out_free; + } + +#ifdef CONFIG_RSBAC_AUTH + /* set auth_last_auth for this process */ + i_tid.process = task_pid(current); + i_attr_val.auth_last_auth = uid; + if (rsbac_set_attr(SW_AUTH, + T_PROCESS, + i_tid, + A_auth_last_auth, + i_attr_val)) + { + rsbac_ds_set_error("sys_rsbac_um_auth_uid()", A_auth_last_auth); + } +#endif /* AUTH */ +#ifdef CONFIG_RSBAC_UM_VIRTUAL + /* set vset for this process */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_auth_name(): setting process %u vset to %u\n", + current->pid, RSBAC_UID_SET(uid)); + } +#endif + i_tid.process = task_pid(current); + i_attr_val.vset = RSBAC_UID_SET(uid); + if (rsbac_set_attr(SW_GEN, + T_PROCESS, + i_tid, + A_vset, + i_attr_val)) + { + rsbac_ds_set_error("sys_rsbac_um_auth_uid()", A_vset); + } +#endif + +out_free: + memset(k_pass, 0, RSBAC_MAXNAMELEN); + rsbac_kfree(k_pass); + return err; + } + +int sys_rsbac_um_add_user( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t uid, + struct rsbac_um_user_entry_t __user * entry_p, + char __user * pass, + rsbac_time_t ttl) + { + int err; + struct rsbac_um_user_entry_t * k_entry_p; + char * k_pass; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(!entry_p) + return -RSBAC_EINVALIDPOINTER; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_add_user(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_add_user(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + k_entry_p = rsbac_kmalloc_unlocked(sizeof(*k_entry_p)); + if(!k_entry_p) + return -RSBAC_ENOMEM; + if(pass) + { + k_pass = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_pass) + { + rsbac_kfree(k_entry_p); + return -RSBAC_ENOMEM; + } + } + else + k_pass = NULL; + err = rsbac_get_user(k_entry_p, entry_p, sizeof(*k_entry_p)); + if(unlikely(err < 0)) + goto out_free; + if(!k_entry_p->name[0]) + { + err = -RSBAC_EINVALIDVALUE; + goto out_free; + } + k_entry_p->name[RSBAC_UM_NAME_LEN - 1] = 0; + k_entry_p->fullname[RSBAC_UM_FULLNAME_LEN - 1] = 0; + k_entry_p->homedir[RSBAC_UM_HOMEDIR_LEN - 1] = 0; + k_entry_p->shell[RSBAC_UM_SHELL_LEN - 1] = 0; + err = rsbac_um_get_uid(0, k_entry_p->name, &uid); + if(!err) { + err = -RSBAC_EEXISTS; + goto out_free; + } + if(pass) + { + err = strncpy_from_user(k_pass, pass, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + goto out_free; + k_pass[RSBAC_MAXNAMELEN-1] = 0; + } + err = rsbac_um_add_user(ta_number, &uid, k_entry_p, k_pass, ttl); + + /* RSBAC: notify ADF of new user */ + if(!err) + { + rsbac_target_id.user = uid; + rsbac_new_target_id.dummy = 0; + if (rsbac_adf_set_attr(R_CREATE, + task_pid(current), + T_USER, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value)) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_add_user(): rsbac_adf_set_attr() returned error\n"); + } + } + +out_free: + rsbac_kfree(k_entry_p); + if(k_pass) + { + memset(k_pass, 0, RSBAC_MAXNAMELEN); + rsbac_kfree(k_pass); + } + return err; + } + +int sys_rsbac_um_add_group( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t gid, + struct rsbac_um_group_entry_t __user * entry_p, + char __user * pass, + rsbac_time_t ttl) + { + int err; + struct rsbac_um_group_entry_t * k_entry_p; + char * k_pass; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(!entry_p) + return -RSBAC_EINVALIDPOINTER; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_add_group(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(gid) == RSBAC_UM_VIRTUAL_KEEP) + gid = RSBAC_GEN_GID (rsbac_get_vset(), RSBAC_GID_NUM(gid)); + else + if (RSBAC_GID_SET(gid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + gid = RSBAC_GID_NUM(gid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_add_group(): calling ADF\n"); + } +#endif + rsbac_target_id.group = gid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_CREATE, + task_pid(current), + T_GROUP, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + k_entry_p = rsbac_kmalloc_unlocked(sizeof(*k_entry_p)); + if(!k_entry_p) + return -RSBAC_ENOMEM; + if(pass) + { + k_pass = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_pass) + { + rsbac_kfree(k_entry_p); + return -RSBAC_ENOMEM; + } + } + else + k_pass = NULL; + err = rsbac_get_user(k_entry_p, entry_p, sizeof(*k_entry_p)); + if(unlikely(err < 0)) + goto out_free; + if(!k_entry_p->name[0]) + { + err = -RSBAC_EINVALIDVALUE; + goto out_free; + } + k_entry_p->name[RSBAC_UM_NAME_LEN - 1] = 0; + err = rsbac_um_get_gid(0, k_entry_p->name, &gid); + if(!err) { + err = -RSBAC_EEXISTS; + goto out_free; + } + if(pass) + { + err = strncpy_from_user(k_pass, pass, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + goto out_free; + k_pass[RSBAC_MAXNAMELEN-1] = 0; + } + err = rsbac_um_add_group(ta_number, &gid, k_entry_p, k_pass, ttl); + + /* RSBAC: notify ADF of new group */ + if(!err) + { + rsbac_target_id.group = gid; + rsbac_new_target_id.dummy = 0; + if (rsbac_adf_set_attr(R_CREATE, + task_pid(current), + T_GROUP, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value)) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_add_group(): rsbac_adf_set_attr() returned error\n"); + } + } + +out_free: + rsbac_kfree(k_entry_p); + if(k_pass) + { + memset(k_pass, 0, RSBAC_MAXNAMELEN); + rsbac_kfree(k_pass); + } + return err; + } + +int sys_rsbac_um_add_gm( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + rsbac_gid_num_t group, + rsbac_time_t ttl) + { + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_add_gm(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(user) == RSBAC_UM_VIRTUAL_KEEP) + user = RSBAC_GEN_UID (rsbac_get_vset(), user); + else + if (RSBAC_UID_SET(user) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + user = RSBAC_UID_NUM(user); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_add_gm(): calling ADF\n"); + } +#endif + rsbac_target_id.user = user; + rsbac_attribute_value.group = group; + if (!rsbac_adf_request(R_CHANGE_GROUP, + task_pid(current), + T_USER, + rsbac_target_id, + A_group, + rsbac_attribute_value)) + { + return -EPERM; + } + + return rsbac_um_add_gm(ta_number, user, group, ttl); + } + +int sys_rsbac_um_mod_user( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t uid, + enum rsbac_um_mod_t mod, + union rsbac_um_mod_data_t __user * data_p) + { + int err; + union rsbac_um_mod_data_t * k_data_p; + enum rsbac_adf_request_t rsbac_request; + union rsbac_target_id_t rsbac_target_id; + enum rsbac_attribute_t rsbac_attribute = A_none; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(mod >= UM_none) + return -RSBAC_EINVALIDREQUEST; + if( !data_p + && (mod != UM_pass) + ) + return -RSBAC_EINVALIDPOINTER; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_mod_user(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + + if(data_p) + { + k_data_p = rsbac_kmalloc_unlocked(sizeof(*k_data_p)); + if(!k_data_p) + return -RSBAC_ENOMEM; +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) + if((current->thread.status & TS_COMPAT) || test_thread_flag(TIF_IA32)) + err = rsbac_get_user(k_data_p, data_p, sizeof(union rsbac_um_mod_data_ia32_t)); + else +#endif + err = rsbac_get_user(k_data_p, data_p, sizeof(*k_data_p)); + if(unlikely(err < 0)) + { + rsbac_kfree(k_data_p); + return err; + } + k_data_p->string[RSBAC_MAXNAMELEN-1] = 0; + } + else + k_data_p = NULL; + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_mod_user(): calling ADF\n"); + } +#endif + rsbac_attribute_value.dummy = 0; + switch(mod) + { + case UM_name: + rsbac_request = R_RENAME; + break; + + case UM_pass: + case UM_cryptpass: + rsbac_request = R_MODIFY_PERMISSIONS_DATA; + break; + + case UM_fullname: + rsbac_request = R_WRITE; + break; + + case UM_homedir: + rsbac_request = R_WRITE; + break; + + case UM_shell: + rsbac_request = R_WRITE; + break; + + case UM_group: + rsbac_request = R_CHANGE_GROUP; + if (!k_data_p) + return -RSBAC_EINVALIDPOINTER; + rsbac_attribute = A_group; + rsbac_attribute_value.group = k_data_p->group; + break; + + case UM_lastchange: + rsbac_request = R_WRITE; + break; + + case UM_minchange: + rsbac_request = R_WRITE; + break; + + case UM_maxchange: + rsbac_request = R_WRITE; + break; + + case UM_warnchange: + rsbac_request = R_WRITE; + break; + + case UM_inactive: + rsbac_request = R_WRITE; + break; + + case UM_expire: + rsbac_request = R_WRITE; + break; + + case UM_ttl: + rsbac_request = R_DELETE; + break; + + default: + if(k_data_p) + rsbac_kfree(k_data_p); + return -RSBAC_EINVALIDREQUEST; + } + rsbac_target_id.user = uid; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_USER, + rsbac_target_id, + rsbac_attribute, + rsbac_attribute_value)) + { + if(k_data_p) + rsbac_kfree(k_data_p); + return -EPERM; + } + + err = rsbac_um_mod_user(ta_number, uid, mod, k_data_p); + + if(k_data_p) + rsbac_kfree(k_data_p); + return err; + } + +int sys_rsbac_um_mod_group( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t gid, + enum rsbac_um_mod_t mod, + union rsbac_um_mod_data_t __user * data_p) + { + int err; + union rsbac_um_mod_data_t * k_data_p; + enum rsbac_adf_request_t rsbac_request; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(mod >= UM_none) + return -RSBAC_EINVALIDREQUEST; + if( !data_p + && (mod != UM_pass) + ) + return -RSBAC_EINVALIDPOINTER; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_mod_group(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(gid) == RSBAC_UM_VIRTUAL_KEEP) + gid = RSBAC_GEN_GID (rsbac_get_vset(), RSBAC_GID_NUM(gid)); + else + if (RSBAC_GID_SET(gid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + gid = RSBAC_GID_NUM(gid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_mod_group(): calling ADF\n"); + } +#endif + switch(mod) + { + case UM_name: + rsbac_request = R_RENAME; + break; + + case UM_pass: + case UM_cryptpass: + rsbac_request = R_MODIFY_PERMISSIONS_DATA; + break; + + case UM_ttl: + rsbac_request = R_DELETE; + break; + + default: + return -RSBAC_EINVALIDREQUEST; + } + rsbac_target_id.group = gid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_GROUP, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + if(data_p) + { + k_data_p = rsbac_kmalloc_unlocked(sizeof(*k_data_p)); + if(!k_data_p) + return -RSBAC_ENOMEM; +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) + if((current->thread.status & TS_COMPAT) || test_thread_flag(TIF_IA32)) + err = rsbac_get_user(k_data_p, data_p, sizeof(union rsbac_um_mod_data_ia32_t)); + else +#endif + err = rsbac_get_user(k_data_p, data_p, sizeof(*k_data_p)); + if(unlikely(err < 0)) + { + rsbac_kfree(k_data_p); + return err; + } + k_data_p->string[RSBAC_MAXNAMELEN-1] = 0; + } + else + k_data_p = NULL; + + err = rsbac_um_mod_group(ta_number, gid, mod, k_data_p); + + if(k_data_p) + rsbac_kfree(k_data_p); + return err; + } + +int sys_rsbac_um_get_user_item( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t uid, + enum rsbac_um_mod_t mod, + union rsbac_um_mod_data_t __user * data_p) + { + int err; + union rsbac_um_mod_data_t * k_data_p; + enum rsbac_adf_request_t rsbac_request; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(mod >= UM_none) + return -RSBAC_EINVALIDREQUEST; + if(!data_p) + return -RSBAC_EINVALIDPOINTER; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_user_item(): calling ADF\n"); + } +#endif + rsbac_attribute_value.dummy = 0; + switch(mod) + { + case UM_name: + rsbac_request = R_SEARCH; + break; + + case UM_group: + case UM_fullname: + case UM_homedir: + case UM_shell: + rsbac_request = R_GET_STATUS_DATA; + break; + + case UM_pass: + rsbac_request = R_GET_PERMISSIONS_DATA; + break; + + case UM_lastchange: + case UM_minchange: + case UM_maxchange: + case UM_warnchange: + case UM_inactive: + case UM_expire: + case UM_ttl: + rsbac_request = R_READ; + break; + + default: + return -RSBAC_EINVALIDREQUEST; + } + rsbac_target_id.user = uid; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + k_data_p = rsbac_kmalloc_unlocked(sizeof(*k_data_p)); + if(!k_data_p) + return -RSBAC_ENOMEM; + memset(k_data_p, 0, sizeof(*k_data_p)); + + err = rsbac_um_get_user_item(ta_number, uid, mod, k_data_p); + if(!err) + { +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) + if((current->thread.status & TS_COMPAT) || test_thread_flag(TIF_IA32)) + err = rsbac_put_user(k_data_p, data_p, sizeof(union rsbac_um_mod_data_ia32_t) ); + else +#endif + err = rsbac_put_user(k_data_p, data_p, sizeof(*k_data_p) ); + } + rsbac_kfree(k_data_p); + return err; + } + +int sys_rsbac_um_get_group_item( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t gid, + enum rsbac_um_mod_t mod, + union rsbac_um_mod_data_t __user * data_p) + { + int err; + union rsbac_um_mod_data_t * k_data_p; + enum rsbac_adf_request_t rsbac_request; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(mod >= UM_none) + return -RSBAC_EINVALIDREQUEST; + if(!data_p) + return -RSBAC_EINVALIDPOINTER; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(gid) == RSBAC_UM_VIRTUAL_KEEP) + gid = RSBAC_GEN_GID (rsbac_get_vset(), gid); + else + if (RSBAC_GID_SET(gid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + gid = RSBAC_GID_NUM(gid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_group_item(): getting item %u for %u/%u\n", + mod, RSBAC_GID_SET(gid), RSBAC_GID_NUM(gid)); + } +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_group_item(): calling ADF\n"); + } +#endif + rsbac_attribute_value.dummy = 0; + switch(mod) + { + case UM_name: + rsbac_request = R_SEARCH; + break; + + case UM_pass: + rsbac_request = R_GET_PERMISSIONS_DATA; + break; + + case UM_ttl: + rsbac_request = R_GET_STATUS_DATA; + break; + + default: + return -RSBAC_EINVALIDREQUEST; + } + rsbac_target_id.group = gid; + if (!rsbac_adf_request(rsbac_request, + task_pid(current), + T_GROUP, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + k_data_p = rsbac_kmalloc_unlocked(sizeof(*k_data_p)); + if(!k_data_p) + return -RSBAC_ENOMEM; + memset(k_data_p, 0, sizeof(*k_data_p)); + + err = rsbac_um_get_group_item(ta_number, gid, mod, k_data_p); + if(!err) + { +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) + if((current->thread.status & TS_COMPAT) || test_thread_flag(TIF_IA32)) + err = rsbac_put_user(k_data_p, data_p, sizeof(union rsbac_um_mod_data_ia32_t) ); + else +#endif + err = rsbac_put_user(k_data_p, data_p, sizeof(*k_data_p) ); + } + rsbac_kfree(k_data_p); + return err; + } + +int sys_rsbac_um_remove_user( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t uid) + { + int err; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_remove_user(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_remove_user(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_DELETE, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + err = rsbac_um_remove_user(ta_number, uid); + + if(!err) + { + rsbac_new_target_id.dummy = 0; + if (rsbac_adf_set_attr(R_DELETE, + task_pid(current), + T_USER, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value)) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_remove_user(): rsbac_adf_set_attr() returned error"); + } + } + + return err; + } + +int sys_rsbac_um_remove_group( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t gid) + { + int err; + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_remove_group(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(gid) == RSBAC_UM_VIRTUAL_KEEP) + gid = RSBAC_GEN_GID (rsbac_get_vset(), gid); + else + if (RSBAC_GID_SET(gid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + gid = RSBAC_GID_NUM(gid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_remove_group(): calling ADF\n"); + } +#endif + rsbac_target_id.group = gid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_DELETE, + task_pid(current), + T_GROUP, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + err = rsbac_um_remove_group(ta_number, gid); + + if(!err) + { + rsbac_new_target_id.dummy = 0; + if (rsbac_adf_set_attr(R_DELETE, + task_pid(current), + T_GROUP, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_none, + rsbac_attribute_value)) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_remove_group(): rsbac_adf_set_attr() returned error"); + } + } + + return err; + } + +int sys_rsbac_um_remove_gm( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + rsbac_gid_num_t group) + { + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_remove_gm(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(user) == RSBAC_UM_VIRTUAL_KEEP) + user = RSBAC_GEN_UID (rsbac_get_vset(), user); + else + if (RSBAC_UID_SET(user) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + user = RSBAC_UID_NUM(user); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_remove_gm(): calling ADF\n"); + } +#endif + rsbac_target_id.user = user; + rsbac_attribute_value.group = group; + if (!rsbac_adf_request(R_CHANGE_GROUP, + task_pid(current), + T_USER, + rsbac_target_id, + A_group, + rsbac_attribute_value)) + { + return -EPERM; + } + + return rsbac_um_remove_gm(ta_number, user, group); + } + +int sys_rsbac_um_user_exists( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t uid) + { + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_user_exists(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + return rsbac_um_user_exists(ta_number, uid); + } + +int sys_rsbac_um_group_exists( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t gid) + { + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(gid) == RSBAC_UM_VIRTUAL_KEEP) + gid = RSBAC_GEN_GID (rsbac_get_vset(), gid); + else + if (RSBAC_GID_SET(gid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + gid = RSBAC_GID_NUM(gid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_group_exists(): calling ADF\n"); + } +#endif + rsbac_target_id.group = gid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + T_GROUP, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + return rsbac_um_group_exists(ta_number, gid); + } + +int sys_rsbac_um_get_next_user( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t old_user, + rsbac_uid_t __user * next_user_p) + { + rsbac_uid_t k_next_user; + int err; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(!next_user_p) + return -RSBAC_EINVALIDPOINTER; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(old_user) == RSBAC_UM_VIRTUAL_KEEP) + old_user = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(old_user)); + else + if (RSBAC_UID_SET(old_user) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + old_user = RSBAC_UID_NUM(old_user); +#endif + + while (!(err = rsbac_um_get_next_user(ta_number, old_user, &k_next_user))) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_next_user(): calling ADF\n"); + } +#endif + rsbac_target_id.user = k_next_user; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + old_user = k_next_user; + continue; + } + err = rsbac_put_user(&k_next_user, next_user_p, sizeof(k_next_user)); + break; + } + return err; + } + +int sys_rsbac_um_get_user_list( + rsbac_list_ta_number_t ta_number, + rsbac_um_set_t vset, + rsbac_uid_t __user user_array[], + u_int maxnum) + { + long count; + rsbac_uid_t * k_user_array; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(maxnum > RSBAC_UM_MAX_MAXNUM) + maxnum = RSBAC_UM_MAX_MAXNUM; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (vset == RSBAC_UM_VIRTUAL_KEEP) + vset = rsbac_get_vset(); + else + if ( (vset > RSBAC_UM_VIRTUAL_MAX) + && (vset != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDVALUE; +#else + vset = 0; +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_user_list(): calling ADF\n"); + } +#endif + rsbac_target_id.user = RSBAC_GEN_UID(vset, RSBAC_ALL_USERS); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + /* count only */ + if(!user_array || !maxnum) + return rsbac_um_get_user_list(ta_number, vset, NULL); + + count = rsbac_um_get_user_list(ta_number, vset, &k_user_array); + if(count>0) + { + if(count > maxnum) + count = maxnum; + rsbac_put_user(k_user_array, + user_array, + count * sizeof(*k_user_array) ); + rsbac_kfree(k_user_array); + } + return count; + } /* end of sys_rsbac_um_get_user_list() */ + +int sys_rsbac_um_get_gm_list( + rsbac_list_ta_number_t ta_number, + rsbac_uid_t user, + rsbac_gid_num_t __user group_array[], + u_int maxnum) + { + long count; + rsbac_gid_num_t * k_group_array; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(maxnum > RSBAC_UM_MAX_MAXNUM) + maxnum = RSBAC_UM_MAX_MAXNUM; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(user) == RSBAC_UM_VIRTUAL_KEEP) + user = RSBAC_GEN_UID (rsbac_get_vset(), user); + else + if (RSBAC_UID_SET(user) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + user = RSBAC_UID_NUM(user); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_gm_list(): calling ADF\n"); + } +#endif + rsbac_target_id.user = user; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + /* count only */ + if(!group_array || !maxnum) + return rsbac_um_get_gm_list(ta_number, user, NULL); + + count = rsbac_um_get_gm_list(ta_number, user, &k_group_array); + if(count>0) + { + if(count > maxnum) + count = maxnum; + rsbac_put_user(k_group_array, + group_array, + count * sizeof(*k_group_array) ); + rsbac_kfree(k_group_array); + } + return count; + } /* end of sys_rsbac_um_get_gm_list() */ + +int sys_rsbac_um_get_gm_user_list( + rsbac_list_ta_number_t ta_number, + rsbac_gid_t group, + rsbac_uid_num_t __user user_array[], + u_int maxnum) + { + long count; + rsbac_uid_num_t * k_user_array; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(maxnum > RSBAC_UM_MAX_MAXNUM) + maxnum = RSBAC_UM_MAX_MAXNUM; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(group) == RSBAC_UM_VIRTUAL_KEEP) + group = RSBAC_GEN_GID (rsbac_get_vset(), group); + else + if (RSBAC_GID_SET(group) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + group = RSBAC_GID_NUM(group); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_gm_user_list(): calling ADF\n"); + } +#endif + rsbac_target_id.group = group; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_READ, + task_pid(current), + T_GROUP, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + /* count number of all users */ + if(!user_array || !maxnum) + return rsbac_um_get_gm_user_list(ta_number, group, NULL); + + count = rsbac_um_get_gm_user_list(ta_number, group, &k_user_array); + if(count>0) + { + if(count > maxnum) + count = maxnum; + rsbac_put_user(k_user_array, + user_array, + count * sizeof(*k_user_array) ); + rsbac_kfree(k_user_array); + } + return count; + } /* end of sys_rsbac_um_get_gm_user_list() */ + +int sys_rsbac_um_get_group_list( + rsbac_list_ta_number_t ta_number, + rsbac_um_set_t vset, + rsbac_gid_t __user group_array[], + u_int maxnum) + { + long count; + rsbac_gid_t * k_group_array; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(maxnum > RSBAC_UM_MAX_MAXNUM) + maxnum = RSBAC_UM_MAX_MAXNUM; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (vset == RSBAC_UM_VIRTUAL_KEEP) + vset = rsbac_get_vset(); + else + if ( (vset > RSBAC_UM_VIRTUAL_MAX) + && (vset != RSBAC_UM_VIRTUAL_ALL) + ) + return -RSBAC_EINVALIDVALUE; +#else + vset = 0; +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_group_list(): calling ADF\n"); + } +#endif + rsbac_target_id.group = RSBAC_GEN_GID(vset, RSBAC_ALL_USERS); + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + T_GROUP, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + /* count only */ + if(!group_array || !maxnum) + return rsbac_um_get_group_list(ta_number, vset, NULL); + + count = rsbac_um_get_group_list(ta_number, vset, &k_group_array); + if(count>0) + { + if(count > maxnum) + count = maxnum; + rsbac_put_user(k_group_array, + group_array, + count * sizeof(*k_group_array) ); + rsbac_kfree(k_group_array); + } + return count; + } /* end of sys_rsbac_um_get_group_list() */ + +int sys_rsbac_um_get_uid( + rsbac_list_ta_number_t ta_number, + char __user * name, + rsbac_uid_t __user * uid_p) + { + rsbac_uid_t k_uid; + int err; + char k_name[RSBAC_MAXNAMELEN]; + + if(!name || !uid_p) + return -RSBAC_EINVALIDPOINTER; + + err = strncpy_from_user(k_name, name, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + return err; + k_name[RSBAC_MAXNAMELEN-1] = 0; + err = rsbac_get_user(&k_uid, uid_p, sizeof(k_uid)); + if(unlikely(err < 0)) + return err; +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_uid(): looking up %u/%s\n", + RSBAC_UID_SET(k_uid), k_name); + } +#endif + /* vset checks are in rsbac_um_get_uid() */ + err = rsbac_um_get_uid(ta_number, k_name, &k_uid); + if(!err) + { + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_uid(): calling ADF\n"); + } +#endif + rsbac_target_id.user = k_uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + err = -EPERM; + else + err = rsbac_put_user(&k_uid, uid_p, sizeof(k_uid)); + } + return err; + } + +int sys_rsbac_um_get_gid( + rsbac_list_ta_number_t ta_number, + char __user * name, + rsbac_gid_t __user * gid_p) + { + rsbac_gid_t k_gid; + int err; + char k_name[RSBAC_MAXNAMELEN]; + + if(!name || !gid_p) + return -RSBAC_EINVALIDPOINTER; + err = strncpy_from_user(k_name, name, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + return err; + k_name[RSBAC_MAXNAMELEN-1] = 0; + err = rsbac_get_user(&k_gid, gid_p, sizeof(k_gid)); + if(unlikely(err < 0)) + return err; +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_gid(): looking up %u/%s\n", + RSBAC_GID_SET(k_gid), k_name); + } +#endif + /* vset checks are in rsbac_um_get_gid() */ + err = rsbac_um_get_gid(ta_number, k_name, &k_gid); + if(!err) + { + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_gid(): calling ADF\n"); + } +#endif + rsbac_target_id.group = k_gid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_SEARCH, + task_pid(current), + T_GROUP, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + err = -EPERM; + else + err = rsbac_put_user(&k_gid, gid_p, sizeof(k_gid)); + } + return err; + } + +int sys_rsbac_um_set_pass(rsbac_uid_t uid, + char __user * old_pass, + char __user * new_pass) + { + int err; + char __user * k_new_pass; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + rsbac_um_set_t vset; +#endif + + if(!new_pass) + return -RSBAC_EINVALIDPOINTER; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + vset = rsbac_get_vset(); + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (vset, uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + + k_new_pass = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_new_pass) + return -RSBAC_ENOMEM; + err = strncpy_from_user(k_new_pass, new_pass, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_new_pass); + return err; + } + k_new_pass[RSBAC_MAXNAMELEN-1] = 0; + + if( old_pass + && (RSBAC_UID_NUM(uid) == __kuid_val(current_uid())) +#ifdef CONFIG_RSBAC_UM_VIRTUAL + && (RSBAC_UID_SET(uid) == vset) +#endif + ) + { + char * k_old_pass; + + k_old_pass = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_old_pass) + { + rsbac_kfree(k_new_pass); + return -RSBAC_ENOMEM; + } + err = strncpy_from_user(k_old_pass, old_pass, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_old_pass); + rsbac_kfree(k_new_pass); + return err; + } + k_old_pass[RSBAC_MAXNAMELEN-1] = 0; + err = rsbac_um_check_pass(uid, k_old_pass); + rsbac_kfree(k_old_pass); + if(err) + { + rsbac_kfree(k_new_pass); + rsbac_printk(KERN_INFO "sys_rsbac_um_set_pass(): old password check failed\n"); + return err; + } + err = rsbac_um_good_pass(uid, k_new_pass); + if(err) + { + rsbac_kfree(k_new_pass); +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_printk(KERN_DEBUG + "sys_rsbac_um_set_pass(): new password goodness check failed for user %u/%u\n", + RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_printk(KERN_DEBUG + "sys_rsbac_um_set_pass(): new password goodness check failed for user %u\n", + RSBAC_UID_NUM(uid)); + } +#endif + return err; + } + } + else + { + /* check admin rights here */ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_set_pass(): RSBAC configuration frozen, no administration allowed!\n"); + rsbac_kfree(k_new_pass); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_set_pass(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_PERMISSIONS_DATA, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + rsbac_kfree(k_new_pass); + return -EPERM; + } + } + + err = rsbac_um_set_pass(uid, k_new_pass); + rsbac_kfree(k_new_pass); + return err; + } + +int sys_rsbac_um_set_pass_name(char __user * name, + char __user * old_pass, + char __user * new_pass) + { + int err; + rsbac_uid_t uid = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, RSBAC_NO_USER); + char * k_name; + + if(!name || !new_pass) + return -RSBAC_EINVALIDPOINTER; + k_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_name) + return -RSBAC_ENOMEM; + err = strncpy_from_user(k_name, name, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_name); + return err; + } + k_name[RSBAC_MAXNAMELEN-1] = 0; + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_set_pass_name(): user %s\n", + k_name); + } +#endif + err = rsbac_um_get_uid(0, k_name, &uid); + rsbac_kfree(k_name); + if(err) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_set_pass_name(): lookup of user %s failed\n", + k_name); + } +#endif + } + else + err = sys_rsbac_um_set_pass(uid, old_pass, new_pass); + + return err; + } + +int sys_rsbac_um_add_onetime(rsbac_uid_t uid, + char __user * old_pass, + char __user * new_pass, + rsbac_time_t ttl) + { +#if defined(CONFIG_RSBAC_UM_ONETIME) + int err; + char * k_new_pass; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + rsbac_um_set_t vset; +#endif + + if(!new_pass) + return -RSBAC_EINVALIDPOINTER; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + vset = rsbac_get_vset(); + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (vset, uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + + k_new_pass = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_new_pass) + return -RSBAC_ENOMEM; + err = strncpy_from_user(k_new_pass, new_pass, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_new_pass); + return err; + } + k_new_pass[RSBAC_MAXNAMELEN-1] = 0; + + if( old_pass + && (RSBAC_UID_NUM(uid) == __kuid_val(current_uid())) +#ifdef CONFIG_RSBAC_UM_VIRTUAL + && (RSBAC_UID_SET(uid) == vset) +#endif + ) + { + char * k_old_pass; + + k_old_pass = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_old_pass) + { + rsbac_kfree(k_new_pass); + return -RSBAC_ENOMEM; + } + err = strncpy_from_user(k_old_pass, old_pass, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_old_pass); + rsbac_kfree(k_new_pass); + return err; + } + k_old_pass[RSBAC_MAXNAMELEN-1] = 0; + err = rsbac_um_check_pass(uid, k_old_pass); + rsbac_kfree(k_old_pass); + if(err) + { + rsbac_kfree(k_new_pass); + rsbac_printk(KERN_INFO "sys_rsbac_um_add_onetime(): old password check failed\n"); + return err; + } + err = rsbac_um_good_pass(uid, k_new_pass); + if(err) + { + rsbac_kfree(k_new_pass); +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if(RSBAC_UID_SET(uid)) + rsbac_printk(KERN_DEBUG + "sys_rsbac_um_add_onetime(): new password goodness check failed for user %u/%u\n", + RSBAC_UID_SET(uid), RSBAC_UID_NUM(uid)); + else +#endif + rsbac_printk(KERN_DEBUG + "sys_rsbac_um_add_onetime(): new password goodness check failed for user %u\n", + RSBAC_UID_NUM(uid)); + } +#endif + return err; + } + } + else + { + /* check admin rights here */ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_add_onetime(): RSBAC configuration frozen, no administration allowed!\n"); + rsbac_kfree(k_new_pass); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_add_onetime(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_PERMISSIONS_DATA, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + rsbac_kfree(k_new_pass); + return -EPERM; + } + } + + err = rsbac_um_add_onetime(uid, k_new_pass, ttl); + rsbac_kfree(k_new_pass); + return err; +#else + return -RSBAC_EINVALIDMODULE; +#endif + } + +int sys_rsbac_um_add_onetime_name(char __user * name, + char __user * old_pass, + char __user * new_pass, + rsbac_time_t ttl) + { +#if defined(CONFIG_RSBAC_UM_ONETIME) + int err; + rsbac_uid_t uid = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, RSBAC_NO_USER); + char * k_name; + + if(!name || !new_pass) + return -RSBAC_EINVALIDPOINTER; + k_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_name) + return -RSBAC_ENOMEM; + err = strncpy_from_user(k_name, name, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_name); + return err; + } + k_name[RSBAC_MAXNAMELEN-1] = 0; + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_add_onetime_name(): user %s\n", + k_name); + } +#endif + err = rsbac_um_get_uid(0, k_name, &uid); + rsbac_kfree(k_name); + if(err) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_add_onetime_name(): lookup of user %s failed\n", + k_name); + } +#endif + } + else + err = sys_rsbac_um_add_onetime(uid, old_pass, new_pass, ttl); + + return err; +#else + return -RSBAC_EINVALIDMODULE; +#endif + } + +int sys_rsbac_um_remove_all_onetime(rsbac_uid_t uid, + char __user * old_pass) + { +#if defined(CONFIG_RSBAC_UM_ONETIME) + int err; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + rsbac_um_set_t vset; +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + vset = rsbac_get_vset(); + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (vset, uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + + if( old_pass + && (RSBAC_UID_NUM(uid) == __kuid_val(current_uid())) +#ifdef CONFIG_RSBAC_UM_VIRTUAL + && (RSBAC_UID_SET(uid) == vset) +#endif + ) + { + char * k_old_pass; + + k_old_pass = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_old_pass) + { + return -RSBAC_ENOMEM; + } + err = strncpy_from_user(k_old_pass, old_pass, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_old_pass); + return err; + } + k_old_pass[RSBAC_MAXNAMELEN-1] = 0; + err = rsbac_um_check_pass(uid, k_old_pass); + rsbac_kfree(k_old_pass); + if(err) + { + rsbac_printk(KERN_INFO "sys_rsbac_um_remove_all_onetime(): old password check failed\n"); + return err; + } + } + else + { + /* check admin rights here */ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_remove_all_onetime(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_remove_all_onetime(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_PERMISSIONS_DATA, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + } + + err = rsbac_um_remove_all_onetime(uid); + return err; +#else + return -RSBAC_EINVALIDMODULE; +#endif + } + +int sys_rsbac_um_remove_all_onetime_name(char __user * name, + char __user * old_pass) + { +#if defined(CONFIG_RSBAC_UM_ONETIME) + int err; + rsbac_uid_t uid = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, RSBAC_NO_USER); + char * k_name; + + if(!name) + return -RSBAC_EINVALIDPOINTER; + k_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_name) + return -RSBAC_ENOMEM; + err = strncpy_from_user(k_name, name, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_name); + return err; + } + k_name[RSBAC_MAXNAMELEN-1] = 0; + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_remove_all_onetime_name(): user %s\n", + k_name); + } +#endif + err = rsbac_um_get_uid(0, k_name, &uid); + rsbac_kfree(k_name); + if(err) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_remove_all_onetime_name(): lookup of user %s failed\n", + k_name); + } +#endif + } + else + err = sys_rsbac_um_remove_all_onetime(uid, old_pass); + + return err; +#else + return -RSBAC_EINVALIDMODULE; +#endif + } + +int sys_rsbac_um_count_onetime(rsbac_uid_t uid, + char __user * old_pass) + { +#if defined(CONFIG_RSBAC_UM_ONETIME) + int err; +#ifdef CONFIG_RSBAC_UM_VIRTUAL + rsbac_um_set_t vset; +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + vset = rsbac_get_vset(); + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (vset, uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + + if( old_pass + && (RSBAC_UID_NUM(uid) == __kuid_val(current_uid())) +#ifdef CONFIG_RSBAC_UM_VIRTUAL + && (RSBAC_UID_SET(uid) == vset) +#endif + ) + { + char * k_old_pass; + + k_old_pass = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_old_pass) + { + return -RSBAC_ENOMEM; + } + err = strncpy_from_user(k_old_pass, old_pass, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_old_pass); + return err; + } + k_old_pass[RSBAC_MAXNAMELEN-1] = 0; + err = rsbac_um_check_pass(uid, k_old_pass); + rsbac_kfree(k_old_pass); + if(err) + { + rsbac_printk(KERN_INFO "sys_rsbac_um_count_onetime(): old password check failed\n"); + return err; + } + } + else + { + /* check admin rights here */ + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_count_onetime(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_count_onetime(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_READ, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + } + + return rsbac_um_count_onetime(uid); +#else + return -RSBAC_EINVALIDMODULE; +#endif + } + +int sys_rsbac_um_count_onetime_name(char __user * name, + char __user * old_pass) + { +#if defined(CONFIG_RSBAC_UM_ONETIME) + int err; + rsbac_uid_t uid = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, RSBAC_NO_USER); + char * k_name; + + if(!name) + return -RSBAC_EINVALIDPOINTER; + k_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_name) + return -RSBAC_ENOMEM; + err = strncpy_from_user(k_name, name, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_name); + return err; + } + k_name[RSBAC_MAXNAMELEN-1] = 0; + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_count_onetime_name(): user %s\n", + k_name); + } +#endif + err = rsbac_um_get_uid(0, k_name, &uid); + rsbac_kfree(k_name); + if(err) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_count_onetime_name(): lookup of user %s failed\n", + k_name); + } +#endif + } + else + err = sys_rsbac_um_count_onetime(uid, old_pass); + + return err; +#else + return -RSBAC_EINVALIDMODULE; +#endif + } + +int sys_rsbac_um_set_group_pass(rsbac_gid_t gid, + char __user * new_pass) + { + int err; + char * k_new_pass; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_FREEZE_UM + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_set_group_pass(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_GID_SET(gid) == RSBAC_UM_VIRTUAL_KEEP) + gid = RSBAC_GEN_GID (rsbac_get_vset(), RSBAC_GID_NUM(gid)); + else + if (RSBAC_GID_SET(gid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + gid = RSBAC_GID_NUM(gid); +#endif + + /* check admin rights here */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_set_group_pass(): calling ADF\n"); + } +#endif + rsbac_target_id.group = gid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_MODIFY_PERMISSIONS_DATA, + task_pid(current), + T_GROUP, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + if(new_pass) + { + k_new_pass = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(!k_new_pass) + return -RSBAC_ENOMEM; + err = strncpy_from_user(k_new_pass, new_pass, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + { + k_new_pass[RSBAC_MAXNAMELEN-1] = 0; + err = rsbac_um_set_group_pass(gid, k_new_pass); + } + rsbac_kfree(k_new_pass); + } + else + { + err = rsbac_um_set_group_pass(gid, NULL); + } + return err; + } + +int sys_rsbac_um_check_account(rsbac_uid_t uid) + { + int err; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_check_account(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + err = rsbac_um_check_account(uid); + if(err == -RSBAC_ENOTFOUND) + err = -EPERM; + return err; + } + +int sys_rsbac_um_check_account_name(char __user * name) + { + int err; + rsbac_uid_t uid = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, RSBAC_NO_USER); + char k_name[RSBAC_MAXNAMELEN]; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(!name) + return -RSBAC_EINVALIDPOINTER; + err = strncpy_from_user(k_name, name, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + return err; + k_name[RSBAC_MAXNAMELEN-1] = 0; +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_check_account_name(): checking user %s\n", + k_name); + } +#endif + err = rsbac_um_get_uid(0, k_name, &uid); + if(err) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_check_account_name(): lookup of user %s failed\n", + k_name); + } +#endif + if(err == -RSBAC_ENOTFOUND) + err = -EPERM; + return err; + } + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_check_account_name(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + err = rsbac_um_check_account(uid); + if(err == -RSBAC_ENOTFOUND) + err = -EPERM; + return err; + } + +int sys_rsbac_um_get_max_history(rsbac_list_ta_number_t ta_number, rsbac_uid_t uid) + { +#ifdef CONFIG_RSBAC_UM_PWHISTORY + int err; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_max_history(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_READ, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + err = rsbac_um_get_max_history(ta_number, uid); + if(err == -RSBAC_ENOTFOUND) + err = -EPERM; + return err; +#else + return -RSBAC_EINVALIDMODULE; +#endif + } + +int sys_rsbac_um_get_max_history_name(rsbac_list_ta_number_t ta_number, char __user * name) + { +#ifdef CONFIG_RSBAC_UM_PWHISTORY + int err; + rsbac_uid_t uid = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, RSBAC_NO_USER); + char k_name[RSBAC_MAXNAMELEN]; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(!name) + return -RSBAC_EINVALIDPOINTER; + err = strncpy_from_user(k_name, name, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + return err; + k_name[RSBAC_MAXNAMELEN-1] = 0; +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_max_history_name(): getting max_history of user %s\n", + k_name); + } +#endif + err = rsbac_um_get_uid(0, k_name, &uid); + if(err) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_max_history_name(): lookup of user %s failed\n", + k_name); + } +#endif + if(err == -RSBAC_ENOTFOUND) + err = -EPERM; + return err; + } + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_get_max_history_name(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_READ, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + err = rsbac_um_get_max_history(ta_number, uid); + if(err == -RSBAC_ENOTFOUND) + err = -EPERM; + return err; +#else + return -RSBAC_EINVALIDMODULE; +#endif + } + +int sys_rsbac_um_set_max_history(rsbac_list_ta_number_t ta_number, rsbac_uid_t uid, __u8 max_history) + { +#ifdef CONFIG_RSBAC_UM_PWHISTORY + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(uid) == RSBAC_UM_VIRTUAL_KEEP) + uid = RSBAC_GEN_UID (rsbac_get_vset(), uid); + else + if (RSBAC_UID_SET(uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + uid = RSBAC_UID_NUM(uid); +#endif + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_set_max_history(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_WRITE, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + return rsbac_um_set_max_history(ta_number, uid, max_history); +#else + return -RSBAC_EINVALIDMODULE; +#endif + } + +int sys_rsbac_um_set_max_history_name(rsbac_list_ta_number_t ta_number, char __user * name, __u8 max_history) + { +#ifdef CONFIG_RSBAC_UM_PWHISTORY + int err; + rsbac_uid_t uid = RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP, RSBAC_NO_USER); + char k_name[RSBAC_MAXNAMELEN]; + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if(!name) + return -RSBAC_EINVALIDPOINTER; + err = strncpy_from_user(k_name, name, RSBAC_MAXNAMELEN); + if(unlikely(err < 0)) + return err; + k_name[RSBAC_MAXNAMELEN-1] = 0; +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_set_max_history_name(): setting max_history of user %s\n", + k_name); + } +#endif + err = rsbac_um_get_uid(0, k_name, &uid); + if(err) + { +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef_um) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_set_max_history_name(): lookup of user %s failed\n", + k_name); + } +#endif + if(err == -RSBAC_ENOTFOUND) + err = -EPERM; + return err; + } + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + rsbac_printk(KERN_DEBUG "sys_rsbac_um_set_max_history_name(): calling ADF\n"); + } +#endif + rsbac_target_id.user = uid; + rsbac_attribute_value.dummy = 0; + if (!rsbac_adf_request(R_WRITE, + task_pid(current), + T_USER, + rsbac_target_id, + A_none, + rsbac_attribute_value)) + { + return -EPERM; + } + + return rsbac_um_set_max_history(ta_number, uid, max_history); +#else + return -RSBAC_EINVALIDMODULE; +#endif + } + +int sys_rsbac_um_select_vset(rsbac_um_set_t vset) + { +#if defined(CONFIG_RSBAC_UM_VIRTUAL) + union rsbac_target_id_t rsbac_target_id; + union rsbac_target_id_t rsbac_new_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if (vset > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; + +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_um_select_vset(): calling ADF\n"); +#endif + rsbac_target_id.process = task_pid(current); + rsbac_attribute_value.owner = RSBAC_GEN_UID(vset, __kuid_val(current_uid())); + if (!rsbac_adf_request(R_CHANGE_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + A_owner, + rsbac_attribute_value)) + { + return -EPERM; + } + + rsbac_pr_debug(aef_um, "Switching process %u to vset %u\n", + current->pid, vset); + rsbac_target_id.process = task_pid(current); + rsbac_attribute_value.vset = vset; + if (rsbac_set_attr(SW_GEN, + T_PROCESS, + rsbac_target_id, + A_vset, + rsbac_attribute_value)) + { + rsbac_ds_set_error("sys_rsbac_um_select_vset()", A_vset); + } + else + { + rsbac_target_id.process = task_pid(current); + rsbac_attribute_value.owner = RSBAC_GEN_UID(vset, __kuid_val(current_uid())); + rsbac_new_target_id.dummy = 0; + if (rsbac_adf_set_attr(R_CHANGE_OWNER, + task_pid(current), + T_PROCESS, + rsbac_target_id, + T_NONE, + rsbac_new_target_id, + A_owner, + rsbac_attribute_value)) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_um_select_vset(): rsbac_adf_set_attr() returned error\n"); + } + } + return 0; +#else + return -RSBAC_EINVALIDMODULE; +#endif + } +#endif + +/************** UDF ***************/ + +#ifdef CONFIG_RSBAC_UDF +int sys_rsbac_udf_flush_cache(void) + { +#ifndef CONFIG_RSBAC_UDF_CACHE + return 0; +#else + union rsbac_target_id_t i_tid; + union rsbac_attribute_value_t i_attr_val1; + + /* Security Officer or admin? */ + i_tid.user = __kuid_val(current_uid()); + if (rsbac_get_attr(SW_UDF, + T_USER, + i_tid, + A_udf_role, + &i_attr_val1, + TRUE)) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_udf_flush_cache(): rsbac_get_attr() returned error!\n"); + return -EPERM; + } + /* if not sec_officer or admin, deny */ + if ( (i_attr_val1.system_role != SR_security_officer) + && (i_attr_val1.system_role != SR_administrator) + ) + #ifdef CONFIG_RSBAC_SOFTMODE + if( !rsbac_softmode + #ifdef CONFIG_RSBAC_SOFTMODE_IND + && !rsbac_ind_softmode[SW_UDF] + #endif + ) + #endif + return -EPERM; + + rsbac_printk(KERN_INFO + "sys_rsbac_udf_flush_cache(): flushing UDF result cache!\n"); + + return rsbac_udf_flush_cache(); +#endif + } +#endif + + +/************************************************* */ +/* DEBUG/LOG functions */ +/************************************************* */ + +int sys_rsbac_adf_log_switch(enum rsbac_adf_request_t request, + enum rsbac_target_t target, + u_int value) + { + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + + if ((value != LL_none) && (value != LL_denied) && (value != LL_full)) + return -RSBAC_EINVALIDVALUE; + if(request >= R_NONE) + return -RSBAC_EINVALIDREQUEST; + if( (target == T_FD) + || (target > T_NONE) + ) + return -RSBAC_EINVALIDTARGET; + +#ifdef CONFIG_RSBAC_FREEZE + if(rsbac_freeze) + { + rsbac_printk(KERN_WARNING + "sys_rsbac_adf_log_switch(): RSBAC configuration frozen, no administration allowed!\n"); + return -EPERM; + } +#endif + + /* call ADF */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_adf_log_switch(): calling ADF\n"); +#endif + rsbac_target_id.dummy = 0; + rsbac_attribute_value.request = target; + if (!rsbac_adf_request(R_SWITCH_LOG, + task_pid(current), + T_NONE, + rsbac_target_id, + A_request, + rsbac_attribute_value)) + { + return -EPERM; + } +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + char * request_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(request_name) + { + get_request_name(request_name,target); + rsbac_printk(KERN_INFO "sys_rsbac_adf_log_switch(): switching RSBAC module logging for request %s (No. %i) to %i!\n", + request_name, target, value); + rsbac_kfree(request_name); + } + } +#endif + rsbac_adf_log_switch(request,target,value); + return 0; + } + +int sys_rsbac_get_adf_log(enum rsbac_adf_request_t request, + enum rsbac_target_t target, + u_int __user * value_p) + { + union rsbac_target_id_t rsbac_target_id; + union rsbac_attribute_value_t rsbac_attribute_value; + u_int k_value; + int err; + + if(request >= R_NONE) + return -RSBAC_EINVALIDREQUEST; + if( (target == T_FD) + || (target > T_NONE) + ) + return -RSBAC_EINVALIDTARGET; + if(!value_p) + return -RSBAC_EINVALIDPOINTER; + /* call ADF */ +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + rsbac_printk(KERN_DEBUG "sys_rsbac_get_adf_log(): calling ADF\n"); +#endif + rsbac_target_id.scd = ST_rsbac; + rsbac_attribute_value.request = request; + if (!rsbac_adf_request(R_GET_STATUS_DATA, + task_pid(current), + T_SCD, + rsbac_target_id, + A_request, + rsbac_attribute_value)) + { + return -EPERM; + } +#ifdef CONFIG_RSBAC_DEBUG + if (rsbac_debug_aef) + { + char * request_name = rsbac_kmalloc_unlocked(RSBAC_MAXNAMELEN); + if(request_name) + { + get_request_name(request_name,target); + rsbac_printk(KERN_DEBUG "sys_rsbac_get_adf_log(): getting RSBAC module logging for request %s (No. %i)!\n", + request_name, target); + rsbac_kfree(request_name); + } + } +#endif + err = rsbac_get_adf_log(request, target, &k_value); + if(!err) + { + rsbac_put_user(&k_value, + value_p, + sizeof(k_value) ); + } + return err; + } + +/* + * Commands to sys_rsbac_log: + * + * 0 -- Close the log. Currently a NOP. + * 1 -- Open the log. Currently a NOP. + * 2 -- Read from the log. + * 3 -- Read up to the last 4k of messages in the ring buffer. + * 4 -- Read and clear last 4k of messages in the ring buffer + * 5 -- Clear ring buffer. + */ +int sys_rsbac_log(int type, + char __user * buf, + int len) + { +#if defined(CONFIG_RSBAC_RMSG) + return rsbac_log(type,buf,len); +#else + return 0; +#endif /* RMSG */ + } + +#if defined(CONFIG_RSBAC_INIT_DELAY) +int sys_rsbac_init(char __user * path) + { + struct dentry * t_dentry = NULL; + rsbac_boolean_t need_put = FALSE; + int err = 0; + + struct path ppath; + + if(!path) + return rsbac_init(ROOT_DEV); + + if ((err = user_lpath(path, &ppath))) + { + goto out; + } + t_dentry = ppath.dentry; + need_put = TRUE; + if (!t_dentry->d_inode) + { + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + /* is inode of type file, symlink or block/char device? */ + if(!S_ISBLK(t_dentry->d_inode->i_mode)) + { /* This is no file or device */ + err = -RSBAC_EINVALIDTARGET; + goto out_dput; + } + err = rsbac_init(t_dentry->d_sb->s_dev); + +out_dput: + if(need_put) + path_put(&ppath); +out: + return err; + } +#endif + +#ifdef CONFIG_RSBAC_LIST_TRANS +int sys_rsbac_list_ta_begin_name( + rsbac_time_t ttl, + rsbac_list_ta_number_t __user * ta_number_p, + rsbac_uid_t commit_uid, + char __user * name, + char __user * password) + { + int err; + rsbac_list_ta_number_t k_ta_number = 0; + char * k_name = NULL; + char * k_password = NULL; + +#ifdef CONFIG_RSBAC_UM_VIRTUAL + if (RSBAC_UID_SET(commit_uid) == RSBAC_UM_VIRTUAL_KEEP) + commit_uid = RSBAC_GEN_UID (rsbac_get_vset(), RSBAC_UID_NUM(commit_uid)); + else + if (RSBAC_UID_SET(commit_uid) > RSBAC_UM_VIRTUAL_MAX) + return -RSBAC_EINVALIDVALUE; +#else + commit_uid = RSBAC_UID_NUM(commit_uid); +#endif + if(name) + { + k_name = rsbac_kmalloc_unlocked(RSBAC_LIST_TA_MAX_NAMELEN); + if(!k_name) + return -ENOMEM; + err = strncpy_from_user(k_name, name, RSBAC_LIST_TA_MAX_NAMELEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_name); + return err; + } + k_name[RSBAC_LIST_TA_MAX_NAMELEN - 1] = 0; + } + if(password) + { + k_password = rsbac_kmalloc_unlocked(RSBAC_LIST_TA_MAX_PASSLEN); + if(!k_password) + return -ENOMEM; + err = strncpy_from_user(k_password, password, RSBAC_LIST_TA_MAX_PASSLEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_password); + return err; + } + k_password[RSBAC_LIST_TA_MAX_PASSLEN - 1] = 0; + } + err = rsbac_list_ta_begin(ttl, &k_ta_number, commit_uid, k_name, k_password); + if(!err) + err = rsbac_put_user(&k_ta_number, + ta_number_p, + sizeof(k_ta_number) ); + if(k_name) + rsbac_kfree(k_name); + if(k_password) + rsbac_kfree(k_password); + return err; + } + +int sys_rsbac_list_ta_begin( + rsbac_time_t ttl, + rsbac_list_ta_number_t __user * ta_number_p, + rsbac_uid_t commit_uid, + char __user * password) + { + return sys_rsbac_list_ta_begin_name(ttl, ta_number_p, commit_uid, NULL, password); + } + +int sys_rsbac_list_ta_refresh( + rsbac_time_t ttl, + rsbac_list_ta_number_t ta_number, + char __user * password) + { + int err; + char * k_password; + + if(password) + { + k_password = rsbac_kmalloc_unlocked(RSBAC_LIST_TA_MAX_PASSLEN); + if(!k_password) + return -ENOMEM; + err = strncpy_from_user(k_password, password, RSBAC_LIST_TA_MAX_PASSLEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_password); + return err; + } + k_password[RSBAC_LIST_TA_MAX_PASSLEN - 1] = 0; + } + else + k_password = NULL; + err = rsbac_list_ta_refresh(ttl, ta_number, k_password); + if(k_password) + rsbac_kfree(k_password); + return err; + } + +int sys_rsbac_list_ta_commit( + rsbac_list_ta_number_t ta_number, + char __user * password) + { + int err; + char * k_password; + + if(password) + { + k_password = rsbac_kmalloc_unlocked(RSBAC_LIST_TA_MAX_PASSLEN); + if(!k_password) + return -ENOMEM; + err = strncpy_from_user(k_password, password, RSBAC_LIST_TA_MAX_PASSLEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_password); + return err; + } + k_password[RSBAC_LIST_TA_MAX_PASSLEN - 1] = 0; + } + else + k_password = NULL; + err = rsbac_list_ta_commit(ta_number, k_password); + if(k_password) + rsbac_kfree(k_password); + return err; + } + +int sys_rsbac_list_ta_forget( + rsbac_list_ta_number_t ta_number, + char __user * password) + { + int err; + char * k_password; + + if(password) + { + k_password = rsbac_kmalloc_unlocked(RSBAC_LIST_TA_MAX_PASSLEN); + if(!k_password) + return -ENOMEM; + err = strncpy_from_user(k_password, password, RSBAC_LIST_TA_MAX_PASSLEN); + if(unlikely(err < 0)) + { + rsbac_kfree(k_password); + return err; + } + k_password[RSBAC_LIST_TA_MAX_PASSLEN - 1] = 0; + } + else + k_password = NULL; + err = rsbac_list_ta_forget(ta_number, k_password); + if(k_password) + rsbac_kfree(k_password); + return err; + } +#endif + +/* Big dispatcher for all syscalls */ +#ifdef rsbac_syscall4 +asmlinkage int sys_rsbac(int dummy, + rsbac_version_t version, + enum rsbac_syscall_t call, + union rsbac_syscall_arg_t __user * arg_p) +#else +asmlinkage int sys_rsbac(rsbac_version_t version, + enum rsbac_syscall_t call, + union rsbac_syscall_arg_t __user * arg_p) +#endif + { + int err; + + if( (!rsbac_initialized) && (call != RSYS_init) ) { + rsbac_printk(KERN_WARNING "sys_rsbac(): RSBAC not initialized\n"); + return -RSBAC_ENOTINITIALIZED; + } + + if ( ( (version < RSBAC_API_MIN_VERSION_NR) + || (version > RSBAC_API_MAX_VERSION_NR) + ) + && (call != RSYS_version) + && (call != RSYS_api_min_version) + && (call != RSYS_api_max_version) + ) + return -RSBAC_EINVALIDVERSION; + + if(call >= RSYS_none) + return -RSBAC_EINVALIDREQUEST; + +#ifdef CONFIG_RSBAC_XSTATS + syscall_count[call]++; +#endif + +#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32) + if((current->thread.status & TS_COMPAT) || test_thread_flag(TIF_IA32)) { + union rsbac_syscall_arg_ia32_t k_arg; + + /* get values from user space */ + if(arg_p) + { + err = rsbac_get_user(&k_arg, arg_p, sizeof(k_arg) ); + if(unlikely(err < 0)) + return err; + } + else + { + memset(&k_arg, 0, sizeof(k_arg)); + } + + switch(call) + { +#ifdef CONFIG_RSBAC_UM + case RSYS_um_get_user_item: + return sys_rsbac_um_get_user_item(k_arg.um_get_user_item.ta_number, + k_arg.um_get_user_item.uid, + k_arg.um_get_user_item.mod, + (void __user *)(long)k_arg.um_get_user_item.data_p); + case RSYS_um_get_uid: + return sys_rsbac_um_get_uid(k_arg.um_get_uid.ta_number, + (void __user *)(long)k_arg.um_get_uid.name, + (void __user *)(long)k_arg.um_get_uid.uid_p); + case RSYS_um_get_group_item: + return sys_rsbac_um_get_group_item(k_arg.um_get_group_item.ta_number, + k_arg.um_get_group_item.gid, + k_arg.um_get_group_item.mod, + (void __user *)(long)k_arg.um_get_group_item.data_p); + case RSYS_um_get_gm_list: + return sys_rsbac_um_get_gm_list(k_arg.um_get_gm_list.ta_number, + k_arg.um_get_gm_list.user, + (void __user *)(long)k_arg.um_get_gm_list.group_array, + k_arg.um_get_gm_list.maxnum); + case RSYS_um_get_gm_user_list: + return sys_rsbac_um_get_gm_user_list(k_arg.um_get_gm_user_list.ta_number, + k_arg.um_get_gm_user_list.group, + (void __user *)(long)k_arg.um_get_gm_user_list.user_array, + k_arg.um_get_gm_user_list.maxnum); + case RSYS_um_get_gid: + return sys_rsbac_um_get_gid(k_arg.um_get_gid.ta_number, + (void __user *)(long)k_arg.um_get_gid.name, + (void __user *)(long)k_arg.um_get_gid.gid_p); + case RSYS_um_get_user_list: + return sys_rsbac_um_get_user_list(k_arg.um_get_user_list.ta_number, + k_arg.um_get_user_list.vset, + (void __user *)(long)k_arg.um_get_user_list.user_array, + k_arg.um_get_user_list.maxnum); + case RSYS_um_check_account_name: + return sys_rsbac_um_check_account_name((void __user *)(long)k_arg.um_check_account_name.name); +#endif + case RSYS_get_attr: + return sys_rsbac_get_attr(k_arg.get_attr.ta_number, + k_arg.get_attr.module, + k_arg.get_attr.target, + (void __user *)(long)k_arg.get_attr.tid, + k_arg.get_attr.attr, + (void __user *)(long)k_arg.get_attr.value, + k_arg.get_attr.inherit); + case RSYS_get_attr_n: + return sys_rsbac_get_attr_n(k_arg.get_attr_n.ta_number, + k_arg.get_attr_n.module, + k_arg.get_attr_n.target, + (void __user *)(long)k_arg.get_attr_n.t_name, + k_arg.get_attr_n.attr, + (void __user *)(long)k_arg.get_attr_n.value, + k_arg.get_attr_n.inherit); + case RSYS_set_attr: + return sys_rsbac_set_attr(k_arg.set_attr.ta_number, + k_arg.set_attr.module, + k_arg.set_attr.target, + (void __user *)(long)k_arg.set_attr.tid, + k_arg.set_attr.attr, + (void __user *)(long)k_arg.set_attr.value); + case RSYS_set_attr_n: + return sys_rsbac_set_attr_n(k_arg.set_attr_n.ta_number, + k_arg.set_attr_n.module, + k_arg.set_attr_n.target, + (void __user *)(long)k_arg.set_attr_n.t_name, + k_arg.set_attr_n.attr, + (void __user *)(long)k_arg.set_attr_n.value); +#ifdef CONFIG_RSBAC_RC + case RSYS_rc_get_current_role: + return sys_rsbac_rc_get_current_role((void __user *)(long)k_arg.rc_get_current_role.role_p); + case RSYS_rc_get_item: + return sys_rsbac_rc_get_item(k_arg.rc_get_item.ta_number, + k_arg.rc_get_item.target, + (void __user *)(long)k_arg.rc_get_item.tid_p, + (void __user *)(long)k_arg.rc_get_item.subtid_p, + k_arg.rc_get_item.item, + (void __user *)(long)k_arg.rc_get_item.value_p, + (void __user *)(long)k_arg.rc_get_item.ttl_p); + case RSYS_rc_change_role: + return sys_rsbac_rc_change_role(k_arg.rc_change_role.role, + (void __user *)(long)k_arg.rc_change_role.pass); +#endif +#ifdef CONFIG_RSBAC_JAIL + case RSYS_jail: + return rsbac_jail_sys_jail(k_arg.jail.version, + (void __user *)(long)k_arg.jail.path, + k_arg.jail.ip, + k_arg.jail.flags, + k_arg.jail.max_caps, + k_arg.jail.scd_get, + k_arg.jail.scd_modify); +#endif + + case RSYS_remove_target: + return sys_rsbac_remove_target(k_arg.remove_target.ta_number, + k_arg.remove_target.target, + (void __user *)(long)k_arg.remove_target.tid); + case RSYS_remove_target_n: + return sys_rsbac_remove_target_n(k_arg.remove_target_n.ta_number, + k_arg.remove_target_n.target, + (void __user *)(long)k_arg.remove_target_n.t_name); + case RSYS_net_list_all_netdev: + return sys_rsbac_net_list_all_netdev(k_arg.net_list_all_netdev.ta_number, + (void __user *)(long)k_arg.net_list_all_netdev.id_p, + k_arg.net_list_all_netdev.maxnum); + case RSYS_net_template: + return sys_rsbac_net_template(k_arg.net_template.ta_number, + k_arg.net_template.call, + k_arg.net_template.id, + (void __user *)(long)k_arg.net_template.data_p); + case RSYS_net_list_all_template: + return sys_rsbac_net_list_all_template(k_arg.net_list_all_template.ta_number, + (void __user *)(long)k_arg.net_list_all_template.id_p, + k_arg.net_list_all_template.maxnum); + case RSYS_switch: + return sys_rsbac_switch(k_arg.switch_module.module, + k_arg.switch_module.value); + case RSYS_get_switch: + return sys_rsbac_get_switch(k_arg.get_switch_module.module, + (void __user *)(long)k_arg.get_switch_module.value_p, + (void __user *)(long)k_arg.get_switch_module.switchable_p); + case RSYS_adf_log_switch: + return sys_rsbac_adf_log_switch(k_arg.adf_log_switch.request, + k_arg.adf_log_switch.target, + k_arg.adf_log_switch.value); + case RSYS_get_adf_log: + return sys_rsbac_get_adf_log(k_arg.get_adf_log.request, + k_arg.get_adf_log.target, + (void __user *)(long)k_arg.get_adf_log.value_p); + case RSYS_write: + return sys_rsbac_write(); + case RSYS_log: + return sys_rsbac_log(k_arg.log.type, + (void __user *)(long)k_arg.log.buf, + k_arg.log.len); +#ifdef CONFIG_RSBAC_MAC + case RSYS_mac_set_curr_level: + return sys_rsbac_mac_set_curr_level(k_arg.mac_set_curr_level.level, + (void __user *)(long)k_arg.mac_set_curr_level.categories_p); + case RSYS_mac_get_curr_level: + return sys_rsbac_mac_get_curr_level((void __user *)(long)k_arg.mac_get_curr_level.level_p, + (void __user *)(long)k_arg.mac_get_curr_level.categories_p); + case RSYS_mac_get_max_level: + return sys_rsbac_mac_get_max_level((void __user *)(long)k_arg.mac_get_max_level.level_p, + (void __user *)(long)k_arg.mac_get_max_level.categories_p); + case RSYS_mac_get_min_level: + return sys_rsbac_mac_get_min_level((void __user *)(long)k_arg.mac_get_min_level.level_p, + (void __user *)(long)k_arg.mac_get_min_level.categories_p); + case RSYS_mac_add_p_tru: + return sys_rsbac_mac_add_p_tru(k_arg.mac_add_p_tru.ta_number, + k_arg.mac_add_p_tru.pid, + k_arg.mac_add_p_tru.uid, + k_arg.mac_add_p_tru.ttl); + case RSYS_mac_remove_p_tru: + return sys_rsbac_mac_remove_p_tru(k_arg.mac_remove_p_tru.ta_number, + k_arg.mac_remove_p_tru.pid, + k_arg.mac_add_p_tru.uid); + case RSYS_mac_add_f_tru: + return sys_rsbac_mac_add_f_tru(k_arg.mac_add_f_tru.ta_number, + (void __user *)(long)k_arg.mac_add_f_tru.filename, + k_arg.mac_add_p_tru.uid, + k_arg.mac_add_f_tru.ttl); + case RSYS_mac_remove_f_tru: + return sys_rsbac_mac_remove_f_tru(k_arg.mac_remove_f_tru.ta_number, + (void __user *)(long)k_arg.mac_remove_f_tru.filename, + k_arg.mac_remove_f_tru.uid); + case RSYS_mac_get_f_trulist: + return sys_rsbac_mac_get_f_trulist(k_arg.mac_get_f_trulist.ta_number, + (void __user *)(long)k_arg.mac_get_f_trulist.filename, + (void __user *)(long)k_arg.mac_get_f_trulist.trulist, + (void __user *)(long)k_arg.mac_get_f_trulist.ttllist, + k_arg.mac_get_f_trulist.maxnum); + case RSYS_mac_get_p_trulist: + return sys_rsbac_mac_get_p_trulist(k_arg.mac_get_p_trulist.ta_number, + k_arg.mac_get_p_trulist.pid, + (void __user *)(long)k_arg.mac_get_p_trulist.trulist, + (void __user *)(long)k_arg.mac_get_p_trulist.ttllist, + k_arg.mac_get_p_trulist.maxnum); +#endif +#ifdef CONFIG_RSBAC_DAZ + case RSYS_daz_flush_cache: + return sys_rsbac_daz_flush_cache(); +#endif +#ifdef CONFIG_RSBAC_RC + case RSYS_rc_copy_role: + return sys_rsbac_rc_copy_role(k_arg.rc_copy_role.ta_number, + k_arg.rc_copy_role.from_role, + k_arg.rc_copy_role.to_role); + case RSYS_rc_copy_type: + return sys_rsbac_rc_copy_type(k_arg.rc_copy_type.ta_number, + k_arg.rc_copy_type.target, + k_arg.rc_copy_type.from_type, + k_arg.rc_copy_type.to_type); + case RSYS_rc_set_item: + return sys_rsbac_rc_set_item(k_arg.rc_set_item.ta_number, + k_arg.rc_set_item.target, + (void __user *)(long)k_arg.rc_set_item.tid_p, + (void __user *)(long)k_arg.rc_set_item.subtid_p, + k_arg.rc_set_item.item, + (void __user *)(long)k_arg.rc_set_item.value_p, + k_arg.rc_set_item.ttl); + case RSYS_rc_get_eff_rights_n: + return sys_rsbac_rc_get_eff_rights_n(k_arg.rc_get_eff_rights_n.ta_number, + k_arg.rc_get_eff_rights_n.target, + (void __user *)(long)k_arg.rc_get_eff_rights_n.t_name, + (void __user *)(long)k_arg.rc_get_eff_rights_n.request_vector_p, + (void __user *)(long)k_arg.rc_get_eff_rights_n.ttl_p); + case RSYS_rc_get_list: + return sys_rsbac_rc_get_list(k_arg.rc_get_list.ta_number, + k_arg.rc_get_list.target, + (void __user *)(long)k_arg.rc_get_list.tid_p, + k_arg.rc_get_list.item, + k_arg.rc_get_list.maxnum, + (void __user *)(long)k_arg.rc_get_list.array_p, + (void __user *)(long)k_arg.rc_get_list.ttl_array_p); + case RSYS_rc_select_fd_create_type: + return sys_rsbac_rc_select_fd_create_type(k_arg.rc_select_fd_create_type.type); +#endif +#ifdef CONFIG_RSBAC_AUTH + case RSYS_auth_add_p_cap: + { + struct rsbac_auth_cap_range_t cap_range_64; + + cap_range_64.first = k_arg.auth_add_p_cap.cap_range.first; + cap_range_64.last = k_arg.auth_add_p_cap.cap_range.last; + return sys_rsbac_auth_add_p_cap(k_arg.auth_add_p_cap.ta_number, + k_arg.auth_add_p_cap.pid, + k_arg.auth_add_p_cap.cap_type, + cap_range_64, + k_arg.auth_add_p_cap.ttl); + } + case RSYS_auth_remove_p_cap: + { + struct rsbac_auth_cap_range_t cap_range_64; + + cap_range_64.first = k_arg.auth_add_p_cap.cap_range.first; + cap_range_64.last = k_arg.auth_add_p_cap.cap_range.last; + return sys_rsbac_auth_remove_p_cap(k_arg.auth_remove_p_cap.ta_number, + k_arg.auth_remove_p_cap.pid, + k_arg.auth_remove_p_cap.cap_type, + cap_range_64); + } + case RSYS_auth_add_f_cap: + { + struct rsbac_auth_cap_range_t cap_range_64; + + cap_range_64.first = k_arg.auth_add_p_cap.cap_range.first; + cap_range_64.last = k_arg.auth_add_p_cap.cap_range.last; + return sys_rsbac_auth_add_f_cap(k_arg.auth_add_f_cap.ta_number, + (void __user *)(long)k_arg.auth_add_f_cap.filename, + k_arg.auth_add_f_cap.cap_type, + cap_range_64, + k_arg.auth_add_f_cap.ttl); + } + case RSYS_auth_remove_f_cap: + { + struct rsbac_auth_cap_range_t cap_range_64; + + cap_range_64.first = k_arg.auth_add_p_cap.cap_range.first; + cap_range_64.last = k_arg.auth_add_p_cap.cap_range.last; + return sys_rsbac_auth_remove_f_cap(k_arg.auth_remove_f_cap.ta_number, + (void __user *)(long)k_arg.auth_remove_f_cap.filename, + k_arg.auth_remove_f_cap.cap_type, + cap_range_64); + } + case RSYS_auth_get_f_caplist: + return sys_rsbac_auth_get_f_caplist(k_arg.auth_get_f_caplist.ta_number, + (void __user *)(long)k_arg.auth_get_f_caplist.filename, + k_arg.auth_get_f_caplist.cap_type, + (void __user *)(long)k_arg.auth_get_f_caplist.caplist, + (void __user *)(long)k_arg.auth_get_f_caplist.ttllist, + k_arg.auth_get_f_caplist.maxnum); + case RSYS_auth_get_p_caplist: + return sys_rsbac_auth_get_p_caplist(k_arg.auth_get_p_caplist.ta_number, + k_arg.auth_get_p_caplist.pid, + k_arg.auth_get_p_caplist.cap_type, + (void __user *)(long)k_arg.auth_get_p_caplist.caplist, + (void __user *)(long)k_arg.auth_get_p_caplist.ttllist, + k_arg.auth_get_p_caplist.maxnum); +#endif +#ifdef CONFIG_RSBAC_ACL + case RSYS_acl: + return sys_rsbac_acl(k_arg.acl.ta_number, + k_arg.acl.call, + (void __user *)(long)k_arg.acl.arg); + case RSYS_acl_n: + return sys_rsbac_acl_n(k_arg.acl_n.ta_number, + k_arg.acl_n.call, + (void __user *)(long)k_arg.acl_n.arg); + case RSYS_acl_get_rights: + return sys_rsbac_acl_get_rights(k_arg.acl_get_rights.ta_number, + (void __user *)(long)k_arg.acl_get_rights.arg, + (void __user *)(long)k_arg.acl_get_rights.rights_p, + k_arg.acl_get_rights.effective); + case RSYS_acl_get_rights_n: + return sys_rsbac_acl_get_rights_n(k_arg.acl_get_rights_n.ta_number, + (void __user *)(long)k_arg.acl_get_rights_n.arg, + (void __user *)(long)k_arg.acl_get_rights_n.rights_p, + k_arg.acl_get_rights_n.effective); + case RSYS_acl_get_tlist: + return sys_rsbac_acl_get_tlist(k_arg.acl_get_tlist.ta_number, + k_arg.acl_get_tlist.target, + (void __user *)(long)k_arg.acl_get_tlist.tid, + (void __user *)(long)k_arg.acl_get_tlist.entry_array, + (void __user *)(long)k_arg.acl_get_tlist.ttl_array, + k_arg.acl_get_tlist.maxnum); + case RSYS_acl_get_tlist_n: + return sys_rsbac_acl_get_tlist_n(k_arg.acl_get_tlist_n.ta_number, + k_arg.acl_get_tlist_n.target, + (void __user *)(long)k_arg.acl_get_tlist_n.t_name, + (void __user *)(long)k_arg.acl_get_tlist_n.entry_array, + (void __user *)(long)k_arg.acl_get_tlist_n.ttl_array, + k_arg.acl_get_tlist_n.maxnum); + case RSYS_acl_get_mask: + return sys_rsbac_acl_get_mask(k_arg.acl_get_mask.ta_number, + k_arg.acl_get_mask.target, + (void __user *)(long)k_arg.acl_get_mask.tid, + (void __user *)(long)k_arg.acl_get_mask.mask_p); + case RSYS_acl_get_mask_n: + return sys_rsbac_acl_get_mask_n(k_arg.acl_get_mask_n.ta_number, + k_arg.acl_get_mask_n.target, + (void __user *)(long)k_arg.acl_get_mask_n.t_name, + (void __user *)(long)k_arg.acl_get_mask_n.mask_p); + case RSYS_acl_group: + return sys_rsbac_acl_group(k_arg.acl_group.ta_number, + k_arg.acl_group.call, + (void __user *)(long)k_arg.acl_group.arg_p); + case RSYS_acl_list_all_dev: + return sys_rsbac_acl_list_all_dev(k_arg.acl_list_all_dev.ta_number, + (void __user *)(long)k_arg.acl_list_all_dev.id_p, + k_arg.acl_list_all_dev.maxnum); + case RSYS_acl_list_all_user: + return sys_rsbac_acl_list_all_user(k_arg.acl_list_all_user.ta_number, + (void __user *)(long)k_arg.acl_list_all_user.id_p, + k_arg.acl_list_all_user.maxnum); + case RSYS_acl_list_all_group: + return sys_rsbac_acl_list_all_group(k_arg.acl_list_all_group.ta_number, + (void __user *)(long)k_arg.acl_list_all_group.id_p, + k_arg.acl_list_all_group.maxnum); +#endif +#ifdef CONFIG_RSBAC_REG + case RSYS_reg: + return sys_rsbac_reg(k_arg.reg.handle, + (void __user *)(long)k_arg.reg.arg); +#endif +#ifdef CONFIG_RSBAC_UM + case RSYS_um_auth_name: + return sys_rsbac_um_auth_name((void __user *)(long)k_arg.um_auth_name.name, + (void __user *)(long)k_arg.um_auth_name.pass); + case RSYS_um_auth_uid: + return sys_rsbac_um_auth_uid(k_arg.um_auth_uid.uid, + (void __user *)(long)k_arg.um_auth_uid.pass); + case RSYS_um_add_user: + return sys_rsbac_um_add_user(k_arg.um_add_user.ta_number, + k_arg.um_add_user.uid, + (void __user *)(long)k_arg.um_add_user.entry_p, + (void __user *)(long)k_arg.um_add_user.pass, + k_arg.um_add_user.ttl); + case RSYS_um_add_group: + return sys_rsbac_um_add_group(k_arg.um_add_group.ta_number, + k_arg.um_add_group.gid, + (void __user *)(long)k_arg.um_add_group.entry_p, + (void __user *)(long)k_arg.um_add_group.pass, + k_arg.um_add_group.ttl); + case RSYS_um_add_gm: + return sys_rsbac_um_add_gm(k_arg.um_add_gm.ta_number, + k_arg.um_add_gm.uid, + k_arg.um_add_gm.gid, + k_arg.um_add_gm.ttl); + case RSYS_um_mod_user: + return sys_rsbac_um_mod_user(k_arg.um_mod_user.ta_number, + k_arg.um_mod_user.uid, + k_arg.um_mod_user.mod, + (void __user *)(long)k_arg.um_mod_user.data_p); + case RSYS_um_mod_group: + return sys_rsbac_um_mod_group(k_arg.um_mod_group.ta_number, + k_arg.um_mod_group.gid, + k_arg.um_mod_group.mod, + (void __user *)(long)k_arg.um_mod_group.data_p); + case RSYS_um_remove_user: + return sys_rsbac_um_remove_user(k_arg.um_remove_user.ta_number, + k_arg.um_remove_user.uid); + case RSYS_um_remove_group: + return sys_rsbac_um_remove_group(k_arg.um_remove_group.ta_number, + k_arg.um_remove_group.gid); + case RSYS_um_remove_gm: + return sys_rsbac_um_remove_gm(k_arg.um_remove_gm.ta_number, + k_arg.um_remove_gm.uid, + k_arg.um_remove_gm.gid); + case RSYS_um_user_exists: + return sys_rsbac_um_user_exists(k_arg.um_user_exists.ta_number, + k_arg.um_user_exists.uid); + case RSYS_um_get_next_user: + return sys_rsbac_um_get_next_user(k_arg.um_get_next_user.ta_number, + k_arg.um_get_next_user.old_user, + (void __user *)(long)k_arg.um_get_next_user.next_user_p); + case RSYS_um_group_exists: + return sys_rsbac_um_group_exists(k_arg.um_group_exists.ta_number, + k_arg.um_group_exists.gid); + case RSYS_um_get_group_list: + return sys_rsbac_um_get_group_list(k_arg.um_get_group_list.ta_number, + k_arg.um_get_group_list.vset, + (void __user *)(long)k_arg.um_get_group_list.group_array, + k_arg.um_get_group_list.maxnum); + case RSYS_um_set_pass: + return sys_rsbac_um_set_pass(k_arg.um_set_pass.uid, + (void __user *)(long)k_arg.um_set_pass.old_pass, + (void __user *)(long)k_arg.um_set_pass.new_pass); + case RSYS_um_set_pass_name: + return sys_rsbac_um_set_pass_name((void __user *)(long)k_arg.um_set_pass_name.name, + (void __user *)(long)k_arg.um_set_pass_name.old_pass, + (void __user *)(long)k_arg.um_set_pass_name.new_pass); + case RSYS_um_add_onetime: + return sys_rsbac_um_add_onetime(k_arg.um_add_onetime.uid, + (void __user *)(long)k_arg.um_add_onetime.old_pass, + (void __user *)(long)k_arg.um_add_onetime.new_pass, + k_arg.um_add_onetime.ttl); + case RSYS_um_add_onetime_name: + return sys_rsbac_um_add_onetime_name((void __user *)(long)k_arg.um_add_onetime_name.name, + (void __user *)(long)k_arg.um_add_onetime_name.old_pass, + (void __user *)(long)k_arg.um_add_onetime_name.new_pass, + k_arg.um_add_onetime_name.ttl); + case RSYS_um_remove_all_onetime: + return sys_rsbac_um_remove_all_onetime(k_arg.um_remove_all_onetime.uid, + (void __user *)(long)k_arg.um_remove_all_onetime.old_pass); + case RSYS_um_remove_all_onetime_name: + return sys_rsbac_um_remove_all_onetime_name((void __user *)(long)k_arg.um_remove_all_onetime_name.name, + (void __user *)(long)k_arg.um_remove_all_onetime_name.old_pass); + case RSYS_um_count_onetime: + return sys_rsbac_um_count_onetime(k_arg.um_count_onetime.uid, + (void __user *)(long)k_arg.um_count_onetime.old_pass); + case RSYS_um_count_onetime_name: + return sys_rsbac_um_count_onetime_name((void __user *)(long)k_arg.um_count_onetime_name.name, + (void __user *)(long)k_arg.um_count_onetime_name.old_pass); + case RSYS_um_set_group_pass: + return sys_rsbac_um_set_group_pass(k_arg.um_set_group_pass.gid, + (void __user *)(long)k_arg.um_set_group_pass.new_pass); + case RSYS_um_check_account: + return sys_rsbac_um_check_account(k_arg.um_check_account.uid); + case RSYS_um_get_max_history: + return sys_rsbac_um_get_max_history(k_arg.um_get_max_history.ta_number, + k_arg.um_get_max_history.uid); + case RSYS_um_get_max_history_name: + return sys_rsbac_um_get_max_history_name(k_arg.um_get_max_history_name.ta_number, + (void __user *)(long)k_arg.um_get_max_history_name.name); + case RSYS_um_set_max_history: + return sys_rsbac_um_set_max_history(k_arg.um_set_max_history.ta_number, + k_arg.um_set_max_history.uid, + k_arg.um_set_max_history.max_history); + case RSYS_um_set_max_history_name: + return sys_rsbac_um_set_max_history_name(k_arg.um_set_max_history_name.ta_number, + (void __user *)(long)k_arg.um_set_max_history_name.name, + k_arg.um_set_max_history_name.max_history); + case RSYS_um_select_vset: + return sys_rsbac_um_select_vset(k_arg.um_select_vset.vset); +#endif +#ifdef CONFIG_RSBAC_UDF + case RSYS_udf_flush_cache: + return sys_rsbac_udf_flush_cache(); +#endif + +#ifdef CONFIG_RSBAC_LIST_TRANS + case RSYS_list_ta_begin_name: + return sys_rsbac_list_ta_begin_name(k_arg.list_ta_begin.ttl, + (void __user *)(long)k_arg.list_ta_begin_name.ta_number_p, + k_arg.list_ta_begin_name.commit_uid, + (void __user *)(long)k_arg.list_ta_begin_name.name, + (void __user *)(long)k_arg.list_ta_begin_name.password); + case RSYS_list_ta_begin: + return sys_rsbac_list_ta_begin(k_arg.list_ta_begin.ttl, + (void __user *)(long)k_arg.list_ta_begin.ta_number_p, + k_arg.list_ta_begin.commit_uid, + (void __user *)(long)k_arg.list_ta_begin.password); + case RSYS_list_ta_refresh: + return sys_rsbac_list_ta_refresh(k_arg.list_ta_refresh.ttl, + k_arg.list_ta_refresh.ta_number, + (void __user *)(long)k_arg.list_ta_refresh.password); + case RSYS_list_ta_commit: + return sys_rsbac_list_ta_commit(k_arg.list_ta_commit.ta_number, + (void __user *)(long)k_arg.list_ta_commit.password); + case RSYS_list_ta_forget: + return sys_rsbac_list_ta_forget(k_arg.list_ta_forget.ta_number, + (void __user *)(long)k_arg.list_ta_forget.password); +#endif + + case RSYS_list_all_dev: + return sys_rsbac_list_all_dev(k_arg.list_all_dev.ta_number, + (void __user *)(long)k_arg.list_all_dev.id_p, + k_arg.list_all_dev.maxnum); + case RSYS_list_all_user: + return sys_rsbac_list_all_user(k_arg.list_all_user.ta_number, + (void __user *)(long)k_arg.list_all_user.id_p, + k_arg.list_all_user.maxnum); + case RSYS_list_all_group: + return sys_rsbac_list_all_group(k_arg.list_all_group.ta_number, + (void __user *)(long)k_arg.list_all_group.id_p, + k_arg.list_all_group.maxnum); + case RSYS_list_all_ipc: + return sys_rsbac_list_all_ipc(k_arg.list_all_ipc.ta_number, + (void __user *)(long)k_arg.list_all_ipc.id_p, + k_arg.list_all_ipc.maxnum); + + case RSYS_version: + return RSBAC_VERSION_NR; + case RSYS_api_min_version: + return RSBAC_API_MIN_VERSION_NR; + case RSYS_api_max_version: + return RSBAC_API_MAX_VERSION_NR; + case RSYS_stats: + return sys_rsbac_stats(); + case RSYS_check: + return sys_rsbac_check(k_arg.check.correct, k_arg.check.check_inode); +#if defined(CONFIG_RSBAC_INIT_DELAY) + case RSYS_init: + return sys_rsbac_init((void __user *)(long)k_arg.init.root_dev); +#endif + + default: + return -RSBAC_EINVALIDREQUEST; + } + } else +#endif + { + union rsbac_syscall_arg_t k_arg; + + /* get values from user space */ + if(arg_p) + { + err = rsbac_get_user(&k_arg, arg_p, sizeof(k_arg) ); + if(unlikely(err < 0)) + return err; + } + else + { + memset(&k_arg, 0, sizeof(k_arg)); + } + + switch(call) + { +#ifdef CONFIG_RSBAC_UM + case RSYS_um_get_user_item: + return sys_rsbac_um_get_user_item(k_arg.um_get_user_item.ta_number, + k_arg.um_get_user_item.uid, + k_arg.um_get_user_item.mod, + k_arg.um_get_user_item.data_p); + case RSYS_um_get_uid: + return sys_rsbac_um_get_uid(k_arg.um_get_uid.ta_number, + k_arg.um_get_uid.name, + k_arg.um_get_uid.uid_p); + case RSYS_um_get_group_item: + return sys_rsbac_um_get_group_item(k_arg.um_get_group_item.ta_number, + k_arg.um_get_group_item.gid, + k_arg.um_get_group_item.mod, + k_arg.um_get_group_item.data_p); + case RSYS_um_get_gm_list: + return sys_rsbac_um_get_gm_list(k_arg.um_get_gm_list.ta_number, + k_arg.um_get_gm_list.user, + k_arg.um_get_gm_list.group_array, + k_arg.um_get_gm_list.maxnum); + case RSYS_um_get_gm_user_list: + return sys_rsbac_um_get_gm_user_list(k_arg.um_get_gm_user_list.ta_number, + k_arg.um_get_gm_user_list.group, + k_arg.um_get_gm_user_list.user_array, + k_arg.um_get_gm_user_list.maxnum); + case RSYS_um_get_gid: + return sys_rsbac_um_get_gid(k_arg.um_get_gid.ta_number, + k_arg.um_get_gid.name, + k_arg.um_get_gid.gid_p); + case RSYS_um_get_user_list: + return sys_rsbac_um_get_user_list(k_arg.um_get_user_list.ta_number, + k_arg.um_get_user_list.vset, + k_arg.um_get_user_list.user_array, + k_arg.um_get_user_list.maxnum); + case RSYS_um_check_account_name: + return sys_rsbac_um_check_account_name(k_arg.um_check_account_name.name); +#endif + case RSYS_get_attr: + return sys_rsbac_get_attr(k_arg.get_attr.ta_number, + k_arg.get_attr.module, + k_arg.get_attr.target, + k_arg.get_attr.tid, + k_arg.get_attr.attr, + k_arg.get_attr.value, + k_arg.get_attr.inherit); + case RSYS_get_attr_n: + return sys_rsbac_get_attr_n(k_arg.get_attr_n.ta_number, + k_arg.get_attr_n.module, + k_arg.get_attr_n.target, + k_arg.get_attr_n.t_name, + k_arg.get_attr_n.attr, + k_arg.get_attr_n.value, + k_arg.get_attr_n.inherit); + case RSYS_set_attr: + return sys_rsbac_set_attr(k_arg.set_attr.ta_number, + k_arg.set_attr.module, + k_arg.set_attr.target, + k_arg.set_attr.tid, + k_arg.set_attr.attr, + k_arg.set_attr.value); + case RSYS_set_attr_n: + return sys_rsbac_set_attr_n(k_arg.set_attr_n.ta_number, + k_arg.set_attr_n.module, + k_arg.set_attr_n.target, + k_arg.set_attr_n.t_name, + k_arg.set_attr_n.attr, + k_arg.set_attr_n.value); +#ifdef CONFIG_RSBAC_RC + case RSYS_rc_get_current_role: + return sys_rsbac_rc_get_current_role(k_arg.rc_get_current_role.role_p); + case RSYS_rc_get_item: + return sys_rsbac_rc_get_item(k_arg.rc_get_item.ta_number, + k_arg.rc_get_item.target, + k_arg.rc_get_item.tid_p, + k_arg.rc_get_item.subtid_p, + k_arg.rc_get_item.item, + k_arg.rc_get_item.value_p, + k_arg.rc_get_item.ttl_p); + case RSYS_rc_change_role: + return sys_rsbac_rc_change_role(k_arg.rc_change_role.role, k_arg.rc_change_role.pass); +#endif +#ifdef CONFIG_RSBAC_JAIL + case RSYS_jail: + return rsbac_jail_sys_jail(k_arg.jail.version, + k_arg.jail.path, + k_arg.jail.ip, + k_arg.jail.flags, + k_arg.jail.max_caps, + k_arg.jail.scd_get, + k_arg.jail.scd_modify); +#endif + + case RSYS_remove_target: + return sys_rsbac_remove_target(k_arg.remove_target.ta_number, + k_arg.remove_target.target, + k_arg.remove_target.tid); + case RSYS_remove_target_n: + return sys_rsbac_remove_target_n(k_arg.remove_target_n.ta_number, + k_arg.remove_target_n.target, + k_arg.remove_target_n.t_name); + case RSYS_net_list_all_netdev: + return sys_rsbac_net_list_all_netdev(k_arg.net_list_all_netdev.ta_number, + k_arg.net_list_all_netdev.id_p, + k_arg.net_list_all_netdev.maxnum); + case RSYS_net_template: + return sys_rsbac_net_template(k_arg.net_template.ta_number, + k_arg.net_template.call, + k_arg.net_template.id, + k_arg.net_template.data_p); + case RSYS_net_list_all_template: + return sys_rsbac_net_list_all_template(k_arg.net_list_all_template.ta_number, + k_arg.net_list_all_template.id_p, + k_arg.net_list_all_template.maxnum); + case RSYS_switch: + return sys_rsbac_switch(k_arg.switch_module.module, + k_arg.switch_module.value); + case RSYS_get_switch: + return sys_rsbac_get_switch(k_arg.get_switch_module.module, + k_arg.get_switch_module.value_p, + k_arg.get_switch_module.switchable_p); + case RSYS_adf_log_switch: + return sys_rsbac_adf_log_switch(k_arg.adf_log_switch.request, + k_arg.adf_log_switch.target, + k_arg.adf_log_switch.value); + case RSYS_get_adf_log: + return sys_rsbac_get_adf_log(k_arg.get_adf_log.request, + k_arg.get_adf_log.target, + k_arg.get_adf_log.value_p); + case RSYS_write: + return sys_rsbac_write(); + case RSYS_log: + return sys_rsbac_log(k_arg.log.type, + k_arg.log.buf, + k_arg.log.len); +#ifdef CONFIG_RSBAC_MAC + case RSYS_mac_set_curr_level: + return sys_rsbac_mac_set_curr_level(k_arg.mac_set_curr_level.level, + k_arg.mac_set_curr_level.categories_p); + case RSYS_mac_get_curr_level: + return sys_rsbac_mac_get_curr_level(k_arg.mac_get_curr_level.level_p, + k_arg.mac_get_curr_level.categories_p); + case RSYS_mac_get_max_level: + return sys_rsbac_mac_get_max_level(k_arg.mac_get_max_level.level_p, + k_arg.mac_get_max_level.categories_p); + case RSYS_mac_get_min_level: + return sys_rsbac_mac_get_min_level(k_arg.mac_get_min_level.level_p, + k_arg.mac_get_min_level.categories_p); + case RSYS_mac_add_p_tru: + return sys_rsbac_mac_add_p_tru(k_arg.mac_add_p_tru.ta_number, + k_arg.mac_add_p_tru.pid, + k_arg.mac_add_p_tru.uid, + k_arg.mac_add_p_tru.ttl); + case RSYS_mac_remove_p_tru: + return sys_rsbac_mac_remove_p_tru(k_arg.mac_remove_p_tru.ta_number, + k_arg.mac_remove_p_tru.pid, + k_arg.mac_add_p_tru.uid); + case RSYS_mac_add_f_tru: + return sys_rsbac_mac_add_f_tru(k_arg.mac_add_f_tru.ta_number, + k_arg.mac_add_f_tru.filename, + k_arg.mac_add_p_tru.uid, + k_arg.mac_add_f_tru.ttl); + case RSYS_mac_remove_f_tru: + return sys_rsbac_mac_remove_f_tru(k_arg.mac_remove_f_tru.ta_number, + k_arg.mac_remove_f_tru.filename, + k_arg.mac_remove_f_tru.uid); + case RSYS_mac_get_f_trulist: + return sys_rsbac_mac_get_f_trulist(k_arg.mac_get_f_trulist.ta_number, + k_arg.mac_get_f_trulist.filename, + k_arg.mac_get_f_trulist.trulist, + k_arg.mac_get_f_trulist.ttllist, + k_arg.mac_get_f_trulist.maxnum); + case RSYS_mac_get_p_trulist: + return sys_rsbac_mac_get_p_trulist(k_arg.mac_get_p_trulist.ta_number, + k_arg.mac_get_p_trulist.pid, + k_arg.mac_get_p_trulist.trulist, + k_arg.mac_get_p_trulist.ttllist, + k_arg.mac_get_p_trulist.maxnum); +#endif +#ifdef CONFIG_RSBAC_DAZ + case RSYS_daz_flush_cache: + return sys_rsbac_daz_flush_cache(); +#endif +#ifdef CONFIG_RSBAC_RC + case RSYS_rc_copy_role: + return sys_rsbac_rc_copy_role(k_arg.rc_copy_role.ta_number, + k_arg.rc_copy_role.from_role, + k_arg.rc_copy_role.to_role); + case RSYS_rc_copy_type: + return sys_rsbac_rc_copy_type(k_arg.rc_copy_type.ta_number, + k_arg.rc_copy_type.target, + k_arg.rc_copy_type.from_type, + k_arg.rc_copy_type.to_type); + case RSYS_rc_set_item: + return sys_rsbac_rc_set_item(k_arg.rc_set_item.ta_number, + k_arg.rc_set_item.target, + k_arg.rc_set_item.tid_p, + k_arg.rc_set_item.subtid_p, + k_arg.rc_set_item.item, + k_arg.rc_set_item.value_p, + k_arg.rc_set_item.ttl); + case RSYS_rc_get_eff_rights_n: + return sys_rsbac_rc_get_eff_rights_n(k_arg.rc_get_eff_rights_n.ta_number, + k_arg.rc_get_eff_rights_n.target, + k_arg.rc_get_eff_rights_n.t_name, + k_arg.rc_get_eff_rights_n.request_vector_p, + k_arg.rc_get_eff_rights_n.ttl_p); + case RSYS_rc_get_list: + return sys_rsbac_rc_get_list(k_arg.rc_get_list.ta_number, + k_arg.rc_get_list.target, + k_arg.rc_get_list.tid_p, + k_arg.rc_get_list.item, + k_arg.rc_get_list.maxnum, + k_arg.rc_get_list.array_p, + k_arg.rc_get_list.ttl_array_p); + case RSYS_rc_select_fd_create_type: + return sys_rsbac_rc_select_fd_create_type(k_arg.rc_select_fd_create_type.type); +#endif +#ifdef CONFIG_RSBAC_AUTH + case RSYS_auth_add_p_cap: + return sys_rsbac_auth_add_p_cap(k_arg.auth_add_p_cap.ta_number, + k_arg.auth_add_p_cap.pid, + k_arg.auth_add_p_cap.cap_type, + k_arg.auth_add_p_cap.cap_range, + k_arg.auth_add_p_cap.ttl); + case RSYS_auth_remove_p_cap: + return sys_rsbac_auth_remove_p_cap(k_arg.auth_remove_p_cap.ta_number, + k_arg.auth_remove_p_cap.pid, + k_arg.auth_remove_p_cap.cap_type, + k_arg.auth_remove_p_cap.cap_range); + case RSYS_auth_add_f_cap: + return sys_rsbac_auth_add_f_cap(k_arg.auth_add_f_cap.ta_number, + k_arg.auth_add_f_cap.filename, + k_arg.auth_add_f_cap.cap_type, + k_arg.auth_add_f_cap.cap_range, + k_arg.auth_add_f_cap.ttl); + case RSYS_auth_remove_f_cap: + return sys_rsbac_auth_remove_f_cap(k_arg.auth_remove_f_cap.ta_number, + k_arg.auth_remove_f_cap.filename, + k_arg.auth_remove_f_cap.cap_type, + k_arg.auth_remove_f_cap.cap_range); + case RSYS_auth_get_f_caplist: + return sys_rsbac_auth_get_f_caplist(k_arg.auth_get_f_caplist.ta_number, + k_arg.auth_get_f_caplist.filename, + k_arg.auth_get_f_caplist.cap_type, + k_arg.auth_get_f_caplist.caplist, + k_arg.auth_get_f_caplist.ttllist, + k_arg.auth_get_f_caplist.maxnum); + case RSYS_auth_get_p_caplist: + return sys_rsbac_auth_get_p_caplist(k_arg.auth_get_p_caplist.ta_number, + k_arg.auth_get_p_caplist.pid, + k_arg.auth_get_p_caplist.cap_type, + k_arg.auth_get_p_caplist.caplist, + k_arg.auth_get_p_caplist.ttllist, + k_arg.auth_get_p_caplist.maxnum); +#endif +#ifdef CONFIG_RSBAC_ACL + case RSYS_acl: + return sys_rsbac_acl(k_arg.acl.ta_number, + k_arg.acl.call, + k_arg.acl.arg); + case RSYS_acl_n: + return sys_rsbac_acl_n(k_arg.acl_n.ta_number, + k_arg.acl_n.call, + k_arg.acl_n.arg); + case RSYS_acl_get_rights: + return sys_rsbac_acl_get_rights(k_arg.acl_get_rights.ta_number, + k_arg.acl_get_rights.arg, + k_arg.acl_get_rights.rights_p, + k_arg.acl_get_rights.effective); + case RSYS_acl_get_rights_n: + return sys_rsbac_acl_get_rights_n(k_arg.acl_get_rights_n.ta_number, + k_arg.acl_get_rights_n.arg, + k_arg.acl_get_rights_n.rights_p, + k_arg.acl_get_rights_n.effective); + case RSYS_acl_get_tlist: + return sys_rsbac_acl_get_tlist(k_arg.acl_get_tlist.ta_number, + k_arg.acl_get_tlist.target, + k_arg.acl_get_tlist.tid, + k_arg.acl_get_tlist.entry_array, + k_arg.acl_get_tlist.ttl_array, + k_arg.acl_get_tlist.maxnum); + case RSYS_acl_get_tlist_n: + return sys_rsbac_acl_get_tlist_n(k_arg.acl_get_tlist_n.ta_number, + k_arg.acl_get_tlist_n.target, + k_arg.acl_get_tlist_n.t_name, + k_arg.acl_get_tlist_n.entry_array, + k_arg.acl_get_tlist_n.ttl_array, + k_arg.acl_get_tlist_n.maxnum); + case RSYS_acl_get_mask: + return sys_rsbac_acl_get_mask(k_arg.acl_get_mask.ta_number, + k_arg.acl_get_mask.target, + k_arg.acl_get_mask.tid, + k_arg.acl_get_mask.mask_p); + case RSYS_acl_get_mask_n: + return sys_rsbac_acl_get_mask_n(k_arg.acl_get_mask_n.ta_number, + k_arg.acl_get_mask_n.target, + k_arg.acl_get_mask_n.t_name, + k_arg.acl_get_mask_n.mask_p); + case RSYS_acl_group: + return sys_rsbac_acl_group(k_arg.acl_group.ta_number, + k_arg.acl_group.call, + k_arg.acl_group.arg_p); + case RSYS_acl_list_all_dev: + return sys_rsbac_acl_list_all_dev(k_arg.acl_list_all_dev.ta_number, + k_arg.acl_list_all_dev.id_p, + k_arg.acl_list_all_dev.maxnum); + case RSYS_acl_list_all_user: + return sys_rsbac_acl_list_all_user(k_arg.acl_list_all_user.ta_number, + k_arg.acl_list_all_user.id_p, + k_arg.acl_list_all_user.maxnum); + case RSYS_acl_list_all_group: + return sys_rsbac_acl_list_all_group(k_arg.acl_list_all_group.ta_number, + k_arg.acl_list_all_group.id_p, + k_arg.acl_list_all_group.maxnum); +#endif +#ifdef CONFIG_RSBAC_REG + case RSYS_reg: + return sys_rsbac_reg(k_arg.reg.handle, + k_arg.reg.arg); +#endif +#ifdef CONFIG_RSBAC_UM + case RSYS_um_auth_name: + return sys_rsbac_um_auth_name(k_arg.um_auth_name.name, + k_arg.um_auth_name.pass); + case RSYS_um_auth_uid: + return sys_rsbac_um_auth_uid(k_arg.um_auth_uid.uid, + k_arg.um_auth_uid.pass); + case RSYS_um_add_user: + return sys_rsbac_um_add_user(k_arg.um_add_user.ta_number, + k_arg.um_add_user.uid, + k_arg.um_add_user.entry_p, + k_arg.um_add_user.pass, + k_arg.um_add_user.ttl); + case RSYS_um_add_group: + return sys_rsbac_um_add_group(k_arg.um_add_group.ta_number, + k_arg.um_add_group.gid, + k_arg.um_add_group.entry_p, + k_arg.um_add_group.pass, + k_arg.um_add_group.ttl); + case RSYS_um_add_gm: + return sys_rsbac_um_add_gm(k_arg.um_add_gm.ta_number, + k_arg.um_add_gm.uid, + k_arg.um_add_gm.gid, + k_arg.um_add_gm.ttl); + case RSYS_um_mod_user: + return sys_rsbac_um_mod_user(k_arg.um_mod_user.ta_number, + k_arg.um_mod_user.uid, + k_arg.um_mod_user.mod, + k_arg.um_mod_user.data_p); + case RSYS_um_mod_group: + return sys_rsbac_um_mod_group(k_arg.um_mod_group.ta_number, + k_arg.um_mod_group.gid, + k_arg.um_mod_group.mod, + k_arg.um_mod_group.data_p); + case RSYS_um_remove_user: + return sys_rsbac_um_remove_user(k_arg.um_remove_user.ta_number, + k_arg.um_remove_user.uid); + case RSYS_um_remove_group: + return sys_rsbac_um_remove_group(k_arg.um_remove_group.ta_number, + k_arg.um_remove_group.gid); + case RSYS_um_remove_gm: + return sys_rsbac_um_remove_gm(k_arg.um_remove_gm.ta_number, + k_arg.um_remove_gm.uid, + k_arg.um_remove_gm.gid); + case RSYS_um_user_exists: + return sys_rsbac_um_user_exists(k_arg.um_user_exists.ta_number, + k_arg.um_user_exists.uid); + case RSYS_um_get_next_user: + return sys_rsbac_um_get_next_user(k_arg.um_get_next_user.ta_number, + k_arg.um_get_next_user.old_user, + k_arg.um_get_next_user.next_user_p); + case RSYS_um_group_exists: + return sys_rsbac_um_group_exists(k_arg.um_group_exists.ta_number, + k_arg.um_group_exists.gid); + case RSYS_um_get_group_list: + return sys_rsbac_um_get_group_list(k_arg.um_get_group_list.ta_number, + k_arg.um_get_group_list.vset, + k_arg.um_get_group_list.group_array, + k_arg.um_get_group_list.maxnum); + case RSYS_um_set_pass: + return sys_rsbac_um_set_pass(k_arg.um_set_pass.uid, + k_arg.um_set_pass.old_pass, + k_arg.um_set_pass.new_pass); + case RSYS_um_set_pass_name: + return sys_rsbac_um_set_pass_name(k_arg.um_set_pass_name.name, + k_arg.um_set_pass_name.old_pass, + k_arg.um_set_pass_name.new_pass); + case RSYS_um_add_onetime: + return sys_rsbac_um_add_onetime(k_arg.um_add_onetime.uid, + k_arg.um_add_onetime.old_pass, + k_arg.um_add_onetime.new_pass, + k_arg.um_add_onetime.ttl); + case RSYS_um_add_onetime_name: + return sys_rsbac_um_add_onetime_name(k_arg.um_add_onetime_name.name, + k_arg.um_add_onetime_name.old_pass, + k_arg.um_add_onetime_name.new_pass, + k_arg.um_add_onetime_name.ttl); + case RSYS_um_remove_all_onetime: + return sys_rsbac_um_remove_all_onetime(k_arg.um_remove_all_onetime.uid, + k_arg.um_remove_all_onetime.old_pass); + case RSYS_um_remove_all_onetime_name: + return sys_rsbac_um_remove_all_onetime_name(k_arg.um_remove_all_onetime_name.name, + k_arg.um_remove_all_onetime_name.old_pass); + case RSYS_um_count_onetime: + return sys_rsbac_um_count_onetime(k_arg.um_count_onetime.uid, + k_arg.um_count_onetime.old_pass); + case RSYS_um_count_onetime_name: + return sys_rsbac_um_count_onetime_name(k_arg.um_count_onetime_name.name, + k_arg.um_count_onetime_name.old_pass); + case RSYS_um_set_group_pass: + return sys_rsbac_um_set_group_pass(k_arg.um_set_group_pass.gid, + k_arg.um_set_group_pass.new_pass); + case RSYS_um_check_account: + return sys_rsbac_um_check_account(k_arg.um_check_account.uid); + case RSYS_um_get_max_history: + return sys_rsbac_um_get_max_history(k_arg.um_get_max_history.ta_number, + k_arg.um_get_max_history.uid); + case RSYS_um_get_max_history_name: + return sys_rsbac_um_get_max_history_name(k_arg.um_get_max_history_name.ta_number, + k_arg.um_get_max_history_name.name); + case RSYS_um_set_max_history: + return sys_rsbac_um_set_max_history(k_arg.um_set_max_history.ta_number, + k_arg.um_set_max_history.uid, + k_arg.um_set_max_history.max_history); + case RSYS_um_set_max_history_name: + return sys_rsbac_um_set_max_history_name(k_arg.um_set_max_history_name.ta_number, + k_arg.um_set_max_history_name.name, + k_arg.um_set_max_history_name.max_history); + case RSYS_um_select_vset: + return sys_rsbac_um_select_vset(k_arg.um_select_vset.vset); +#endif +#ifdef CONFIG_RSBAC_UDF + case RSYS_udf_flush_cache: + return sys_rsbac_udf_flush_cache(); +#endif + +#ifdef CONFIG_RSBAC_LIST_TRANS + case RSYS_list_ta_begin_name: + return sys_rsbac_list_ta_begin_name(k_arg.list_ta_begin.ttl, + k_arg.list_ta_begin_name.ta_number_p, + k_arg.list_ta_begin_name.commit_uid, + k_arg.list_ta_begin_name.name, + k_arg.list_ta_begin_name.password); + case RSYS_list_ta_begin: + return sys_rsbac_list_ta_begin(k_arg.list_ta_begin.ttl, + k_arg.list_ta_begin.ta_number_p, + k_arg.list_ta_begin.commit_uid, + k_arg.list_ta_begin.password); + case RSYS_list_ta_refresh: + return sys_rsbac_list_ta_refresh(k_arg.list_ta_refresh.ttl, + k_arg.list_ta_refresh.ta_number, + k_arg.list_ta_refresh.password); + case RSYS_list_ta_commit: + return sys_rsbac_list_ta_commit(k_arg.list_ta_commit.ta_number, + k_arg.list_ta_commit.password); + case RSYS_list_ta_forget: + return sys_rsbac_list_ta_forget(k_arg.list_ta_forget.ta_number, + k_arg.list_ta_forget.password); +#endif + + case RSYS_list_all_dev: + return sys_rsbac_list_all_dev(k_arg.list_all_dev.ta_number, + k_arg.list_all_dev.id_p, + k_arg.list_all_dev.maxnum); + case RSYS_list_all_user: + return sys_rsbac_list_all_user(k_arg.list_all_user.ta_number, + k_arg.list_all_user.id_p, + k_arg.list_all_user.maxnum); + case RSYS_list_all_group: + return sys_rsbac_list_all_group(k_arg.list_all_group.ta_number, + k_arg.list_all_group.id_p, + k_arg.list_all_group.maxnum); + case RSYS_list_all_ipc: + return sys_rsbac_list_all_ipc(k_arg.list_all_ipc. + ta_number, + k_arg.list_all_ipc.id_p, + k_arg.list_all_ipc.maxnum); + + case RSYS_version: + return RSBAC_VERSION_NR; + case RSYS_api_min_version: + return RSBAC_API_MIN_VERSION_NR; + case RSYS_api_max_version: + return RSBAC_API_MAX_VERSION_NR; + case RSYS_stats: + return sys_rsbac_stats(); + case RSYS_check: + return sys_rsbac_check(k_arg.check.correct, k_arg.check.check_inode); +#if defined(CONFIG_RSBAC_INIT_DELAY) + case RSYS_init: + return sys_rsbac_init(k_arg.init.root_dev); +#endif + + default: + return -RSBAC_EINVALIDREQUEST; + } + } + } + +/* end of syscalls.c */ diff --git a/security/Kconfig b/security/Kconfig index e8e449444e65..6b5278d346ff 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -4,6 +4,8 @@ menu "Security options" +source "rsbac/Kconfig" + source security/keys/Kconfig config SECURITY_DMESG_RESTRICT