Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (33 commits)
  AppArmor: kill unused macros in lsm.c
  AppArmor: cleanup generated files correctly
  KEYS: Add an iovec version of KEYCTL_INSTANTIATE
  KEYS: Add a new keyctl op to reject a key with a specified error code
  KEYS: Add a key type op to permit the key description to be vetted
  KEYS: Add an RCU payload dereference macro
  AppArmor: Cleanup make file to remove cruft and make it easier to read
  SELinux: implement the new sb_remount LSM hook
  LSM: Pass -o remount options to the LSM
  SELinux: Compute SID for the newly created socket
  SELinux: Socket retains creator role and MLS attribute
  SELinux: Auto-generate security_is_socket_class
  TOMOYO: Fix memory leak upon file open.
  Revert "selinux: simplify ioctl checking"
  selinux: drop unused packet flow permissions
  selinux: Fix packet forwarding checks on postrouting
  selinux: Fix wrong checks for selinux_policycap_netpeer
  selinux: Fix check for xfrm selinux context algorithm
  ima: remove unnecessary call to ima_must_measure
  IMA: remove IMA imbalance checking
  ...
This commit is contained in:
Linus Torvalds 2011-03-16 09:15:43 -07:00
commit 0f6e0e8448
85 changed files with 1549 additions and 712 deletions

View File

@ -127,14 +127,15 @@ This is because process A's keyrings can't simply be attached to
of them, and (b) it requires the same UID/GID/Groups all the way through.
======================
NEGATIVE INSTANTIATION
======================
====================================
NEGATIVE INSTANTIATION AND REJECTION
====================================
Rather than instantiating a key, it is possible for the possessor of an
authorisation key to negatively instantiate a key that's under construction.
This is a short duration placeholder that causes any attempt at re-requesting
the key whilst it exists to fail with error ENOKEY.
the key whilst it exists to fail with error ENOKEY if negated or the specified
error if rejected.
This is provided to prevent excessive repeated spawning of /sbin/request-key
processes for a key that will never be obtainable.

View File

@ -637,6 +637,9 @@ The keyctl syscall functions are:
long keyctl(KEYCTL_INSTANTIATE, key_serial_t key,
const void *payload, size_t plen,
key_serial_t keyring);
long keyctl(KEYCTL_INSTANTIATE_IOV, key_serial_t key,
const struct iovec *payload_iov, unsigned ioc,
key_serial_t keyring);
If the kernel calls back to userspace to complete the instantiation of a
key, userspace should use this call to supply data for the key before the
@ -652,11 +655,16 @@ The keyctl syscall functions are:
The payload and plen arguments describe the payload data as for add_key().
The payload_iov and ioc arguments describe the payload data in an iovec
array instead of a single buffer.
(*) Negatively instantiate a partially constructed key.
long keyctl(KEYCTL_NEGATE, key_serial_t key,
unsigned timeout, key_serial_t keyring);
long keyctl(KEYCTL_REJECT, key_serial_t key,
unsigned timeout, unsigned error, key_serial_t keyring);
If the kernel calls back to userspace to complete the instantiation of a
key, userspace should use this call mark the key as negative before the
@ -669,6 +677,10 @@ The keyctl syscall functions are:
that keyring, however all the constraints applying in KEYCTL_LINK apply in
this case too.
If the key is rejected, future searches for it will return the specified
error code until the rejected key expires. Negating the key is the same
as rejecting the key with ENOKEY as the error code.
(*) Set the default request-key destination keyring.
@ -1062,6 +1074,13 @@ The structure has a number of fields, some of which are mandatory:
viable.
(*) int (*vet_description)(const char *description);
This optional method is called to vet a key description. If the key type
doesn't approve of the key description, it may return an error, otherwise
it should return 0.
(*) int (*instantiate)(struct key *key, const void *data, size_t datalen);
This method is called to attach a payload to a key during construction.
@ -1231,10 +1250,11 @@ hand the request off to (perhaps a path held in placed in another key by, for
example, the KDE desktop manager).
The program (or whatever it calls) should finish construction of the key by
calling KEYCTL_INSTANTIATE, which also permits it to cache the key in one of
the keyrings (probably the session ring) before returning. Alternatively, the
key can be marked as negative with KEYCTL_NEGATE; this also permits the key to
be cached in one of the keyrings.
calling KEYCTL_INSTANTIATE or KEYCTL_INSTANTIATE_IOV, which also permits it to
cache the key in one of the keyrings (probably the session ring) before
returning. Alternatively, the key can be marked as negative with KEYCTL_NEGATE
or KEYCTL_REJECT; this also permits the key to be cached in one of the
keyrings.
If it returns with the key remaining in the unconstructed state, the key will
be marked as being negative, it will be added to the session keyring, and an

View File

@ -2130,6 +2130,11 @@ config SYSVIPC_COMPAT
def_bool y
depends on COMPAT && SYSVIPC
config KEYS_COMPAT
bool
depends on COMPAT && KEYS
default y
endmenu

View File

@ -90,13 +90,14 @@ static noinline int cow_file_range(struct inode *inode,
unsigned long *nr_written, int unlock);
static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
struct inode *inode, struct inode *dir)
struct inode *inode, struct inode *dir,
const struct qstr *qstr)
{
int err;
err = btrfs_init_acl(trans, inode, dir);
if (!err)
err = btrfs_xattr_security_init(trans, inode, dir);
err = btrfs_xattr_security_init(trans, inode, dir, qstr);
return err;
}
@ -4704,7 +4705,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
if (IS_ERR(inode))
goto out_unlock;
err = btrfs_init_inode_security(trans, inode, dir);
err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
if (err) {
drop_inode = 1;
goto out_unlock;
@ -4765,7 +4766,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
if (IS_ERR(inode))
goto out_unlock;
err = btrfs_init_inode_security(trans, inode, dir);
err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
if (err) {
drop_inode = 1;
goto out_unlock;
@ -4891,7 +4892,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
drop_on_err = 1;
err = btrfs_init_inode_security(trans, inode, dir);
err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
if (err)
goto out_fail;
@ -7103,7 +7104,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
if (IS_ERR(inode))
goto out_unlock;
err = btrfs_init_inode_security(trans, inode, dir);
err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
if (err) {
drop_inode = 1;
goto out_unlock;

View File

@ -370,7 +370,8 @@ int btrfs_removexattr(struct dentry *dentry, const char *name)
}
int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
struct inode *inode, struct inode *dir)
struct inode *inode, struct inode *dir,
const struct qstr *qstr)
{
int err;
size_t len;
@ -378,7 +379,8 @@ int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
char *suffix;
char *name;
err = security_inode_init_security(inode, dir, &suffix, &value, &len);
err = security_inode_init_security(inode, dir, qstr, &suffix, &value,
&len);
if (err) {
if (err == -EOPNOTSUPP)
return 0;

View File

@ -37,6 +37,7 @@ extern int btrfs_setxattr(struct dentry *dentry, const char *name,
extern int btrfs_removexattr(struct dentry *dentry, const char *name);
extern int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
struct inode *inode, struct inode *dir);
struct inode *inode, struct inode *dir,
const struct qstr *qstr);
#endif /* __XATTR__ */

View File

@ -275,6 +275,7 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
bool preemptive)
{
struct dentry *grave, *trap;
struct path path, path_to_graveyard;
char nbuffer[8 + 8 + 1];
int ret;
@ -287,10 +288,18 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
/* non-directories can just be unlinked */
if (!S_ISDIR(rep->d_inode->i_mode)) {
_debug("unlink stale object");
ret = vfs_unlink(dir->d_inode, rep);
if (preemptive)
cachefiles_mark_object_buried(cache, rep);
path.mnt = cache->mnt;
path.dentry = dir;
ret = security_path_unlink(&path, rep);
if (ret < 0) {
cachefiles_io_error(cache, "Unlink security error");
} else {
ret = vfs_unlink(dir->d_inode, rep);
if (preemptive)
cachefiles_mark_object_buried(cache, rep);
}
mutex_unlock(&dir->d_inode->i_mutex);
@ -379,12 +388,23 @@ try_again:
}
/* attempt the rename */
ret = vfs_rename(dir->d_inode, rep, cache->graveyard->d_inode, grave);
if (ret != 0 && ret != -ENOMEM)
cachefiles_io_error(cache, "Rename failed with error %d", ret);
path.mnt = cache->mnt;
path.dentry = dir;
path_to_graveyard.mnt = cache->mnt;
path_to_graveyard.dentry = cache->graveyard;
ret = security_path_rename(&path, rep, &path_to_graveyard, grave);
if (ret < 0) {
cachefiles_io_error(cache, "Rename security error %d", ret);
} else {
ret = vfs_rename(dir->d_inode, rep,
cache->graveyard->d_inode, grave);
if (ret != 0 && ret != -ENOMEM)
cachefiles_io_error(cache,
"Rename failed with error %d", ret);
if (preemptive)
cachefiles_mark_object_buried(cache, rep);
if (preemptive)
cachefiles_mark_object_buried(cache, rep);
}
unlock_rename(cache->graveyard, dir);
dput(grave);
@ -448,6 +468,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
{
struct cachefiles_cache *cache;
struct dentry *dir, *next = NULL;
struct path path;
unsigned long start;
const char *name;
int ret, nlen;
@ -458,6 +479,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
cache = container_of(parent->fscache.cache,
struct cachefiles_cache, cache);
path.mnt = cache->mnt;
ASSERT(parent->dentry);
ASSERT(parent->dentry->d_inode);
@ -511,6 +533,10 @@ lookup_again:
if (ret < 0)
goto create_error;
path.dentry = dir;
ret = security_path_mkdir(&path, next, 0);
if (ret < 0)
goto create_error;
start = jiffies;
ret = vfs_mkdir(dir->d_inode, next, 0);
cachefiles_hist(cachefiles_mkdir_histogram, start);
@ -536,6 +562,10 @@ lookup_again:
if (ret < 0)
goto create_error;
path.dentry = dir;
ret = security_path_mknod(&path, next, S_IFREG, 0);
if (ret < 0)
goto create_error;
start = jiffies;
ret = vfs_create(dir->d_inode, next, S_IFREG, NULL);
cachefiles_hist(cachefiles_create_histogram, start);
@ -692,6 +722,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
{
struct dentry *subdir;
unsigned long start;
struct path path;
int ret;
_enter(",,%s", dirname);
@ -719,6 +750,11 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
_debug("attempt mkdir");
path.mnt = cache->mnt;
path.dentry = dir;
ret = security_path_mkdir(&path, subdir, 0700);
if (ret < 0)
goto mkdir_error;
ret = vfs_mkdir(dir->d_inode, subdir, 0700);
if (ret < 0)
goto mkdir_error;

View File

@ -110,7 +110,7 @@ extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **);
extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *, int);
/* ialloc.c */
extern struct inode * ext2_new_inode (struct inode *, int);
extern struct inode * ext2_new_inode (struct inode *, int, const struct qstr *);
extern void ext2_free_inode (struct inode *);
extern unsigned long ext2_count_free_inodes (struct super_block *);
extern void ext2_check_inodes_bitmap (struct super_block *);

View File

@ -429,7 +429,8 @@ found:
return group;
}
struct inode *ext2_new_inode(struct inode *dir, int mode)
struct inode *ext2_new_inode(struct inode *dir, int mode,
const struct qstr *qstr)
{
struct super_block *sb;
struct buffer_head *bitmap_bh = NULL;
@ -585,7 +586,7 @@ got:
if (err)
goto fail_free_drop;
err = ext2_init_security(inode,dir);
err = ext2_init_security(inode, dir, qstr);
if (err)
goto fail_free_drop;

View File

@ -104,7 +104,7 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, st
dquot_initialize(dir);
inode = ext2_new_inode(dir, mode);
inode = ext2_new_inode(dir, mode, &dentry->d_name);
if (IS_ERR(inode))
return PTR_ERR(inode);
@ -133,7 +133,7 @@ static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_
dquot_initialize(dir);
inode = ext2_new_inode (dir, mode);
inode = ext2_new_inode (dir, mode, &dentry->d_name);
err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
init_special_inode(inode, inode->i_mode, rdev);
@ -159,7 +159,7 @@ static int ext2_symlink (struct inode * dir, struct dentry * dentry,
dquot_initialize(dir);
inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO);
inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO, &dentry->d_name);
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out;
@ -230,7 +230,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode_inc_link_count(dir);
inode = ext2_new_inode (dir, S_IFDIR | mode);
inode = ext2_new_inode(dir, S_IFDIR | mode, &dentry->d_name);
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out_dir;

View File

@ -116,9 +116,11 @@ exit_ext2_xattr(void)
# endif /* CONFIG_EXT2_FS_XATTR */
#ifdef CONFIG_EXT2_FS_SECURITY
extern int ext2_init_security(struct inode *inode, struct inode *dir);
extern int ext2_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr);
#else
static inline int ext2_init_security(struct inode *inode, struct inode *dir)
static inline int ext2_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr)
{
return 0;
}

View File

@ -47,14 +47,15 @@ ext2_xattr_security_set(struct dentry *dentry, const char *name,
}
int
ext2_init_security(struct inode *inode, struct inode *dir)
ext2_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr)
{
int err;
size_t len;
void *value;
char *name;
err = security_inode_init_security(inode, dir, &name, &value, &len);
err = security_inode_init_security(inode, dir, qstr, &name, &value, &len);
if (err) {
if (err == -EOPNOTSUPP)
return 0;

View File

@ -404,7 +404,8 @@ static int find_group_other(struct super_block *sb, struct inode *parent)
* For other inodes, search forward from the parent directory's block
* group to find a free inode.
*/
struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode)
struct inode *ext3_new_inode(handle_t *handle, struct inode * dir,
const struct qstr *qstr, int mode)
{
struct super_block *sb;
struct buffer_head *bitmap_bh = NULL;
@ -589,7 +590,7 @@ got:
if (err)
goto fail_free_drop;
err = ext3_init_security(handle,inode, dir);
err = ext3_init_security(handle, inode, dir, qstr);
if (err)
goto fail_free_drop;

View File

@ -1710,7 +1710,7 @@ retry:
if (IS_DIRSYNC(dir))
handle->h_sync = 1;
inode = ext3_new_inode (handle, dir, mode);
inode = ext3_new_inode (handle, dir, &dentry->d_name, mode);
err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
inode->i_op = &ext3_file_inode_operations;
@ -1746,7 +1746,7 @@ retry:
if (IS_DIRSYNC(dir))
handle->h_sync = 1;
inode = ext3_new_inode (handle, dir, mode);
inode = ext3_new_inode (handle, dir, &dentry->d_name, mode);
err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
init_special_inode(inode, inode->i_mode, rdev);
@ -1784,7 +1784,7 @@ retry:
if (IS_DIRSYNC(dir))
handle->h_sync = 1;
inode = ext3_new_inode (handle, dir, S_IFDIR | mode);
inode = ext3_new_inode (handle, dir, &dentry->d_name, S_IFDIR | mode);
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out_stop;
@ -2206,7 +2206,7 @@ retry:
if (IS_DIRSYNC(dir))
handle->h_sync = 1;
inode = ext3_new_inode (handle, dir, S_IFLNK|S_IRWXUGO);
inode = ext3_new_inode (handle, dir, &dentry->d_name, S_IFLNK|S_IRWXUGO);
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out_stop;

View File

@ -128,10 +128,10 @@ exit_ext3_xattr(void)
#ifdef CONFIG_EXT3_FS_SECURITY
extern int ext3_init_security(handle_t *handle, struct inode *inode,
struct inode *dir);
struct inode *dir, const struct qstr *qstr);
#else
static inline int ext3_init_security(handle_t *handle, struct inode *inode,
struct inode *dir)
struct inode *dir, const struct qstr *qstr)
{
return 0;
}

View File

@ -49,14 +49,15 @@ ext3_xattr_security_set(struct dentry *dentry, const char *name,
}
int
ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir)
ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir,
const struct qstr *qstr)
{
int err;
size_t len;
void *value;
char *name;
err = security_inode_init_security(inode, dir, &name, &value, &len);
err = security_inode_init_security(inode, dir, qstr, &name, &value, &len);
if (err) {
if (err == -EOPNOTSUPP)
return 0;

View File

@ -1042,7 +1042,7 @@ got:
if (err)
goto fail_free_drop;
err = ext4_init_security(handle, inode, dir);
err = ext4_init_security(handle, inode, dir, qstr);
if (err)
goto fail_free_drop;

View File

@ -145,10 +145,10 @@ ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
#ifdef CONFIG_EXT4_FS_SECURITY
extern int ext4_init_security(handle_t *handle, struct inode *inode,
struct inode *dir);
struct inode *dir, const struct qstr *qstr);
#else
static inline int ext4_init_security(handle_t *handle, struct inode *inode,
struct inode *dir)
struct inode *dir, const struct qstr *qstr)
{
return 0;
}

View File

@ -49,14 +49,15 @@ ext4_xattr_security_set(struct dentry *dentry, const char *name,
}
int
ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir)
ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir,
const struct qstr *qstr)
{
int err;
size_t len;
void *value;
char *name;
err = security_inode_init_security(inode, dir, &name, &value, &len);
err = security_inode_init_security(inode, dir, qstr, &name, &value, &len);
if (err) {
if (err == -EOPNOTSUPP)
return 0;

View File

@ -190,7 +190,8 @@ struct file *alloc_file(struct path *path, fmode_t mode,
file_take_write(file);
WARN_ON(mnt_clone_write(path->mnt));
}
ima_counts_get(file);
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
i_readcount_inc(path->dentry->d_inode);
return file;
}
EXPORT_SYMBOL(alloc_file);
@ -251,6 +252,8 @@ static void __fput(struct file *file)
fops_put(file->f_op);
put_pid(file->f_owner.pid);
file_sb_list_del(file);
if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
i_readcount_dec(inode);
if (file->f_mode & FMODE_WRITE)
drop_file_write_access(file);
file->f_path.dentry = NULL;

View File

@ -763,14 +763,15 @@ fail:
return error;
}
static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip)
static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
const struct qstr *qstr)
{
int err;
size_t len;
void *value;
char *name;
err = security_inode_init_security(&ip->i_inode, &dip->i_inode,
err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
&name, &value, &len);
if (err) {
@ -854,7 +855,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
if (error)
goto fail_gunlock2;
error = gfs2_security_init(dip, GFS2_I(inode));
error = gfs2_security_init(dip, GFS2_I(inode), name);
if (error)
goto fail_gunlock2;

View File

@ -215,8 +215,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
no chance of AB-BA deadlock involving its f->sem). */
mutex_unlock(&f->sem);
ret = jffs2_do_create(c, dir_f, f, ri,
dentry->d_name.name, dentry->d_name.len);
ret = jffs2_do_create(c, dir_f, f, ri, &dentry->d_name);
if (ret)
goto fail;
@ -386,7 +385,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
jffs2_complete_reservation(c);
ret = jffs2_init_security(inode, dir_i);
ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
if (ret)
goto fail;
@ -530,7 +529,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
jffs2_complete_reservation(c);
ret = jffs2_init_security(inode, dir_i);
ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
if (ret)
goto fail;
@ -703,7 +702,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
jffs2_complete_reservation(c);
ret = jffs2_init_security(inode, dir_i);
ret = jffs2_init_security(inode, dir_i, &dentry->d_name);
if (ret)
goto fail;

View File

@ -401,7 +401,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
struct jffs2_raw_inode *ri, unsigned char *buf,
uint32_t offset, uint32_t writelen, uint32_t *retlen);
int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f,
struct jffs2_raw_inode *ri, const char *name, int namelen);
struct jffs2_raw_inode *ri, const struct qstr *qstr);
int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name,
int namelen, struct jffs2_inode_info *dead_f, uint32_t time);
int jffs2_do_link(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino,

View File

@ -23,14 +23,15 @@
#include "nodelist.h"
/* ---- Initial Security Label Attachment -------------- */
int jffs2_init_security(struct inode *inode, struct inode *dir)
int jffs2_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr)
{
int rc;
size_t len;
void *value;
char *name;
rc = security_inode_init_security(inode, dir, &name, &value, &len);
rc = security_inode_init_security(inode, dir, qstr, &name, &value, &len);
if (rc) {
if (rc == -EOPNOTSUPP)
return 0;

View File

@ -424,7 +424,9 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
return ret;
}
int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen)
int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
struct jffs2_inode_info *f, struct jffs2_raw_inode *ri,
const struct qstr *qstr)
{
struct jffs2_raw_dirent *rd;
struct jffs2_full_dnode *fn;
@ -466,15 +468,15 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode);
ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode, qstr);
if (ret)
return ret;
ret = jffs2_init_acl_post(&f->vfs_inode);
if (ret)
return ret;
ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
ret = jffs2_reserve_space(c, sizeof(*rd)+qstr->len, &alloclen,
ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(qstr->len));
if (ret) {
/* Eep. */
@ -493,19 +495,19 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
rd->totlen = cpu_to_je32(sizeof(*rd) + qstr->len);
rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
rd->pino = cpu_to_je32(dir_f->inocache->ino);
rd->version = cpu_to_je32(++dir_f->highest_version);
rd->ino = ri->ino;
rd->mctime = ri->ctime;
rd->nsize = namelen;
rd->nsize = qstr->len;
rd->type = DT_REG;
rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
rd->name_crc = cpu_to_je32(crc32(0, qstr->name, qstr->len));
fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, ALLOC_NORMAL);
fd = jffs2_write_dirent(c, dir_f, rd, qstr->name, qstr->len, ALLOC_NORMAL);
jffs2_free_raw_dirent(rd);

View File

@ -121,10 +121,11 @@ extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
#endif /* CONFIG_JFFS2_FS_XATTR */
#ifdef CONFIG_JFFS2_FS_SECURITY
extern int jffs2_init_security(struct inode *inode, struct inode *dir);
extern int jffs2_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr);
extern const struct xattr_handler jffs2_security_xattr_handler;
#else
#define jffs2_init_security(inode,dir) (0)
#define jffs2_init_security(inode,dir,qstr) (0)
#endif /* CONFIG_JFFS2_FS_SECURITY */
#endif /* _JFFS2_FS_XATTR_H_ */

View File

@ -62,10 +62,11 @@ extern ssize_t jfs_listxattr(struct dentry *, char *, size_t);
extern int jfs_removexattr(struct dentry *, const char *);
#ifdef CONFIG_JFS_SECURITY
extern int jfs_init_security(tid_t, struct inode *, struct inode *);
extern int jfs_init_security(tid_t, struct inode *, struct inode *,
const struct qstr *);
#else
static inline int jfs_init_security(tid_t tid, struct inode *inode,
struct inode *dir)
struct inode *dir, const struct qstr *qstr)
{
return 0;
}

View File

@ -115,7 +115,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
if (rc)
goto out3;
rc = jfs_init_security(tid, ip, dip);
rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
if (rc) {
txAbort(tid, 0);
goto out3;
@ -253,7 +253,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
if (rc)
goto out3;
rc = jfs_init_security(tid, ip, dip);
rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
if (rc) {
txAbort(tid, 0);
goto out3;
@ -929,7 +929,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
rc = jfs_init_security(tid, ip, dip);
rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
if (rc)
goto out3;
@ -1392,7 +1392,7 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
if (rc)
goto out3;
rc = jfs_init_security(tid, ip, dir);
rc = jfs_init_security(tid, ip, dir, &dentry->d_name);
if (rc) {
txAbort(tid, 0);
goto out3;

View File

@ -1091,7 +1091,8 @@ int jfs_removexattr(struct dentry *dentry, const char *name)
}
#ifdef CONFIG_JFS_SECURITY
int jfs_init_security(tid_t tid, struct inode *inode, struct inode *dir)
int jfs_init_security(tid_t tid, struct inode *inode, struct inode *dir,
const struct qstr *qstr)
{
int rc;
size_t len;
@ -1099,7 +1100,8 @@ int jfs_init_security(tid_t tid, struct inode *inode, struct inode *dir)
char *suffix;
char *name;
rc = security_inode_init_security(inode, dir, &suffix, &value, &len);
rc = security_inode_init_security(inode, dir, qstr, &suffix, &value,
&len);
if (rc) {
if (rc == -EOPNOTSUPP)
return 0;

View File

@ -1783,6 +1783,10 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
if (path->dentry != path->mnt->mnt_root)
return -EINVAL;
err = security_sb_remount(sb, data);
if (err)
return err;
down_write(&sb->s_umount);
if (flags & MS_BIND)
err = change_mount_flags(path->mnt, flags);

View File

@ -293,7 +293,7 @@ static int ocfs2_mknod(struct inode *dir,
}
/* get security xattr */
status = ocfs2_init_security_get(inode, dir, &si);
status = ocfs2_init_security_get(inode, dir, &dentry->d_name, &si);
if (status) {
if (status == -EOPNOTSUPP)
si.enable = 0;
@ -1665,7 +1665,7 @@ static int ocfs2_symlink(struct inode *dir,
}
/* get security xattr */
status = ocfs2_init_security_get(inode, dir, &si);
status = ocfs2_init_security_get(inode, dir, &dentry->d_name, &si);
if (status) {
if (status == -EOPNOTSUPP)
si.enable = 0;

View File

@ -4328,7 +4328,8 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir,
/* If the security isn't preserved, we need to re-initialize them. */
if (!preserve) {
error = ocfs2_init_security_and_acl(dir, new_orphan_inode);
error = ocfs2_init_security_and_acl(dir, new_orphan_inode,
&new_dentry->d_name);
if (error)
mlog_errno(error);
}

View File

@ -7185,7 +7185,8 @@ out:
* must not hold any lock expect i_mutex.
*/
int ocfs2_init_security_and_acl(struct inode *dir,
struct inode *inode)
struct inode *inode,
const struct qstr *qstr)
{
int ret = 0;
struct buffer_head *dir_bh = NULL;
@ -7193,7 +7194,7 @@ int ocfs2_init_security_and_acl(struct inode *dir,
.enable = 1,
};
ret = ocfs2_init_security_get(inode, dir, &si);
ret = ocfs2_init_security_get(inode, dir, qstr, &si);
if (!ret) {
ret = ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_SECURITY,
si.name, si.value, si.value_len,
@ -7261,13 +7262,14 @@ static int ocfs2_xattr_security_set(struct dentry *dentry, const char *name,
int ocfs2_init_security_get(struct inode *inode,
struct inode *dir,
const struct qstr *qstr,
struct ocfs2_security_xattr_info *si)
{
/* check whether ocfs2 support feature xattr */
if (!ocfs2_supports_xattr(OCFS2_SB(dir->i_sb)))
return -EOPNOTSUPP;
return security_inode_init_security(inode, dir, &si->name, &si->value,
&si->value_len);
return security_inode_init_security(inode, dir, qstr, &si->name,
&si->value, &si->value_len);
}
int ocfs2_init_security_set(handle_t *handle,

View File

@ -57,6 +57,7 @@ int ocfs2_has_inline_xattr_value_outside(struct inode *inode,
struct ocfs2_dinode *di);
int ocfs2_xattr_remove(struct inode *, struct buffer_head *);
int ocfs2_init_security_get(struct inode *, struct inode *,
const struct qstr *,
struct ocfs2_security_xattr_info *);
int ocfs2_init_security_set(handle_t *, struct inode *,
struct buffer_head *,
@ -94,5 +95,6 @@ int ocfs2_reflink_xattrs(struct inode *old_inode,
struct buffer_head *new_bh,
bool preserve_security);
int ocfs2_init_security_and_acl(struct inode *dir,
struct inode *inode);
struct inode *inode,
const struct qstr *qstr);
#endif /* OCFS2_XATTR_H */

View File

@ -714,7 +714,8 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
if (error)
goto cleanup_all;
}
ima_counts_get(f);
if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
i_readcount_inc(inode);
f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

View File

@ -32,7 +32,6 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
ei->sysctl_entry = table;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */
inode->i_mode = table->mode;
if (!table->child) {
inode->i_mode |= S_IFREG;

View File

@ -593,7 +593,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
new_inode_init(inode, dir, mode);
jbegin_count += reiserfs_cache_default_acl(dir);
retval = reiserfs_security_init(dir, inode, &security);
retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security);
if (retval < 0) {
drop_new_inode(inode);
return retval;
@ -667,7 +667,7 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
new_inode_init(inode, dir, mode);
jbegin_count += reiserfs_cache_default_acl(dir);
retval = reiserfs_security_init(dir, inode, &security);
retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security);
if (retval < 0) {
drop_new_inode(inode);
return retval;
@ -747,7 +747,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
new_inode_init(inode, dir, mode);
jbegin_count += reiserfs_cache_default_acl(dir);
retval = reiserfs_security_init(dir, inode, &security);
retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security);
if (retval < 0) {
drop_new_inode(inode);
return retval;
@ -1032,7 +1032,8 @@ static int reiserfs_symlink(struct inode *parent_dir,
}
new_inode_init(inode, parent_dir, mode);
retval = reiserfs_security_init(parent_dir, inode, &security);
retval = reiserfs_security_init(parent_dir, inode, &dentry->d_name,
&security);
if (retval < 0) {
drop_new_inode(inode);
return retval;

View File

@ -54,6 +54,7 @@ static size_t security_list(struct dentry *dentry, char *list, size_t list_len,
* of blocks needed for the transaction. If successful, reiserfs_security
* must be released using reiserfs_security_free when the caller is done. */
int reiserfs_security_init(struct inode *dir, struct inode *inode,
const struct qstr *qstr,
struct reiserfs_security_handle *sec)
{
int blocks = 0;
@ -65,7 +66,7 @@ int reiserfs_security_init(struct inode *dir, struct inode *inode,
if (IS_PRIVATE(dir))
return 0;
error = security_inode_init_security(inode, dir, &sec->name,
error = security_inode_init_security(inode, dir, qstr, &sec->name,
&sec->value, &sec->length);
if (error) {
if (error == -EOPNOTSUPP)

View File

@ -102,7 +102,8 @@ xfs_mark_inode_dirty(
STATIC int
xfs_init_security(
struct inode *inode,
struct inode *dir)
struct inode *dir,
const struct qstr *qstr)
{
struct xfs_inode *ip = XFS_I(inode);
size_t length;
@ -110,7 +111,7 @@ xfs_init_security(
unsigned char *name;
int error;
error = security_inode_init_security(inode, dir, (char **)&name,
error = security_inode_init_security(inode, dir, qstr, (char **)&name,
&value, &length);
if (error) {
if (error == -EOPNOTSUPP)
@ -194,7 +195,7 @@ xfs_vn_mknod(
inode = VFS_I(ip);
error = xfs_init_security(inode, dir);
error = xfs_init_security(inode, dir, &dentry->d_name);
if (unlikely(error))
goto out_cleanup_inode;
@ -367,7 +368,7 @@ xfs_vn_symlink(
inode = VFS_I(cip);
error = xfs_init_security(inode, dir);
error = xfs_init_security(inode, dir, &dentry->d_name);
if (unlikely(error))
goto out_cleanup_inode;

View File

@ -884,7 +884,8 @@ extern int ext3fs_dirhash(const char *name, int len, struct
dx_hash_info *hinfo);
/* ialloc.c */
extern struct inode * ext3_new_inode (handle_t *, struct inode *, int);
extern struct inode * ext3_new_inode (handle_t *, struct inode *,
const struct qstr *, int);
extern void ext3_free_inode (handle_t *, struct inode *);
extern struct inode * ext3_orphan_get (struct super_block *, unsigned long);
extern unsigned long ext3_count_free_inodes (struct super_block *);

View File

@ -801,8 +801,7 @@ struct inode {
#endif
#ifdef CONFIG_IMA
/* protected by i_lock */
unsigned int i_readcount; /* struct files open RO */
atomic_t i_readcount; /* struct files open RO */
#endif
atomic_t i_writecount;
#ifdef CONFIG_SECURITY
@ -2215,6 +2214,26 @@ static inline void allow_write_access(struct file *file)
if (file)
atomic_inc(&file->f_path.dentry->d_inode->i_writecount);
}
#ifdef CONFIG_IMA
static inline void i_readcount_dec(struct inode *inode)
{
BUG_ON(!atomic_read(&inode->i_readcount));
atomic_dec(&inode->i_readcount);
}
static inline void i_readcount_inc(struct inode *inode)
{
atomic_inc(&inode->i_readcount);
}
#else
static inline void i_readcount_dec(struct inode *inode)
{
return;
}
static inline void i_readcount_inc(struct inode *inode)
{
return;
}
#endif
extern int do_pipe_flags(int *, int);
extern struct file *create_read_pipe(struct file *f, int flags);
extern struct file *create_write_pipe(int flags);

View File

@ -20,7 +20,6 @@ extern void ima_inode_free(struct inode *inode);
extern int ima_file_check(struct file *file, int mask);
extern void ima_file_free(struct file *file);
extern int ima_file_mmap(struct file *file, unsigned long prot);
extern void ima_counts_get(struct file *file);
#else
static inline int ima_bprm_check(struct linux_binprm *bprm)
@ -53,10 +52,5 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot)
return 0;
}
static inline void ima_counts_get(struct file *file)
{
return;
}
#endif /* CONFIG_IMA_H */
#endif /* _LINUX_IMA_H */

View File

@ -41,6 +41,9 @@ struct key_type {
*/
size_t def_datalen;
/* vet a description */
int (*vet_description)(const char *description);
/* instantiate a key of this type
* - this method should call key_payload_reserve() to determine if the
* user's quota will hold the payload
@ -102,11 +105,20 @@ extern int key_instantiate_and_link(struct key *key,
size_t datalen,
struct key *keyring,
struct key *instkey);
extern int key_negate_and_link(struct key *key,
extern int key_reject_and_link(struct key *key,
unsigned timeout,
unsigned error,
struct key *keyring,
struct key *instkey);
extern void complete_request_key(struct key_construction *cons, int error);
static inline int key_negate_and_link(struct key *key,
unsigned timeout,
struct key *keyring,
struct key *instkey)
{
return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey);
}
#endif /* CONFIG_KEYS */
#endif /* _LINUX_KEY_TYPE_H */

View File

@ -170,6 +170,7 @@ struct key {
struct list_head link;
unsigned long x[2];
void *p[2];
int reject_error;
} type_data;
/* key data
@ -275,6 +276,10 @@ static inline key_serial_t key_serial(struct key *key)
return key ? key->serial : 0;
}
#define rcu_dereference_key(KEY) \
(rcu_dereference_protected((KEY)->payload.rcudata, \
rwsem_is_locked(&((struct key *)(KEY))->sem)))
#ifdef CONFIG_SYSCTL
extern ctl_table key_sysctls[];
#endif

View File

@ -53,5 +53,7 @@
#define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */
#define KEYCTL_GET_SECURITY 17 /* get key security label */
#define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */
#define KEYCTL_REJECT 19 /* reject a partially constructed key */
#define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */
#endif /* _LINUX_KEYCTL_H */

View File

@ -63,6 +63,7 @@ extern const struct xattr_handler reiserfs_xattr_trusted_handler;
extern const struct xattr_handler reiserfs_xattr_security_handler;
#ifdef CONFIG_REISERFS_FS_SECURITY
int reiserfs_security_init(struct inode *dir, struct inode *inode,
const struct qstr *qstr,
struct reiserfs_security_handle *sec);
int reiserfs_security_write(struct reiserfs_transaction_handle *th,
struct inode *inode,
@ -130,6 +131,7 @@ static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
#ifndef CONFIG_REISERFS_FS_SECURITY
static inline int reiserfs_security_init(struct inode *dir,
struct inode *inode,
const struct qstr *qstr,
struct reiserfs_security_handle *sec)
{
return 0;

View File

@ -25,6 +25,7 @@
#include <linux/fs.h>
#include <linux/fsnotify.h>
#include <linux/binfmts.h>
#include <linux/dcache.h>
#include <linux/signal.h>
#include <linux/resource.h>
#include <linux/sem.h>
@ -267,6 +268,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @orig the original mount data copied from userspace.
* @copy copied data which will be passed to the security module.
* Returns 0 if the copy was successful.
* @sb_remount:
* Extracts security system specifc mount options and verifys no changes
* are being made to those options.
* @sb superblock being remounted
* @data contains the filesystem-specific data.
* Return 0 if permission is granted.
* @sb_umount:
* Check permission before the @mnt file system is unmounted.
* @mnt contains the mounted file system.
@ -315,6 +322,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* then it should return -EOPNOTSUPP to skip this processing.
* @inode contains the inode structure of the newly created inode.
* @dir contains the inode structure of the parent directory.
* @qstr contains the last path component of the new object
* @name will be set to the allocated name suffix (e.g. selinux).
* @value will be set to the allocated attribute value.
* @len will be set to the length of the value.
@ -1257,12 +1265,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @cap contains the capability <include/linux/capability.h>.
* @audit: Whether to write an audit message or not
* Return 0 if the capability is granted for @tsk.
* @sysctl:
* Check permission before accessing the @table sysctl variable in the
* manner specified by @op.
* @table contains the ctl_table structure for the sysctl variable.
* @op contains the operation (001 = search, 002 = write, 004 = read).
* Return 0 if permission is granted.
* @syslog:
* Check permission before accessing the kernel message ring or changing
* logging to the console.
@ -1383,7 +1385,6 @@ struct security_operations {
const kernel_cap_t *permitted);
int (*capable) (struct task_struct *tsk, const struct cred *cred,
int cap, int audit);
int (*sysctl) (struct ctl_table *table, int op);
int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
int (*quota_on) (struct dentry *dentry);
int (*syslog) (int type);
@ -1399,6 +1400,7 @@ struct security_operations {
int (*sb_alloc_security) (struct super_block *sb);
void (*sb_free_security) (struct super_block *sb);
int (*sb_copy_data) (char *orig, char *copy);
int (*sb_remount) (struct super_block *sb, void *data);
int (*sb_kern_mount) (struct super_block *sb, int flags, void *data);
int (*sb_show_options) (struct seq_file *m, struct super_block *sb);
int (*sb_statfs) (struct dentry *dentry);
@ -1435,7 +1437,8 @@ struct security_operations {
int (*inode_alloc_security) (struct inode *inode);
void (*inode_free_security) (struct inode *inode);
int (*inode_init_security) (struct inode *inode, struct inode *dir,
char **name, void **value, size_t *len);
const struct qstr *qstr, char **name,
void **value, size_t *len);
int (*inode_create) (struct inode *dir,
struct dentry *dentry, int mode);
int (*inode_link) (struct dentry *old_dentry,
@ -1665,7 +1668,6 @@ int security_capset(struct cred *new, const struct cred *old,
int security_capable(const struct cred *cred, int cap);
int security_real_capable(struct task_struct *tsk, int cap);
int security_real_capable_noaudit(struct task_struct *tsk, int cap);
int security_sysctl(struct ctl_table *table, int op);
int security_quotactl(int cmds, int type, int id, struct super_block *sb);
int security_quota_on(struct dentry *dentry);
int security_syslog(int type);
@ -1681,6 +1683,7 @@ int security_bprm_secureexec(struct linux_binprm *bprm);
int security_sb_alloc(struct super_block *sb);
void security_sb_free(struct super_block *sb);
int security_sb_copy_data(char *orig, char *copy);
int security_sb_remount(struct super_block *sb, void *data);
int security_sb_kern_mount(struct super_block *sb, int flags, void *data);
int security_sb_show_options(struct seq_file *m, struct super_block *sb);
int security_sb_statfs(struct dentry *dentry);
@ -1696,7 +1699,8 @@ int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
int security_inode_alloc(struct inode *inode);
void security_inode_free(struct inode *inode);
int security_inode_init_security(struct inode *inode, struct inode *dir,
char **name, void **value, size_t *len);
const struct qstr *qstr, char **name,
void **value, size_t *len);
int security_inode_create(struct inode *dir, struct dentry *dentry, int mode);
int security_inode_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry);
@ -1883,11 +1887,6 @@ int security_real_capable_noaudit(struct task_struct *tsk, int cap)
return ret;
}
static inline int security_sysctl(struct ctl_table *table, int op)
{
return 0;
}
static inline int security_quotactl(int cmds, int type, int id,
struct super_block *sb)
{
@ -1965,6 +1964,11 @@ static inline int security_sb_copy_data(char *orig, char *copy)
return 0;
}
static inline int security_sb_remount(struct super_block *sb, void *data)
{
return 0;
}
static inline int security_sb_kern_mount(struct super_block *sb, int flags, void *data)
{
return 0;
@ -2024,6 +2028,7 @@ static inline void security_inode_free(struct inode *inode)
static inline int security_inode_init_security(struct inode *inode,
struct inode *dir,
const struct qstr *qstr,
char **name,
void **value,
size_t *len)

View File

@ -42,11 +42,13 @@
#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
#define XATTR_SMACK_EXEC "SMACK64EXEC"
#define XATTR_SMACK_TRANSMUTE "SMACK64TRANSMUTE"
#define XATTR_SMACK_MMAP "SMACK64MMAP"
#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
#define XATTR_NAME_SMACKEXEC XATTR_SECURITY_PREFIX XATTR_SMACK_EXEC
#define XATTR_NAME_SMACKTRANSMUTE XATTR_SECURITY_PREFIX XATTR_SMACK_TRANSMUTE
#define XATTR_NAME_SMACKMMAP XATTR_SECURITY_PREFIX XATTR_SMACK_MMAP
#define XATTR_CAPS_SUFFIX "capability"
#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX

View File

@ -1683,13 +1683,8 @@ static int test_perm(int mode, int op)
int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
{
int error;
int mode;
error = security_sysctl(table, op & (MAY_READ | MAY_WRITE | MAY_EXEC));
if (error)
return error;
if (root->permissions)
mode = root->permissions(root, current->nsproxy, table);
else

View File

@ -1843,8 +1843,9 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);
if (inode) {
error = security_inode_init_security(inode, dir, NULL, NULL,
NULL);
error = security_inode_init_security(inode, dir,
&dentry->d_name, NULL,
NULL, NULL);
if (error) {
if (error != -EOPNOTSUPP) {
iput(inode);
@ -1983,8 +1984,8 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
if (!inode)
return -ENOSPC;
error = security_inode_init_security(inode, dir, NULL, NULL,
NULL);
error = security_inode_init_security(inode, dir, &dentry->d_name, NULL,
NULL, NULL);
if (error) {
if (error != -EOPNOTSUPP) {
iput(inode);

View File

@ -25,6 +25,7 @@
#include <keys/user-type.h>
#include "ar-internal.h"
static int rxrpc_vet_description_s(const char *);
static int rxrpc_instantiate(struct key *, const void *, size_t);
static int rxrpc_instantiate_s(struct key *, const void *, size_t);
static void rxrpc_destroy(struct key *);
@ -52,12 +53,30 @@ EXPORT_SYMBOL(key_type_rxrpc);
*/
struct key_type key_type_rxrpc_s = {
.name = "rxrpc_s",
.vet_description = rxrpc_vet_description_s,
.instantiate = rxrpc_instantiate_s,
.match = user_match,
.destroy = rxrpc_destroy_s,
.describe = rxrpc_describe,
};
/*
* Vet the description for an RxRPC server key
*/
static int rxrpc_vet_description_s(const char *desc)
{
unsigned long num;
char *p;
num = simple_strtoul(desc, &p, 10);
if (*p != ':' || num > 65535)
return -EINVAL;
num = simple_strtoul(p + 1, &p, 10);
if (*p || num < 1 || num > 255)
return -EINVAL;
return 0;
}
/*
* parse an RxKAD type XDR format token
* - the caller guarantees we have at least 4 words

View File

@ -43,6 +43,8 @@ int main(int argc, char *argv[])
int i, j, k;
int isids_len;
FILE *fout;
const char *needle = "SOCKET";
char *substr;
progname = argv[0];
@ -88,6 +90,24 @@ int main(int argc, char *argv[])
fprintf(fout, "%2d\n", i);
}
fprintf(fout, "\n#define SECINITSID_NUM %d\n", i-1);
fprintf(fout, "\nstatic inline bool security_is_socket_class(u16 kern_tclass)\n");
fprintf(fout, "{\n");
fprintf(fout, "\tbool sock = false;\n\n");
fprintf(fout, "\tswitch (kern_tclass) {\n");
for (i = 0; secclass_map[i].name; i++) {
struct security_class_mapping *map = &secclass_map[i];
substr = strstr(map->name, needle);
if (substr && strcmp(substr, needle) == 0)
fprintf(fout, "\tcase SECCLASS_%s:\n", map->name);
}
fprintf(fout, "\t\tsock = true;\n");
fprintf(fout, "\t\tbreak;\n");
fprintf(fout, "\tdefault:\n");
fprintf(fout, "\t\tbreak;\n");
fprintf(fout, "\t}\n\n");
fprintf(fout, "\treturn sock;\n");
fprintf(fout, "}\n");
fprintf(fout, "\n#endif\n");
fclose(fout);

View File

@ -6,19 +6,47 @@ apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
resource.o sid.o file.o
clean-files: capability_names.h af_names.h
clean-files := capability_names.h rlim_names.h
# Build a lower case string table of capability names
# Transforms lines from
# #define CAP_DAC_OVERRIDE 1
# to
# [1] = "dac_override",
quiet_cmd_make-caps = GEN $@
cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ; sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@
cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ;\
sed $< >>$@ -r -n -e '/CAP_FS_MASK/d' \
-e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\
echo "};" >> $@
# Build a lower case string table of rlimit names.
# Transforms lines from
# #define RLIMIT_STACK 3 /* max stack size */
# to
# [RLIMIT_STACK] = "stack",
#
# and build a second integer table (with the second sed cmd), that maps
# RLIMIT defines to the order defined in asm-generic/resource.h Thi is
# required by policy load to map policy ordering of RLIMITs to internal
# ordering for architectures that redefine an RLIMIT.
# Transforms lines from
# #define RLIMIT_STACK 3 /* max stack size */
# to
# RLIMIT_STACK,
quiet_cmd_make-rlim = GEN $@
cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ; sed -n --e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+RLIMIT_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@ ; echo "static const int rlim_map[] = {" >> $@ ; sed -n -e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+\\(RLIMIT_[A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/\\1,/p" $< >> $@ ; echo "};" >> $@
cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ;\
sed $< >> $@ -r -n \
-e 's/^\# ?define[ \t]+(RLIMIT_([A-Z0-9_]+)).*/[\1] = "\L\2",/p';\
echo "};" >> $@ ;\
echo "static const int rlim_map[] = {" >> $@ ;\
sed -r -n "s/^\# ?define[ \t]+(RLIMIT_[A-Z0-9_]+).*/\1,/p" $< >> $@ ;\
echo "};" >> $@
$(obj)/capability.o : $(obj)/capability_names.h
$(obj)/resource.o : $(obj)/rlim_names.h
$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
$(call cmd,make-caps)
$(obj)/af_names.h : $(srctree)/include/linux/socket.h
$(call cmd,make-af)
$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h
$(call cmd,make-rlim)

View File

@ -693,11 +693,9 @@ static struct kernel_param_ops param_ops_aalockpolicy = {
static int param_set_audit(const char *val, struct kernel_param *kp);
static int param_get_audit(char *buffer, struct kernel_param *kp);
#define param_check_audit(name, p) __param_check(name, p, int)
static int param_set_mode(const char *val, struct kernel_param *kp);
static int param_get_mode(char *buffer, struct kernel_param *kp);
#define param_check_mode(name, p) __param_check(name, p, int)
/* Flag values, also controllable via /sys/module/apparmor/parameters
* We define special types as we want to do additional mediation.

View File

@ -12,11 +12,6 @@
#include <linux/security.h>
static int cap_sysctl(ctl_table *table, int op)
{
return 0;
}
static int cap_syslog(int type)
{
return 0;
@ -59,6 +54,11 @@ static int cap_sb_copy_data(char *orig, char *copy)
return 0;
}
static int cap_sb_remount(struct super_block *sb, void *data)
{
return 0;
}
static int cap_sb_kern_mount(struct super_block *sb, int flags, void *data)
{
return 0;
@ -118,7 +118,8 @@ static void cap_inode_free_security(struct inode *inode)
}
static int cap_inode_init_security(struct inode *inode, struct inode *dir,
char **name, void **value, size_t *len)
const struct qstr *qstr, char **name,
void **value, size_t *len)
{
return -EOPNOTSUPP;
}
@ -880,7 +881,6 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, capable);
set_to_cap_if_null(ops, quotactl);
set_to_cap_if_null(ops, quota_on);
set_to_cap_if_null(ops, sysctl);
set_to_cap_if_null(ops, syslog);
set_to_cap_if_null(ops, settime);
set_to_cap_if_null(ops, vm_enough_memory);
@ -892,6 +892,7 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, sb_alloc_security);
set_to_cap_if_null(ops, sb_free_security);
set_to_cap_if_null(ops, sb_copy_data);
set_to_cap_if_null(ops, sb_remount);
set_to_cap_if_null(ops, sb_kern_mount);
set_to_cap_if_null(ops, sb_show_options);
set_to_cap_if_null(ops, sb_statfs);

View File

@ -110,8 +110,7 @@ struct ima_iint_cache {
};
/* LIM API function definitions */
int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
int mask, int function);
int ima_must_measure(struct inode *inode, int mask, int function);
int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file);
void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
const unsigned char *filename);

View File

@ -105,20 +105,13 @@ err_out:
* mask: contains the permission mask
* fsmagic: hex value
*
* Must be called with iint->mutex held.
*
* Return 0 to measure. Return 1 if already measured.
* For matching a DONT_MEASURE policy, no policy, or other
* error, return an error code.
* Return 0 to measure. For matching a DONT_MEASURE policy, no policy,
* or other error, return an error code.
*/
int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
int mask, int function)
int ima_must_measure(struct inode *inode, int mask, int function)
{
int must_measure;
if (iint && iint->flags & IMA_MEASURED)
return 1;
must_measure = ima_match_policy(inode, function, mask);
return must_measure ? 0 : -EACCES;
}

View File

@ -137,11 +137,6 @@ void ima_inode_free(struct inode *inode)
{
struct ima_iint_cache *iint;
if (inode->i_readcount)
printk(KERN_INFO "%s: readcount: %u\n", __func__, inode->i_readcount);
inode->i_readcount = 0;
if (!IS_IMA(inode))
return;

View File

@ -36,67 +36,17 @@ static int __init hash_setup(char *str)
}
__setup("ima_hash=", hash_setup);
struct ima_imbalance {
struct hlist_node node;
unsigned long fsmagic;
};
/*
* ima_limit_imbalance - emit one imbalance message per filesystem type
* ima_rdwr_violation_check
*
* Maintain list of filesystem types that do not measure files properly.
* Return false if unknown, true if known.
*/
static bool ima_limit_imbalance(struct file *file)
{
static DEFINE_SPINLOCK(ima_imbalance_lock);
static HLIST_HEAD(ima_imbalance_list);
struct super_block *sb = file->f_dentry->d_sb;
struct ima_imbalance *entry;
struct hlist_node *node;
bool found = false;
rcu_read_lock();
hlist_for_each_entry_rcu(entry, node, &ima_imbalance_list, node) {
if (entry->fsmagic == sb->s_magic) {
found = true;
break;
}
}
rcu_read_unlock();
if (found)
goto out;
entry = kmalloc(sizeof(*entry), GFP_NOFS);
if (!entry)
goto out;
entry->fsmagic = sb->s_magic;
spin_lock(&ima_imbalance_lock);
/*
* we could have raced and something else might have added this fs
* to the list, but we don't really care
*/
hlist_add_head_rcu(&entry->node, &ima_imbalance_list);
spin_unlock(&ima_imbalance_lock);
printk(KERN_INFO "IMA: unmeasured files on fsmagic: %lX\n",
entry->fsmagic);
out:
return found;
}
/*
* ima_counts_get - increment file counts
*
* Maintain read/write counters for all files, but only
* invalidate the PCR for measured files:
* Only invalidate the PCR for measured files:
* - Opening a file for write when already open for read,
* results in a time of measure, time of use (ToMToU) error.
* - Opening a file for read when already open for write,
* could result in a file measurement error.
*
*/
void ima_counts_get(struct file *file)
static void ima_rdwr_violation_check(struct file *file)
{
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
@ -104,32 +54,25 @@ void ima_counts_get(struct file *file)
int rc;
bool send_tomtou = false, send_writers = false;
if (!S_ISREG(inode->i_mode))
if (!S_ISREG(inode->i_mode) || !ima_initialized)
return;
spin_lock(&inode->i_lock);
if (!ima_initialized)
goto out;
mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */
if (mode & FMODE_WRITE) {
if (inode->i_readcount && IS_IMA(inode))
if (atomic_read(&inode->i_readcount) && IS_IMA(inode))
send_tomtou = true;
goto out;
}
rc = ima_must_measure(NULL, inode, MAY_READ, FILE_CHECK);
rc = ima_must_measure(inode, MAY_READ, FILE_CHECK);
if (rc < 0)
goto out;
if (atomic_read(&inode->i_writecount) > 0)
send_writers = true;
out:
/* remember the vfs deals with i_writecount */
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
inode->i_readcount++;
spin_unlock(&inode->i_lock);
mutex_unlock(&inode->i_mutex);
if (send_tomtou)
ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
@ -139,71 +82,25 @@ out:
"open_writers");
}
/*
* Decrement ima counts
*/
static void ima_dec_counts(struct inode *inode, struct file *file)
{
mode_t mode = file->f_mode;
assert_spin_locked(&inode->i_lock);
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
if (unlikely(inode->i_readcount == 0)) {
if (!ima_limit_imbalance(file)) {
printk(KERN_INFO "%s: open/free imbalance (r:%u)\n",
__func__, inode->i_readcount);
dump_stack();
}
return;
}
inode->i_readcount--;
}
}
static void ima_check_last_writer(struct ima_iint_cache *iint,
struct inode *inode,
struct file *file)
{
mode_t mode = file->f_mode;
BUG_ON(!mutex_is_locked(&iint->mutex));
assert_spin_locked(&inode->i_lock);
mutex_lock(&iint->mutex);
if (mode & FMODE_WRITE &&
atomic_read(&inode->i_writecount) == 1 &&
iint->version != inode->i_version)
iint->flags &= ~IMA_MEASURED;
}
static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode,
struct file *file)
{
mutex_lock(&iint->mutex);
spin_lock(&inode->i_lock);
ima_dec_counts(inode, file);
ima_check_last_writer(iint, inode, file);
spin_unlock(&inode->i_lock);
mutex_unlock(&iint->mutex);
}
static void ima_file_free_noiint(struct inode *inode, struct file *file)
{
spin_lock(&inode->i_lock);
ima_dec_counts(inode, file);
spin_unlock(&inode->i_lock);
}
/**
* ima_file_free - called on __fput()
* @file: pointer to file structure being freed
*
* Flag files that changed, based on i_version;
* and decrement the i_readcount.
* Flag files that changed, based on i_version
*/
void ima_file_free(struct file *file)
{
@ -214,12 +111,10 @@ void ima_file_free(struct file *file)
return;
iint = ima_iint_find(inode);
if (!iint)
return;
if (iint)
ima_file_free_iint(iint, inode, file);
else
ima_file_free_noiint(inode, file);
ima_check_last_writer(iint, inode, file);
}
static int process_measurement(struct file *file, const unsigned char *filename,
@ -232,7 +127,7 @@ static int process_measurement(struct file *file, const unsigned char *filename,
if (!ima_initialized || !S_ISREG(inode->i_mode))
return 0;
rc = ima_must_measure(NULL, inode, mask, function);
rc = ima_must_measure(inode, mask, function);
if (rc != 0)
return rc;
retry:
@ -246,7 +141,7 @@ retry:
mutex_lock(&iint->mutex);
rc = ima_must_measure(iint, inode, mask, function);
rc = iint->flags & IMA_MEASURED ? 1 : 0;
if (rc != 0)
goto out;
@ -317,6 +212,7 @@ int ima_file_check(struct file *file, int mask)
{
int rc;
ima_rdwr_violation_check(file);
rc = process_measurement(file, file->f_dentry->d_name.name,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
FILE_CHECK);

View File

@ -12,8 +12,51 @@
#include <linux/syscalls.h>
#include <linux/keyctl.h>
#include <linux/compat.h>
#include <linux/slab.h>
#include "internal.h"
/*
* Instantiate a key with the specified compatibility multipart payload and
* link the key into the destination keyring if one is given.
*
* The caller must have the appropriate instantiation permit set for this to
* work (see keyctl_assume_authority). No other permissions are required.
*
* If successful, 0 will be returned.
*/
long compat_keyctl_instantiate_key_iov(
key_serial_t id,
const struct compat_iovec __user *_payload_iov,
unsigned ioc,
key_serial_t ringid)
{
struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
long ret;
if (_payload_iov == 0 || ioc == 0)
goto no_payload;
ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc,
ARRAY_SIZE(iovstack),
iovstack, &iov);
if (ret < 0)
return ret;
if (ret == 0)
goto no_payload_free;
ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
if (iov != iovstack)
kfree(iov);
return ret;
no_payload_free:
if (iov != iovstack)
kfree(iov);
no_payload:
return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
}
/*
* The key control system call, 32-bit compatibility version for 64-bit archs
*
@ -85,6 +128,13 @@ asmlinkage long compat_sys_keyctl(u32 option,
case KEYCTL_SESSION_TO_PARENT:
return keyctl_session_to_parent();
case KEYCTL_REJECT:
return keyctl_reject_key(arg2, arg3, arg4, arg5);
case KEYCTL_INSTANTIATE_IOV:
return compat_keyctl_instantiate_key_iov(
arg2, compat_ptr(arg3), arg4, arg5);
default:
return -EOPNOTSUPP;
}

View File

@ -765,8 +765,7 @@ static long encrypted_read(const struct key *key, char __user *buffer,
size_t asciiblob_len;
int ret;
epayload = rcu_dereference_protected(key->payload.data,
rwsem_is_locked(&((struct key *)key)->sem));
epayload = rcu_dereference_key(key);
/* returns the hex encoded iv, encrypted-data, and hmac as ascii */
asciiblob_len = epayload->datablob_len + ivsize + 1

View File

@ -214,6 +214,14 @@ extern long keyctl_assume_authority(key_serial_t);
extern long keyctl_get_security(key_serial_t keyid, char __user *buffer,
size_t buflen);
extern long keyctl_session_to_parent(void);
extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t);
extern long keyctl_instantiate_key_iov(key_serial_t,
const struct iovec __user *,
unsigned, key_serial_t);
extern long keyctl_instantiate_key_common(key_serial_t,
const struct iovec __user *,
unsigned, size_t, key_serial_t);
/*
* Debugging key validation

View File

@ -249,6 +249,14 @@ struct key *key_alloc(struct key_type *type, const char *desc,
if (!desc || !*desc)
goto error;
if (type->vet_description) {
ret = type->vet_description(desc);
if (ret < 0) {
key = ERR_PTR(ret);
goto error;
}
}
desclen = strlen(desc) + 1;
quotalen = desclen + type->def_datalen;
@ -503,26 +511,29 @@ int key_instantiate_and_link(struct key *key,
EXPORT_SYMBOL(key_instantiate_and_link);
/**
* key_negate_and_link - Negatively instantiate a key and link it into the keyring.
* key_reject_and_link - Negatively instantiate a key and link it into the keyring.
* @key: The key to instantiate.
* @timeout: The timeout on the negative key.
* @error: The error to return when the key is hit.
* @keyring: Keyring to create a link in on success (or NULL).
* @authkey: The authorisation token permitting instantiation.
*
* Negatively instantiate a key that's in the uninstantiated state and, if
* successful, set its timeout and link it in to the destination keyring if one
* is supplied. The key and any links to the key will be automatically garbage
* collected after the timeout expires.
* successful, set its timeout and stored error and link it in to the
* destination keyring if one is supplied. The key and any links to the key
* will be automatically garbage collected after the timeout expires.
*
* Negative keys are used to rate limit repeated request_key() calls by causing
* them to return -ENOKEY until the negative key expires.
* them to return the stored error code (typically ENOKEY) until the negative
* key expires.
*
* If successful, 0 is returned, the authorisation token is revoked and anyone
* waiting for the key is woken up. If the key was already instantiated,
* -EBUSY will be returned.
*/
int key_negate_and_link(struct key *key,
int key_reject_and_link(struct key *key,
unsigned timeout,
unsigned error,
struct key *keyring,
struct key *authkey)
{
@ -548,6 +559,7 @@ int key_negate_and_link(struct key *key,
atomic_inc(&key->user->nikeys);
set_bit(KEY_FLAG_NEGATIVE, &key->flags);
set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
key->type_data.reject_error = -error;
now = current_kernel_time();
key->expiry = now.tv_sec + timeout;
key_schedule_gc(key->expiry + key_gc_delay);
@ -577,8 +589,7 @@ int key_negate_and_link(struct key *key,
return ret == 0 ? link_ret : ret;
}
EXPORT_SYMBOL(key_negate_and_link);
EXPORT_SYMBOL(key_reject_and_link);
/*
* Garbage collect keys in process context so that we don't have to disable

View File

@ -912,6 +912,21 @@ static int keyctl_change_reqkey_auth(struct key *key)
return commit_creds(new);
}
/*
* Copy the iovec data from userspace
*/
static long copy_from_user_iovec(void *buffer, const struct iovec *iov,
unsigned ioc)
{
for (; ioc > 0; ioc--) {
if (copy_from_user(buffer, iov->iov_base, iov->iov_len) != 0)
return -EFAULT;
buffer += iov->iov_len;
iov++;
}
return 0;
}
/*
* Instantiate a key with the specified payload and link the key into the
* destination keyring if one is given.
@ -921,10 +936,11 @@ static int keyctl_change_reqkey_auth(struct key *key)
*
* If successful, 0 will be returned.
*/
long keyctl_instantiate_key(key_serial_t id,
const void __user *_payload,
size_t plen,
key_serial_t ringid)
long keyctl_instantiate_key_common(key_serial_t id,
const struct iovec *payload_iov,
unsigned ioc,
size_t plen,
key_serial_t ringid)
{
const struct cred *cred = current_cred();
struct request_key_auth *rka;
@ -953,7 +969,7 @@ long keyctl_instantiate_key(key_serial_t id,
/* pull the payload in if one was supplied */
payload = NULL;
if (_payload) {
if (payload_iov) {
ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL);
if (!payload) {
@ -965,8 +981,8 @@ long keyctl_instantiate_key(key_serial_t id,
goto error;
}
ret = -EFAULT;
if (copy_from_user(payload, _payload, plen) != 0)
ret = copy_from_user_iovec(payload, payload_iov, ioc);
if (ret < 0)
goto error2;
}
@ -996,6 +1012,72 @@ error:
return ret;
}
/*
* Instantiate a key with the specified payload and link the key into the
* destination keyring if one is given.
*
* The caller must have the appropriate instantiation permit set for this to
* work (see keyctl_assume_authority). No other permissions are required.
*
* If successful, 0 will be returned.
*/
long keyctl_instantiate_key(key_serial_t id,
const void __user *_payload,
size_t plen,
key_serial_t ringid)
{
if (_payload && plen) {
struct iovec iov[1] = {
[0].iov_base = (void __user *)_payload,
[0].iov_len = plen
};
return keyctl_instantiate_key_common(id, iov, 1, plen, ringid);
}
return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
}
/*
* Instantiate a key with the specified multipart payload and link the key into
* the destination keyring if one is given.
*
* The caller must have the appropriate instantiation permit set for this to
* work (see keyctl_assume_authority). No other permissions are required.
*
* If successful, 0 will be returned.
*/
long keyctl_instantiate_key_iov(key_serial_t id,
const struct iovec __user *_payload_iov,
unsigned ioc,
key_serial_t ringid)
{
struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
long ret;
if (_payload_iov == 0 || ioc == 0)
goto no_payload;
ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
ARRAY_SIZE(iovstack), iovstack, &iov);
if (ret < 0)
return ret;
if (ret == 0)
goto no_payload_free;
ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
if (iov != iovstack)
kfree(iov);
return ret;
no_payload_free:
if (iov != iovstack)
kfree(iov);
no_payload:
return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
}
/*
* Negatively instantiate the key with the given timeout (in seconds) and link
* the key into the destination keyring if one is given.
@ -1012,13 +1094,43 @@ error:
* If successful, 0 will be returned.
*/
long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
{
return keyctl_reject_key(id, timeout, ENOKEY, ringid);
}
/*
* Negatively instantiate the key with the given timeout (in seconds) and error
* code and link the key into the destination keyring if one is given.
*
* The caller must have the appropriate instantiation permit set for this to
* work (see keyctl_assume_authority). No other permissions are required.
*
* The key and any links to the key will be automatically garbage collected
* after the timeout expires.
*
* Negative keys are used to rate limit repeated request_key() calls by causing
* them to return the specified error code until the negative key expires.
*
* If successful, 0 will be returned.
*/
long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error,
key_serial_t ringid)
{
const struct cred *cred = current_cred();
struct request_key_auth *rka;
struct key *instkey, *dest_keyring;
long ret;
kenter("%d,%u,%d", id, timeout, ringid);
kenter("%d,%u,%u,%d", id, timeout, error, ringid);
/* must be a valid error code and mustn't be a kernel special */
if (error <= 0 ||
error >= MAX_ERRNO ||
error == ERESTARTSYS ||
error == ERESTARTNOINTR ||
error == ERESTARTNOHAND ||
error == ERESTART_RESTARTBLOCK)
return -EINVAL;
/* the appropriate instantiation authorisation key must have been
* assumed before calling this */
@ -1038,7 +1150,7 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
goto error;
/* instantiate the key and link it into a keyring */
ret = key_negate_and_link(rka->target_key, timeout,
ret = key_reject_and_link(rka->target_key, timeout, error,
dest_keyring, instkey);
key_put(dest_keyring);
@ -1492,6 +1604,19 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
case KEYCTL_SESSION_TO_PARENT:
return keyctl_session_to_parent();
case KEYCTL_REJECT:
return keyctl_reject_key((key_serial_t) arg2,
(unsigned) arg3,
(unsigned) arg4,
(key_serial_t) arg5);
case KEYCTL_INSTANTIATE_IOV:
return keyctl_instantiate_key_iov(
(key_serial_t) arg2,
(const struct iovec __user *) arg3,
(unsigned) arg4,
(key_serial_t) arg5);
default:
return -EOPNOTSUPP;
}

View File

@ -352,7 +352,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
goto error_2;
if (key->expiry && now.tv_sec >= key->expiry)
goto error_2;
key_ref = ERR_PTR(-ENOKEY);
key_ref = ERR_PTR(key->type_data.reject_error);
if (kflags & (1 << KEY_FLAG_NEGATIVE))
goto error_2;
goto found;
@ -401,7 +401,7 @@ descend:
/* we set a different error code if we pass a negative key */
if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
err = -ENOKEY;
err = key->type_data.reject_error;
continue;
}

View File

@ -585,7 +585,7 @@ int wait_for_key_construction(struct key *key, bool intr)
if (ret < 0)
return ret;
if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
return -ENOKEY;
return key->type_data.reject_error;
return key_validate(key);
}
EXPORT_SYMBOL(wait_for_key_construction);

View File

@ -1076,8 +1076,7 @@ static long trusted_read(const struct key *key, char __user *buffer,
char *bufp;
int i;
p = rcu_dereference_protected(key->payload.data,
rwsem_is_locked(&((struct key *)key)->sem));
p = rcu_dereference_key(key);
if (!p)
return -EINVAL;
if (!buffer || buflen <= 0)

View File

@ -184,8 +184,7 @@ long user_read(const struct key *key, char __user *buffer, size_t buflen)
struct user_key_payload *upayload;
long ret;
upayload = rcu_dereference_protected(
key->payload.data, rwsem_is_locked(&((struct key *)key)->sem));
upayload = rcu_dereference_key(key);
ret = upayload->datalen;
/* we can return the data as is */

View File

@ -181,11 +181,6 @@ int security_real_capable_noaudit(struct task_struct *tsk, int cap)
return ret;
}
int security_sysctl(struct ctl_table *table, int op)
{
return security_ops->sysctl(table, op);
}
int security_quotactl(int cmds, int type, int id, struct super_block *sb)
{
return security_ops->quotactl(cmds, type, id, sb);
@ -271,6 +266,11 @@ int security_sb_copy_data(char *orig, char *copy)
}
EXPORT_SYMBOL(security_sb_copy_data);
int security_sb_remount(struct super_block *sb, void *data)
{
return security_ops->sb_remount(sb, data);
}
int security_sb_kern_mount(struct super_block *sb, int flags, void *data)
{
return security_ops->sb_kern_mount(sb, flags, data);
@ -335,11 +335,13 @@ void security_inode_free(struct inode *inode)
}
int security_inode_init_security(struct inode *inode, struct inode *dir,
char **name, void **value, size_t *len)
const struct qstr *qstr, char **name,
void **value, size_t *len)
{
if (unlikely(IS_PRIVATE(inode)))
return -EOPNOTSUPP;
return security_ops->inode_init_security(inode, dir, name, value, len);
return security_ops->inode_init_security(inode, dir, qstr, name, value,
len);
}
EXPORT_SYMBOL(security_inode_init_security);
@ -359,6 +361,7 @@ int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
return 0;
return security_ops->path_mkdir(dir, dentry, mode);
}
EXPORT_SYMBOL(security_path_mkdir);
int security_path_rmdir(struct path *dir, struct dentry *dentry)
{
@ -373,6 +376,7 @@ int security_path_unlink(struct path *dir, struct dentry *dentry)
return 0;
return security_ops->path_unlink(dir, dentry);
}
EXPORT_SYMBOL(security_path_unlink);
int security_path_symlink(struct path *dir, struct dentry *dentry,
const char *old_name)
@ -399,6 +403,7 @@ int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
return security_ops->path_rename(old_dir, old_dentry, new_dir,
new_dentry);
}
EXPORT_SYMBOL(security_path_rename);
int security_path_truncate(struct path *path)
{

View File

@ -24,9 +24,11 @@
*/
#include <linux/init.h>
#include <linux/kd.h>
#include <linux/kernel.h>
#include <linux/tracehook.h>
#include <linux/errno.h>
#include <linux/ext2_fs.h>
#include <linux/sched.h>
#include <linux/security.h>
#include <linux/xattr.h>
@ -36,14 +38,15 @@
#include <linux/mman.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/proc_fs.h>
#include <linux/swap.h>
#include <linux/spinlock.h>
#include <linux/syscalls.h>
#include <linux/dcache.h>
#include <linux/file.h>
#include <linux/fdtable.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/proc_fs.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/tty.h>
@ -70,7 +73,6 @@
#include <net/ipv6.h>
#include <linux/hugetlb.h>
#include <linux/personality.h>
#include <linux/sysctl.h>
#include <linux/audit.h>
#include <linux/string.h>
#include <linux/selinux.h>
@ -1120,39 +1122,35 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
}
#ifdef CONFIG_PROC_FS
static int selinux_proc_get_sid(struct proc_dir_entry *de,
static int selinux_proc_get_sid(struct dentry *dentry,
u16 tclass,
u32 *sid)
{
int buflen, rc;
char *buffer, *path, *end;
int rc;
char *buffer, *path;
buffer = (char *)__get_free_page(GFP_KERNEL);
if (!buffer)
return -ENOMEM;
buflen = PAGE_SIZE;
end = buffer+buflen;
*--end = '\0';
buflen--;
path = end-1;
*path = '/';
while (de && de != de->parent) {
buflen -= de->namelen + 1;
if (buflen < 0)
break;
end -= de->namelen;
memcpy(end, de->name, de->namelen);
*--end = '/';
path = end;
de = de->parent;
path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
if (IS_ERR(path))
rc = PTR_ERR(path);
else {
/* each process gets a /proc/PID/ entry. Strip off the
* PID part to get a valid selinux labeling.
* e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
while (path[1] >= '0' && path[1] <= '9') {
path[1] = '/';
path++;
}
rc = security_genfs_sid("proc", path, tclass, sid);
}
rc = security_genfs_sid("proc", path, tclass, sid);
free_page((unsigned long)buffer);
return rc;
}
#else
static int selinux_proc_get_sid(struct proc_dir_entry *de,
static int selinux_proc_get_sid(struct dentry *dentry,
u16 tclass,
u32 *sid)
{
@ -1300,10 +1298,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
/* Try to obtain a transition SID. */
isec->sclass = inode_mode_to_security_class(inode->i_mode);
rc = security_transition_sid(isec->task_sid,
sbsec->sid,
isec->sclass,
&sid);
rc = security_transition_sid(isec->task_sid, sbsec->sid,
isec->sclass, NULL, &sid);
if (rc)
goto out_unlock;
isec->sid = sid;
@ -1316,10 +1312,9 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
isec->sid = sbsec->sid;
if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
struct proc_inode *proci = PROC_I(inode);
if (proci->pde) {
if (opt_dentry) {
isec->sclass = inode_mode_to_security_class(inode->i_mode);
rc = selinux_proc_get_sid(proci->pde,
rc = selinux_proc_get_sid(opt_dentry,
isec->sclass,
&sid);
if (rc)
@ -1578,7 +1573,7 @@ static int may_create(struct inode *dir,
return rc;
if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
rc = security_transition_sid(sid, dsec->sid, tclass, NULL, &newsid);
if (rc)
return rc;
}
@ -1862,82 +1857,6 @@ static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
return task_has_capability(tsk, cred, cap, audit);
}
static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
{
int buflen, rc;
char *buffer, *path, *end;
rc = -ENOMEM;
buffer = (char *)__get_free_page(GFP_KERNEL);
if (!buffer)
goto out;
buflen = PAGE_SIZE;
end = buffer+buflen;
*--end = '\0';
buflen--;
path = end-1;
*path = '/';
while (table) {
const char *name = table->procname;
size_t namelen = strlen(name);
buflen -= namelen + 1;
if (buflen < 0)
goto out_free;
end -= namelen;
memcpy(end, name, namelen);
*--end = '/';
path = end;
table = table->parent;
}
buflen -= 4;
if (buflen < 0)
goto out_free;
end -= 4;
memcpy(end, "/sys", 4);
path = end;
rc = security_genfs_sid("proc", path, tclass, sid);
out_free:
free_page((unsigned long)buffer);
out:
return rc;
}
static int selinux_sysctl(ctl_table *table, int op)
{
int error = 0;
u32 av;
u32 tsid, sid;
int rc;
sid = current_sid();
rc = selinux_sysctl_get_sid(table, (op == 0001) ?
SECCLASS_DIR : SECCLASS_FILE, &tsid);
if (rc) {
/* Default to the well-defined sysctl SID. */
tsid = SECINITSID_SYSCTL;
}
/* The op values are "defined" in sysctl.c, thereby creating
* a bad coupling between this module and sysctl.c */
if (op == 001) {
error = avc_has_perm(sid, tsid,
SECCLASS_DIR, DIR__SEARCH, NULL);
} else {
av = 0;
if (op & 004)
av |= FILE__READ;
if (op & 002)
av |= FILE__WRITE;
if (av)
error = avc_has_perm(sid, tsid,
SECCLASS_FILE, av, NULL);
}
return error;
}
static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
{
const struct cred *cred = current_cred();
@ -2060,7 +1979,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
} else {
/* Check for a default transition on this program. */
rc = security_transition_sid(old_tsec->sid, isec->sid,
SECCLASS_PROCESS, &new_tsec->sid);
SECCLASS_PROCESS, NULL,
&new_tsec->sid);
if (rc)
return rc;
}
@ -2443,6 +2363,91 @@ out:
return rc;
}
static int selinux_sb_remount(struct super_block *sb, void *data)
{
int rc, i, *flags;
struct security_mnt_opts opts;
char *secdata, **mount_options;
struct superblock_security_struct *sbsec = sb->s_security;
if (!(sbsec->flags & SE_SBINITIALIZED))
return 0;
if (!data)
return 0;
if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
return 0;
security_init_mnt_opts(&opts);
secdata = alloc_secdata();
if (!secdata)
return -ENOMEM;
rc = selinux_sb_copy_data(data, secdata);
if (rc)
goto out_free_secdata;
rc = selinux_parse_opts_str(secdata, &opts);
if (rc)
goto out_free_secdata;
mount_options = opts.mnt_opts;
flags = opts.mnt_opts_flags;
for (i = 0; i < opts.num_mnt_opts; i++) {
u32 sid;
size_t len;
if (flags[i] == SE_SBLABELSUPP)
continue;
len = strlen(mount_options[i]);
rc = security_context_to_sid(mount_options[i], len, &sid);
if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n",
mount_options[i], sb->s_id, sb->s_type->name, rc);
goto out_free_opts;
}
rc = -EINVAL;
switch (flags[i]) {
case FSCONTEXT_MNT:
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
goto out_bad_option;
break;
case CONTEXT_MNT:
if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
goto out_bad_option;
break;
case ROOTCONTEXT_MNT: {
struct inode_security_struct *root_isec;
root_isec = sb->s_root->d_inode->i_security;
if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
goto out_bad_option;
break;
}
case DEFCONTEXT_MNT:
if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
goto out_bad_option;
break;
default:
goto out_free_opts;
}
}
rc = 0;
out_free_opts:
security_free_mnt_opts(&opts);
out_free_secdata:
free_secdata(secdata);
return rc;
out_bad_option:
printk(KERN_WARNING "SELinux: unable to change security options "
"during remount (dev %s, type=%s)\n", sb->s_id,
sb->s_type->name);
goto out_free_opts;
}
static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
{
const struct cred *cred = current_cred();
@ -2509,8 +2514,8 @@ static void selinux_inode_free_security(struct inode *inode)
}
static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
char **name, void **value,
size_t *len)
const struct qstr *qstr, char **name,
void **value, size_t *len)
{
const struct task_security_struct *tsec = current_security();
struct inode_security_struct *dsec;
@ -2531,7 +2536,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
rc = security_transition_sid(sid, dsec->sid,
inode_mode_to_security_class(inode->i_mode),
&newsid);
qstr, &newsid);
if (rc) {
printk(KERN_WARNING "%s: "
"security_transition_sid failed, rc=%d (dev=%s "
@ -2932,16 +2937,47 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
const struct cred *cred = current_cred();
u32 av = 0;
int error = 0;
if (_IOC_DIR(cmd) & _IOC_WRITE)
av |= FILE__WRITE;
if (_IOC_DIR(cmd) & _IOC_READ)
av |= FILE__READ;
if (!av)
av = FILE__IOCTL;
switch (cmd) {
case FIONREAD:
/* fall through */
case FIBMAP:
/* fall through */
case FIGETBSZ:
/* fall through */
case EXT2_IOC_GETFLAGS:
/* fall through */
case EXT2_IOC_GETVERSION:
error = file_has_perm(cred, file, FILE__GETATTR);
break;
return file_has_perm(cred, file, av);
case EXT2_IOC_SETFLAGS:
/* fall through */
case EXT2_IOC_SETVERSION:
error = file_has_perm(cred, file, FILE__SETATTR);
break;
/* sys_ioctl() checks */
case FIONBIO:
/* fall through */
case FIOASYNC:
error = file_has_perm(cred, file, 0);
break;
case KDSKBENT:
case KDSKBSENT:
error = task_has_capability(current, cred, CAP_SYS_TTY_CONFIG,
SECURITY_CAP_AUDIT);
break;
/* default case assumes that the command will go
* to the file's ioctl() function.
*/
default:
error = file_has_perm(cred, file, FILE__IOCTL);
}
return error;
}
static int default_noexec;
@ -3644,9 +3680,16 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
/* socket security operations */
static u32 socket_sockcreate_sid(const struct task_security_struct *tsec)
static int socket_sockcreate_sid(const struct task_security_struct *tsec,
u16 secclass, u32 *socksid)
{
return tsec->sockcreate_sid ? : tsec->sid;
if (tsec->sockcreate_sid > SECSID_NULL) {
*socksid = tsec->sockcreate_sid;
return 0;
}
return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL,
socksid);
}
static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
@ -3670,12 +3713,16 @@ static int selinux_socket_create(int family, int type,
const struct task_security_struct *tsec = current_security();
u32 newsid;
u16 secclass;
int rc;
if (kern)
return 0;
newsid = socket_sockcreate_sid(tsec);
secclass = socket_type_to_security_class(family, type, protocol);
rc = socket_sockcreate_sid(tsec, secclass, &newsid);
if (rc)
return rc;
return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
}
@ -3687,12 +3734,16 @@ static int selinux_socket_post_create(struct socket *sock, int family,
struct sk_security_struct *sksec;
int err = 0;
isec->sclass = socket_type_to_security_class(family, type, protocol);
if (kern)
isec->sid = SECINITSID_KERNEL;
else
isec->sid = socket_sockcreate_sid(tsec);
else {
err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
if (err)
return err;
}
isec->sclass = socket_type_to_security_class(family, type, protocol);
isec->initialized = 1;
if (sock->sk) {
@ -4002,7 +4053,6 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
{
int err = 0;
struct sk_security_struct *sksec = sk->sk_security;
u32 peer_sid;
u32 sk_sid = sksec->sid;
struct common_audit_data ad;
char *addrp;
@ -4021,20 +4071,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
return err;
}
if (selinux_policycap_netpeer) {
err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
if (err)
return err;
err = avc_has_perm(sk_sid, peer_sid,
SECCLASS_PEER, PEER__RECV, &ad);
if (err)
selinux_netlbl_err(skb, err, 0);
} else {
err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
if (err)
return err;
err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
}
err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
if (err)
return err;
err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
return err;
}
@ -4529,9 +4569,8 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
SECCLASS_PACKET, PACKET__SEND, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
if (selinux_policycap_netpeer)
if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
return NF_DROP_ERR(-ECONNREFUSED);
if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
return NF_DROP_ERR(-ECONNREFUSED);
return NF_ACCEPT;
}
@ -4574,27 +4613,14 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
* from the sending socket, otherwise use the kernel's sid */
sk = skb->sk;
if (sk == NULL) {
switch (family) {
case PF_INET:
if (IPCB(skb)->flags & IPSKB_FORWARDED)
secmark_perm = PACKET__FORWARD_OUT;
else
secmark_perm = PACKET__SEND;
break;
case PF_INET6:
if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
secmark_perm = PACKET__FORWARD_OUT;
else
secmark_perm = PACKET__SEND;
break;
default:
return NF_DROP_ERR(-ECONNREFUSED);
}
if (secmark_perm == PACKET__FORWARD_OUT) {
if (skb->skb_iif) {
secmark_perm = PACKET__FORWARD_OUT;
if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
return NF_DROP;
} else
} else {
secmark_perm = PACKET__SEND;
peer_sid = SECINITSID_KERNEL;
}
} else {
struct sk_security_struct *sksec = sk->sk_security;
peer_sid = sksec->sid;
@ -4848,7 +4874,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
* message queue this message will be stored in
*/
rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
&msec->sid);
NULL, &msec->sid);
if (rc)
return rc;
}
@ -5402,7 +5428,6 @@ static struct security_operations selinux_ops = {
.ptrace_traceme = selinux_ptrace_traceme,
.capget = selinux_capget,
.capset = selinux_capset,
.sysctl = selinux_sysctl,
.capable = selinux_capable,
.quotactl = selinux_quotactl,
.quota_on = selinux_quota_on,
@ -5420,6 +5445,7 @@ static struct security_operations selinux_ops = {
.sb_alloc_security = selinux_sb_alloc_security,
.sb_free_security = selinux_sb_free_security,
.sb_copy_data = selinux_sb_copy_data,
.sb_remount = selinux_sb_remount,
.sb_kern_mount = selinux_sb_kern_mount,
.sb_show_options = selinux_sb_show_options,
.sb_statfs = selinux_sb_statfs,

View File

@ -12,6 +12,10 @@
#define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \
"write", "associate", "unix_read", "unix_write"
/*
* Note: The name for any socket class should be suffixed by "socket",
* and doesn't contain more than one substr of "socket".
*/
struct security_class_mapping secclass_map[] = {
{ "security",
{ "compute_av", "compute_create", "compute_member",
@ -132,8 +136,7 @@ struct security_class_mapping secclass_map[] = {
{ "appletalk_socket",
{ COMMON_SOCK_PERMS, NULL } },
{ "packet",
{ "send", "recv", "relabelto", "flow_in", "flow_out",
"forward_in", "forward_out", NULL } },
{ "send", "recv", "relabelto", "forward_in", "forward_out", NULL } },
{ "key",
{ "view", "read", "write", "search", "link", "setattr", "create",
NULL } },

View File

@ -8,6 +8,7 @@
#ifndef _SELINUX_SECURITY_H_
#define _SELINUX_SECURITY_H_
#include <linux/dcache.h>
#include <linux/magic.h>
#include <linux/types.h>
#include "flask.h"
@ -28,13 +29,14 @@
#define POLICYDB_VERSION_POLCAP 22
#define POLICYDB_VERSION_PERMISSIVE 23
#define POLICYDB_VERSION_BOUNDARY 24
#define POLICYDB_VERSION_FILENAME_TRANS 25
/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
#else
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_FILENAME_TRANS
#endif
/* Mask for just the mount related flags */
@ -106,8 +108,8 @@ void security_compute_av(u32 ssid, u32 tsid,
void security_compute_av_user(u32 ssid, u32 tsid,
u16 tclass, struct av_decision *avd);
int security_transition_sid(u32 ssid, u32 tsid,
u16 tclass, u32 *out_sid);
int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
const struct qstr *qstr, u32 *out_sid);
int security_transition_sid_user(u32 ssid, u32 tsid,
u16 tclass, u32 *out_sid);

View File

@ -14,7 +14,7 @@
*
* Copyright (C) 2003 Tresys Technology, LLC
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
*
* Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
@ -27,16 +27,16 @@ struct avtab_key {
u16 source_type; /* source type */
u16 target_type; /* target type */
u16 target_class; /* target object class */
#define AVTAB_ALLOWED 1
#define AVTAB_AUDITALLOW 2
#define AVTAB_AUDITDENY 4
#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
#define AVTAB_TRANSITION 16
#define AVTAB_MEMBER 32
#define AVTAB_CHANGE 64
#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
#define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */
#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */
#define AVTAB_ALLOWED 0x0001
#define AVTAB_AUDITALLOW 0x0002
#define AVTAB_AUDITDENY 0x0004
#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
#define AVTAB_TRANSITION 0x0010
#define AVTAB_MEMBER 0x0020
#define AVTAB_CHANGE 0x0040
#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
#define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */
#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */
u16 specified; /* what field is specified */
};
@ -86,7 +86,6 @@ void avtab_cache_destroy(void);
#define MAX_AVTAB_HASH_BITS 11
#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
#endif /* _SS_AVTAB_H_ */

View File

@ -36,7 +36,6 @@ struct ebitmap {
};
#define ebitmap_length(e) ((e)->highbit)
#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
struct ebitmap_node **n)

View File

@ -512,7 +512,8 @@ int mls_compute_sid(struct context *scontext,
struct context *tcontext,
u16 tclass,
u32 specified,
struct context *newcontext)
struct context *newcontext,
bool sock)
{
struct range_trans rtr;
struct mls_range *r;
@ -531,7 +532,7 @@ int mls_compute_sid(struct context *scontext,
return mls_range_set(newcontext, r);
/* Fallthrough */
case AVTAB_CHANGE:
if (tclass == policydb.process_class)
if ((tclass == policydb.process_class) || (sock == true))
/* Use the process MLS attributes. */
return mls_context_cpy(newcontext, scontext);
else

View File

@ -49,7 +49,8 @@ int mls_compute_sid(struct context *scontext,
struct context *tcontext,
u16 tclass,
u32 specified,
struct context *newcontext);
struct context *newcontext,
bool sock);
int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
struct context *usercon);

View File

@ -123,6 +123,11 @@ static struct policydb_compat_info policydb_compat[] = {
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
},
{
.version = POLICYDB_VERSION_FILENAME_TRANS,
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
},
};
static struct policydb_compat_info *policydb_lookup_compat(int version)
@ -704,6 +709,7 @@ void policydb_destroy(struct policydb *p)
int i;
struct role_allow *ra, *lra = NULL;
struct role_trans *tr, *ltr = NULL;
struct filename_trans *ft, *nft;
for (i = 0; i < SYM_NUM; i++) {
cond_resched();
@ -781,6 +787,15 @@ void policydb_destroy(struct policydb *p)
}
flex_array_free(p->type_attr_map_array);
}
ft = p->filename_trans;
while (ft) {
nft = ft->next;
kfree(ft->name);
kfree(ft);
ft = nft;
}
ebitmap_destroy(&p->policycaps);
ebitmap_destroy(&p->permissive_map);
@ -1788,6 +1803,76 @@ out:
return rc;
}
static int filename_trans_read(struct policydb *p, void *fp)
{
struct filename_trans *ft, *last;
u32 nel, len;
char *name;
__le32 buf[4];
int rc, i;
if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
return 0;
rc = next_entry(buf, fp, sizeof(u32));
if (rc)
goto out;
nel = le32_to_cpu(buf[0]);
printk(KERN_ERR "%s: nel=%d\n", __func__, nel);
last = p->filename_trans;
while (last && last->next)
last = last->next;
for (i = 0; i < nel; i++) {
rc = -ENOMEM;
ft = kzalloc(sizeof(*ft), GFP_KERNEL);
if (!ft)
goto out;
/* add it to the tail of the list */
if (!last)
p->filename_trans = ft;
else
last->next = ft;
last = ft;
/* length of the path component string */
rc = next_entry(buf, fp, sizeof(u32));
if (rc)
goto out;
len = le32_to_cpu(buf[0]);
rc = -ENOMEM;
name = kmalloc(len + 1, GFP_KERNEL);
if (!name)
goto out;
ft->name = name;
/* path component string */
rc = next_entry(name, fp, len);
if (rc)
goto out;
name[len] = 0;
printk(KERN_ERR "%s: ft=%p ft->name=%p ft->name=%s\n", __func__, ft, ft->name, ft->name);
rc = next_entry(buf, fp, sizeof(u32) * 4);
if (rc)
goto out;
ft->stype = le32_to_cpu(buf[0]);
ft->ttype = le32_to_cpu(buf[1]);
ft->tclass = le32_to_cpu(buf[2]);
ft->otype = le32_to_cpu(buf[3]);
}
rc = 0;
out:
return rc;
}
static int genfs_read(struct policydb *p, void *fp)
{
int i, j, rc;
@ -2251,6 +2336,10 @@ int policydb_read(struct policydb *p, void *fp)
lra = ra;
}
rc = filename_trans_read(p, fp);
if (rc)
goto bad;
rc = policydb_index(p);
if (rc)
goto bad;
@ -3025,6 +3114,43 @@ static int range_write(struct policydb *p, void *fp)
return 0;
}
static int filename_trans_write(struct policydb *p, void *fp)
{
struct filename_trans *ft;
u32 len, nel = 0;
__le32 buf[4];
int rc;
for (ft = p->filename_trans; ft; ft = ft->next)
nel++;
buf[0] = cpu_to_le32(nel);
rc = put_entry(buf, sizeof(u32), 1, fp);
if (rc)
return rc;
for (ft = p->filename_trans; ft; ft = ft->next) {
len = strlen(ft->name);
buf[0] = cpu_to_le32(len);
rc = put_entry(buf, sizeof(u32), 1, fp);
if (rc)
return rc;
rc = put_entry(ft->name, sizeof(char), len, fp);
if (rc)
return rc;
buf[0] = ft->stype;
buf[1] = ft->ttype;
buf[2] = ft->tclass;
buf[3] = ft->otype;
rc = put_entry(buf, sizeof(u32), 4, fp);
if (rc)
return rc;
}
return 0;
}
/*
* Write the configuration data in a policy database
* structure to a policy database binary representation
@ -3135,6 +3261,10 @@ int policydb_write(struct policydb *p, void *fp)
if (rc)
return rc;
rc = filename_trans_write(p, fp);
if (rc)
return rc;
rc = ocontext_write(p, info, fp);
if (rc)
return rc;

View File

@ -77,6 +77,15 @@ struct role_trans {
struct role_trans *next;
};
struct filename_trans {
struct filename_trans *next;
u32 stype; /* current process */
u32 ttype; /* parent dir context */
u16 tclass; /* class of new object */
const char *name; /* last path component */
u32 otype; /* expected of new object */
};
struct role_allow {
u32 role; /* current role */
u32 new_role; /* new role */
@ -217,6 +226,9 @@ struct policydb {
/* role transitions */
struct role_trans *role_tr;
/* file transitions with the last path component */
struct filename_trans *filename_trans;
/* bools indexed by (value - 1) */
struct cond_bool_datum **bool_val_to_struct;
/* type enforcement conditional access vectors and transitions */
@ -302,7 +314,7 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
return 0;
}
static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file *fp)
static inline int put_entry(const void *buf, size_t bytes, int num, struct policy_file *fp)
{
size_t len = bytes * num;

View File

@ -201,6 +201,21 @@ static u16 unmap_class(u16 tclass)
return tclass;
}
/*
* Get kernel value for class from its policy value
*/
static u16 map_class(u16 pol_value)
{
u16 i;
for (i = 1; i < current_mapping_size; i++) {
if (current_mapping[i].value == pol_value)
return i;
}
return pol_value;
}
static void map_decision(u16 tclass, struct av_decision *avd,
int allow_unknown)
{
@ -1343,10 +1358,27 @@ out:
return -EACCES;
}
static void filename_compute_type(struct policydb *p, struct context *newcontext,
u32 scon, u32 tcon, u16 tclass,
const struct qstr *qstr)
{
struct filename_trans *ft;
for (ft = p->filename_trans; ft; ft = ft->next) {
if (ft->stype == scon &&
ft->ttype == tcon &&
ft->tclass == tclass &&
!strcmp(ft->name, qstr->name)) {
newcontext->type = ft->otype;
return;
}
}
}
static int security_compute_sid(u32 ssid,
u32 tsid,
u16 orig_tclass,
u32 specified,
const struct qstr *qstr,
u32 *out_sid,
bool kern)
{
@ -1357,6 +1389,7 @@ static int security_compute_sid(u32 ssid,
struct avtab_node *node;
u16 tclass;
int rc = 0;
bool sock;
if (!ss_initialized) {
switch (orig_tclass) {
@ -1374,10 +1407,13 @@ static int security_compute_sid(u32 ssid,
read_lock(&policy_rwlock);
if (kern)
if (kern) {
tclass = unmap_class(orig_tclass);
else
sock = security_is_socket_class(orig_tclass);
} else {
tclass = orig_tclass;
sock = security_is_socket_class(map_class(tclass));
}
scontext = sidtab_search(&sidtab, ssid);
if (!scontext) {
@ -1408,7 +1444,7 @@ static int security_compute_sid(u32 ssid,
}
/* Set the role and type to default values. */
if (tclass == policydb.process_class) {
if ((tclass == policydb.process_class) || (sock == true)) {
/* Use the current role and type of process. */
newcontext.role = scontext->role;
newcontext.type = scontext->type;
@ -1442,6 +1478,11 @@ static int security_compute_sid(u32 ssid,
newcontext.type = avdatum->data;
}
/* if we have a qstr this is a file trans check so check those rules */
if (qstr)
filename_compute_type(&policydb, &newcontext, scontext->type,
tcontext->type, tclass, qstr);
/* Check for class-specific changes. */
if (tclass == policydb.process_class) {
if (specified & AVTAB_TRANSITION) {
@ -1460,7 +1501,8 @@ static int security_compute_sid(u32 ssid,
/* Set the MLS attributes.
This is done last because it may allocate memory. */
rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext);
rc = mls_compute_sid(scontext, tcontext, tclass, specified,
&newcontext, sock);
if (rc)
goto out_unlock;
@ -1495,22 +1537,17 @@ out:
* if insufficient memory is available, or %0 if the new SID was
* computed successfully.
*/
int security_transition_sid(u32 ssid,
u32 tsid,
u16 tclass,
u32 *out_sid)
int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
const struct qstr *qstr, u32 *out_sid)
{
return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
out_sid, true);
qstr, out_sid, true);
}
int security_transition_sid_user(u32 ssid,
u32 tsid,
u16 tclass,
u32 *out_sid)
int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid)
{
return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
out_sid, false);
NULL, out_sid, false);
}
/**
@ -1531,8 +1568,8 @@ int security_member_sid(u32 ssid,
u16 tclass,
u32 *out_sid)
{
return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid,
false);
return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, NULL,
out_sid, false);
}
/**
@ -1553,8 +1590,8 @@ int security_change_sid(u32 ssid,
u16 tclass,
u32 *out_sid)
{
return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid,
false);
return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL,
out_sid, false);
}
/* Clone the SID into the new SID table. */

View File

@ -208,7 +208,7 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp,
if (!uctx)
goto not_from_user;
if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX)
if (uctx->ctx_alg != XFRM_SC_ALG_SELINUX)
return -EINVAL;
str_len = uctx->ctx_len;

View File

@ -52,13 +52,16 @@ struct socket_smack {
struct inode_smack {
char *smk_inode; /* label of the fso */
char *smk_task; /* label of the task */
char *smk_mmap; /* label of the mmap domain */
struct mutex smk_lock; /* initialization lock */
int smk_flags; /* smack inode flags */
};
struct task_smack {
char *smk_task; /* label used for access control */
char *smk_forked; /* label when forked */
char *smk_task; /* label for access control */
char *smk_forked; /* label when forked */
struct list_head smk_rules; /* per task access rules */
struct mutex smk_rules_lock; /* lock for the rules */
};
#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
@ -151,12 +154,6 @@ struct smack_known {
*/
#define SMACK_MAGIC 0x43415d53 /* "SMAC" */
/*
* A limit on the number of entries in the lists
* makes some of the list administration easier.
*/
#define SMACK_LIST_MAX 10000
/*
* CIPSO defaults.
*/
@ -174,9 +171,7 @@ struct smack_known {
/*
* Just to make the common cases easier to deal with
*/
#define MAY_ANY (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
#define MAY_ANYREAD (MAY_READ | MAY_EXEC)
#define MAY_ANYWRITE (MAY_WRITE | MAY_APPEND)
#define MAY_READWRITE (MAY_READ | MAY_WRITE)
#define MAY_NOT 0
@ -202,7 +197,7 @@ struct inode_smack *new_inode_smack(char *);
/*
* These functions are in smack_access.c
*/
int smk_access_entry(char *, char *);
int smk_access_entry(char *, char *, struct list_head *);
int smk_access(char *, char *, int, struct smk_audit_info *);
int smk_curacc(char *, u32, struct smk_audit_info *);
int smack_to_cipso(const char *, struct smack_cipso *);

View File

@ -70,10 +70,11 @@ int log_policy = SMACK_AUDIT_DENIED;
* smk_access_entry - look up matching access rule
* @subject_label: a pointer to the subject's Smack label
* @object_label: a pointer to the object's Smack label
* @rule_list: the list of rules to search
*
* This function looks up the subject/object pair in the
* access rule list and returns pointer to the matching rule if found,
* NULL otherwise.
* access rule list and returns the access mode. If no
* entry is found returns -ENOENT.
*
* NOTE:
* Even though Smack labels are usually shared on smack_list
@ -85,13 +86,13 @@ int log_policy = SMACK_AUDIT_DENIED;
* will be on the list, so checking the pointers may be a worthwhile
* optimization.
*/
int smk_access_entry(char *subject_label, char *object_label)
int smk_access_entry(char *subject_label, char *object_label,
struct list_head *rule_list)
{
u32 may = MAY_NOT;
int may = -ENOENT;
struct smack_rule *srp;
rcu_read_lock();
list_for_each_entry_rcu(srp, &smack_rule_list, list) {
list_for_each_entry_rcu(srp, rule_list, list) {
if (srp->smk_subject == subject_label ||
strcmp(srp->smk_subject, subject_label) == 0) {
if (srp->smk_object == object_label ||
@ -101,7 +102,6 @@ int smk_access_entry(char *subject_label, char *object_label)
}
}
}
rcu_read_unlock();
return may;
}
@ -129,7 +129,7 @@ int smk_access_entry(char *subject_label, char *object_label)
int smk_access(char *subject_label, char *object_label, int request,
struct smk_audit_info *a)
{
u32 may = MAY_NOT;
int may = MAY_NOT;
int rc = 0;
/*
@ -181,13 +181,14 @@ int smk_access(char *subject_label, char *object_label, int request,
* Beyond here an explicit relationship is required.
* If the requested access is contained in the available
* access (e.g. read is included in readwrite) it's
* good.
* good. A negative response from smk_access_entry()
* indicates there is no entry for this pair.
*/
may = smk_access_entry(subject_label, object_label);
/*
* This is a bit map operation.
*/
if ((request & may) == request)
rcu_read_lock();
may = smk_access_entry(subject_label, object_label, &smack_rule_list);
rcu_read_unlock();
if (may > 0 && (request & may) == request)
goto out_audit;
rc = -EACCES;
@ -212,12 +213,27 @@ out_audit:
*/
int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
{
struct task_smack *tsp = current_security();
char *sp = smk_of_task(tsp);
int may;
int rc;
char *sp = smk_of_current();
/*
* Check the global rule list
*/
rc = smk_access(sp, obj_label, mode, NULL);
if (rc == 0)
goto out_audit;
if (rc == 0) {
/*
* If there is an entry in the task's rule list
* it can further restrict access.
*/
may = smk_access_entry(sp, obj_label, &tsp->smk_rules);
if (may < 0)
goto out_audit;
if ((mode & may) == mode)
goto out_audit;
rc = -EACCES;
}
/*
* Return if a specific label has been designated as the
@ -228,7 +244,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
goto out_audit;
if (capable(CAP_MAC_OVERRIDE))
return 0;
rc = 0;
out_audit:
#ifdef CONFIG_AUDIT

View File

@ -33,6 +33,7 @@
#include <net/cipso_ipv4.h>
#include <linux/audit.h>
#include <linux/magic.h>
#include <linux/dcache.h>
#include "smack.h"
#define task_security(task) (task_cred_xxx((task), security))
@ -84,6 +85,56 @@ struct inode_smack *new_inode_smack(char *smack)
return isp;
}
/**
* new_task_smack - allocate a task security blob
* @smack: a pointer to the Smack label to use in the blob
*
* Returns the new blob or NULL if there's no memory available
*/
static struct task_smack *new_task_smack(char *task, char *forked, gfp_t gfp)
{
struct task_smack *tsp;
tsp = kzalloc(sizeof(struct task_smack), gfp);
if (tsp == NULL)
return NULL;
tsp->smk_task = task;
tsp->smk_forked = forked;
INIT_LIST_HEAD(&tsp->smk_rules);
mutex_init(&tsp->smk_rules_lock);
return tsp;
}
/**
* smk_copy_rules - copy a rule set
* @nhead - new rules header pointer
* @ohead - old rules header pointer
*
* Returns 0 on success, -ENOMEM on error
*/
static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead,
gfp_t gfp)
{
struct smack_rule *nrp;
struct smack_rule *orp;
int rc = 0;
INIT_LIST_HEAD(nhead);
list_for_each_entry_rcu(orp, ohead, list) {
nrp = kzalloc(sizeof(struct smack_rule), gfp);
if (nrp == NULL) {
rc = -ENOMEM;
break;
}
*nrp = *orp;
list_add_rcu(&nrp->list, nhead);
}
return rc;
}
/*
* LSM hooks.
* We he, that is fun!
@ -102,23 +153,17 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
{
int rc;
struct smk_audit_info ad;
char *sp, *tsp;
char *tsp;
rc = cap_ptrace_access_check(ctp, mode);
if (rc != 0)
return rc;
sp = smk_of_current();
tsp = smk_of_task(task_security(ctp));
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, ctp);
/* we won't log here, because rc can be overriden */
rc = smk_access(sp, tsp, MAY_READWRITE, NULL);
if (rc != 0 && capable(CAP_MAC_OVERRIDE))
rc = 0;
smack_log(sp, tsp, MAY_READWRITE, rc, &ad);
rc = smk_curacc(tsp, MAY_READWRITE, &ad);
return rc;
}
@ -134,23 +179,17 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
{
int rc;
struct smk_audit_info ad;
char *sp, *tsp;
char *tsp;
rc = cap_ptrace_traceme(ptp);
if (rc != 0)
return rc;
tsp = smk_of_task(task_security(ptp));
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, ptp);
sp = smk_of_current();
tsp = smk_of_task(task_security(ptp));
/* we won't log here, because rc can be overriden */
rc = smk_access(tsp, sp, MAY_READWRITE, NULL);
if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE))
rc = 0;
smack_log(tsp, sp, MAY_READWRITE, rc, &ad);
rc = smk_curacc(tsp, MAY_READWRITE, &ad);
return rc;
}
@ -463,6 +502,7 @@ static void smack_inode_free_security(struct inode *inode)
* smack_inode_init_security - copy out the smack from an inode
* @inode: the inode
* @dir: unused
* @qstr: unused
* @name: where to put the attribute name
* @value: where to put the attribute value
* @len: where to put the length of the attribute
@ -470,11 +510,12 @@ static void smack_inode_free_security(struct inode *inode)
* Returns 0 if it all works out, -ENOMEM if there's no memory
*/
static int smack_inode_init_security(struct inode *inode, struct inode *dir,
char **name, void **value, size_t *len)
const struct qstr *qstr, char **name,
void **value, size_t *len)
{
char *isp = smk_of_inode(inode);
char *dsp = smk_of_inode(dir);
u32 may;
int may;
if (name) {
*name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL);
@ -483,14 +524,17 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
}
if (value) {
may = smk_access_entry(smk_of_current(), dsp);
rcu_read_lock();
may = smk_access_entry(smk_of_current(), dsp, &smack_rule_list);
rcu_read_unlock();
/*
* If the access rule allows transmutation and
* the directory requests transmutation then
* by all means transmute.
*/
if (((may & MAY_TRANSMUTE) != 0) && smk_inode_transmutable(dir))
if (may > 0 && ((may & MAY_TRANSMUTE) != 0) &&
smk_inode_transmutable(dir))
isp = dsp;
*value = kstrdup(isp, GFP_KERNEL);
@ -716,7 +760,8 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
if (!capable(CAP_MAC_ADMIN))
rc = -EPERM;
/*
@ -773,6 +818,12 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
isp->smk_task = nsp;
else
isp->smk_task = smack_known_invalid.smk_known;
} else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
nsp = smk_import(value, size);
if (nsp != NULL)
isp->smk_mmap = nsp;
else
isp->smk_mmap = smack_known_invalid.smk_known;
} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0)
isp->smk_flags |= SMK_INODE_TRANSMUTE;
@ -815,7 +866,8 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 ||
strcmp(name, XATTR_NAME_SMACKMMAP)) {
if (!capable(CAP_MAC_ADMIN))
rc = -EPERM;
} else
@ -829,6 +881,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
if (rc == 0) {
isp = dentry->d_inode->i_security;
isp->smk_task = NULL;
isp->smk_mmap = NULL;
}
return rc;
@ -1059,6 +1112,126 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
return rc;
}
/**
* smack_file_mmap :
* Check permissions for a mmap operation. The @file may be NULL, e.g.
* if mapping anonymous memory.
* @file contains the file structure for file to map (may be NULL).
* @reqprot contains the protection requested by the application.
* @prot contains the protection that will be applied by the kernel.
* @flags contains the operational flags.
* Return 0 if permission is granted.
*/
static int smack_file_mmap(struct file *file,
unsigned long reqprot, unsigned long prot,
unsigned long flags, unsigned long addr,
unsigned long addr_only)
{
struct smack_rule *srp;
struct task_smack *tsp;
char *sp;
char *msmack;
char *osmack;
struct inode_smack *isp;
struct dentry *dp;
int may;
int mmay;
int tmay;
int rc;
/* do DAC check on address space usage */
rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
if (rc || addr_only)
return rc;
if (file == NULL || file->f_dentry == NULL)
return 0;
dp = file->f_dentry;
if (dp->d_inode == NULL)
return 0;
isp = dp->d_inode->i_security;
if (isp->smk_mmap == NULL)
return 0;
msmack = isp->smk_mmap;
tsp = current_security();
sp = smk_of_current();
rc = 0;
rcu_read_lock();
/*
* For each Smack rule associated with the subject
* label verify that the SMACK64MMAP also has access
* to that rule's object label.
*
* Because neither of the labels comes
* from the networking code it is sufficient
* to compare pointers.
*/
list_for_each_entry_rcu(srp, &smack_rule_list, list) {
if (srp->smk_subject != sp)
continue;
osmack = srp->smk_object;
/*
* Matching labels always allows access.
*/
if (msmack == osmack)
continue;
/*
* If there is a matching local rule take
* that into account as well.
*/
may = smk_access_entry(srp->smk_subject, osmack,
&tsp->smk_rules);
if (may == -ENOENT)
may = srp->smk_access;
else
may &= srp->smk_access;
/*
* If may is zero the SMACK64MMAP subject can't
* possibly have less access.
*/
if (may == 0)
continue;
/*
* Fetch the global list entry.
* If there isn't one a SMACK64MMAP subject
* can't have as much access as current.
*/
mmay = smk_access_entry(msmack, osmack, &smack_rule_list);
if (mmay == -ENOENT) {
rc = -EACCES;
break;
}
/*
* If there is a local entry it modifies the
* potential access, too.
*/
tmay = smk_access_entry(msmack, osmack, &tsp->smk_rules);
if (tmay != -ENOENT)
mmay &= tmay;
/*
* If there is any access available to current that is
* not available to a SMACK64MMAP subject
* deny access.
*/
if ((may | mmay) != mmay) {
rc = -EACCES;
break;
}
}
rcu_read_unlock();
return rc;
}
/**
* smack_file_set_fowner - set the file security blob value
* @file: object in question
@ -1095,6 +1268,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
* struct fown_struct is never outside the context of a struct file
*/
file = container_of(fown, struct file, f_owner);
/* we don't log here as rc can be overriden */
rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL);
if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
@ -1145,9 +1319,14 @@ static int smack_file_receive(struct file *file)
*/
static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{
cred->security = kzalloc(sizeof(struct task_smack), gfp);
if (cred->security == NULL)
struct task_smack *tsp;
tsp = new_task_smack(NULL, NULL, gfp);
if (tsp == NULL)
return -ENOMEM;
cred->security = tsp;
return 0;
}
@ -1156,13 +1335,24 @@ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
* smack_cred_free - "free" task-level security credentials
* @cred: the credentials in question
*
* Smack isn't using copies of blobs. Everyone
* points to an immutable list. The blobs never go away.
* There is no leak here.
*/
static void smack_cred_free(struct cred *cred)
{
kfree(cred->security);
struct task_smack *tsp = cred->security;
struct smack_rule *rp;
struct list_head *l;
struct list_head *n;
if (tsp == NULL)
return;
cred->security = NULL;
list_for_each_safe(l, n, &tsp->smk_rules) {
rp = list_entry(l, struct smack_rule, list);
list_del(&rp->list);
kfree(rp);
}
kfree(tsp);
}
/**
@ -1178,13 +1368,16 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
{
struct task_smack *old_tsp = old->security;
struct task_smack *new_tsp;
int rc;
new_tsp = kzalloc(sizeof(struct task_smack), gfp);
new_tsp = new_task_smack(old_tsp->smk_task, old_tsp->smk_task, gfp);
if (new_tsp == NULL)
return -ENOMEM;
new_tsp->smk_task = old_tsp->smk_task;
new_tsp->smk_forked = old_tsp->smk_task;
rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp);
if (rc != 0)
return rc;
new->security = new_tsp;
return 0;
}
@ -1203,6 +1396,11 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old)
new_tsp->smk_task = old_tsp->smk_task;
new_tsp->smk_forked = old_tsp->smk_task;
mutex_init(&new_tsp->smk_rules_lock);
INIT_LIST_HEAD(&new_tsp->smk_rules);
/* cbs copy rule list */
}
/**
@ -2419,6 +2617,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
}
}
isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp);
isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp);
dput(dp);
break;
@ -2478,6 +2677,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
static int smack_setprocattr(struct task_struct *p, char *name,
void *value, size_t size)
{
int rc;
struct task_smack *tsp;
struct task_smack *oldtsp;
struct cred *new;
@ -2513,13 +2713,16 @@ static int smack_setprocattr(struct task_struct *p, char *name,
new = prepare_creds();
if (new == NULL)
return -ENOMEM;
tsp = kzalloc(sizeof(struct task_smack), GFP_KERNEL);
tsp = new_task_smack(newsmack, oldtsp->smk_forked, GFP_KERNEL);
if (tsp == NULL) {
kfree(new);
return -ENOMEM;
}
tsp->smk_task = newsmack;
tsp->smk_forked = oldtsp->smk_forked;
rc = smk_copy_rules(&tsp->smk_rules, &oldtsp->smk_rules, GFP_KERNEL);
if (rc != 0)
return rc;
new->security = tsp;
commit_creds(new);
return size;
@ -3221,6 +3424,7 @@ struct security_operations smack_ops = {
.file_ioctl = smack_file_ioctl,
.file_lock = smack_file_lock,
.file_fcntl = smack_file_fcntl,
.file_mmap = smack_file_mmap,
.file_set_fowner = smack_file_set_fowner,
.file_send_sigiotask = smack_file_send_sigiotask,
.file_receive = smack_file_receive,
@ -3334,23 +3538,20 @@ static __init int smack_init(void)
struct cred *cred;
struct task_smack *tsp;
tsp = kzalloc(sizeof(struct task_smack), GFP_KERNEL);
if (!security_module_enable(&smack_ops))
return 0;
tsp = new_task_smack(smack_known_floor.smk_known,
smack_known_floor.smk_known, GFP_KERNEL);
if (tsp == NULL)
return -ENOMEM;
if (!security_module_enable(&smack_ops)) {
kfree(tsp);
return 0;
}
printk(KERN_INFO "Smack: Initializing.\n");
/*
* Set the security state for the initial task.
*/
cred = (struct cred *) current->cred;
tsp->smk_forked = smack_known_floor.smk_known;
tsp->smk_task = smack_known_floor.smk_known;
cred->security = tsp;
/* initialize the smack_know_list */

View File

@ -43,6 +43,7 @@ enum smk_inos {
SMK_NETLBLADDR = 8, /* single label hosts */
SMK_ONLYCAP = 9, /* the only "capable" label */
SMK_LOGGING = 10, /* logging */
SMK_LOAD_SELF = 11, /* task specific rules */
};
/*
@ -135,104 +136,30 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap)
#define SMK_NETLBLADDRMIN 9
#define SMK_NETLBLADDRMAX 42
/*
* Seq_file read operations for /smack/load
*/
static void *load_seq_start(struct seq_file *s, loff_t *pos)
{
if (*pos == SEQ_READ_FINISHED)
return NULL;
if (list_empty(&smack_rule_list))
return NULL;
return smack_rule_list.next;
}
static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
struct list_head *list = v;
if (list_is_last(list, &smack_rule_list)) {
*pos = SEQ_READ_FINISHED;
return NULL;
}
return list->next;
}
static int load_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_rule *srp =
list_entry(list, struct smack_rule, list);
seq_printf(s, "%s %s", (char *)srp->smk_subject,
(char *)srp->smk_object);
seq_putc(s, ' ');
if (srp->smk_access & MAY_READ)
seq_putc(s, 'r');
if (srp->smk_access & MAY_WRITE)
seq_putc(s, 'w');
if (srp->smk_access & MAY_EXEC)
seq_putc(s, 'x');
if (srp->smk_access & MAY_APPEND)
seq_putc(s, 'a');
if (srp->smk_access & MAY_TRANSMUTE)
seq_putc(s, 't');
if (srp->smk_access == 0)
seq_putc(s, '-');
seq_putc(s, '\n');
return 0;
}
static void load_seq_stop(struct seq_file *s, void *v)
{
/* No-op */
}
static const struct seq_operations load_seq_ops = {
.start = load_seq_start,
.next = load_seq_next,
.show = load_seq_show,
.stop = load_seq_stop,
};
/**
* smk_open_load - open() for /smack/load
* @inode: inode structure representing file
* @file: "load" file pointer
*
* For reading, use load_seq_* seq_file reading operations.
*/
static int smk_open_load(struct inode *inode, struct file *file)
{
return seq_open(file, &load_seq_ops);
}
/**
* smk_set_access - add a rule to the rule list
* @srp: the new rule to add
* @rule_list: the list of rules
* @rule_lock: the rule list lock
*
* Looks through the current subject/object/access list for
* the subject/object pair and replaces the access that was
* there. If the pair isn't found add it with the specified
* access.
*
* Returns 1 if a rule was found to exist already, 0 if it is new
* Returns 0 if nothing goes wrong or -ENOMEM if it fails
* during the allocation of the new pair to add.
*/
static int smk_set_access(struct smack_rule *srp)
static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
struct mutex *rule_lock)
{
struct smack_rule *sp;
int ret = 0;
int found;
mutex_lock(&smack_list_lock);
int found = 0;
found = 0;
list_for_each_entry_rcu(sp, &smack_rule_list, list) {
mutex_lock(rule_lock);
list_for_each_entry_rcu(sp, rule_list, list) {
if (sp->smk_subject == srp->smk_subject &&
sp->smk_object == srp->smk_object) {
found = 1;
@ -241,19 +168,21 @@ static int smk_set_access(struct smack_rule *srp)
}
}
if (found == 0)
list_add_rcu(&srp->list, &smack_rule_list);
list_add_rcu(&srp->list, rule_list);
mutex_unlock(&smack_list_lock);
mutex_unlock(rule_lock);
return ret;
return found;
}
/**
* smk_write_load - write() for /smack/load
* smk_write_load_list - write() for any /smack/load
* @file: file pointer, not actually used
* @buf: where to get the data from
* @count: bytes sent
* @ppos: where to start - must be 0
* @rule_list: the list of rules to write to
* @rule_lock: lock for the rule list
*
* Get one smack access rule from above.
* The format is exactly:
@ -263,21 +192,19 @@ static int smk_set_access(struct smack_rule *srp)
*
* writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes.
*/
static ssize_t smk_write_load(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
size_t count, loff_t *ppos,
struct list_head *rule_list,
struct mutex *rule_lock)
{
struct smack_rule *rule;
char *data;
int rc = -EINVAL;
/*
* Must have privilege.
* No partial writes.
* Enough data must be present.
*/
if (!capable(CAP_MAC_ADMIN))
return -EPERM;
if (*ppos != 0)
return -EINVAL;
/*
@ -372,11 +299,13 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
goto out_free_rule;
}
rc = smk_set_access(rule);
if (!rc)
rc = count;
goto out;
rc = count;
/*
* smk_set_access returns true if there was already a rule
* for the subject/object pair, and false if it was new.
*/
if (!smk_set_access(rule, rule_list, rule_lock))
goto out;
out_free_rule:
kfree(rule);
@ -385,6 +314,108 @@ out:
return rc;
}
/*
* Seq_file read operations for /smack/load
*/
static void *load_seq_start(struct seq_file *s, loff_t *pos)
{
if (*pos == SEQ_READ_FINISHED)
return NULL;
if (list_empty(&smack_rule_list))
return NULL;
return smack_rule_list.next;
}
static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
struct list_head *list = v;
if (list_is_last(list, &smack_rule_list)) {
*pos = SEQ_READ_FINISHED;
return NULL;
}
return list->next;
}
static int load_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_rule *srp =
list_entry(list, struct smack_rule, list);
seq_printf(s, "%s %s", (char *)srp->smk_subject,
(char *)srp->smk_object);
seq_putc(s, ' ');
if (srp->smk_access & MAY_READ)
seq_putc(s, 'r');
if (srp->smk_access & MAY_WRITE)
seq_putc(s, 'w');
if (srp->smk_access & MAY_EXEC)
seq_putc(s, 'x');
if (srp->smk_access & MAY_APPEND)
seq_putc(s, 'a');
if (srp->smk_access & MAY_TRANSMUTE)
seq_putc(s, 't');
if (srp->smk_access == 0)
seq_putc(s, '-');
seq_putc(s, '\n');
return 0;
}
static void load_seq_stop(struct seq_file *s, void *v)
{
/* No-op */
}
static const struct seq_operations load_seq_ops = {
.start = load_seq_start,
.next = load_seq_next,
.show = load_seq_show,
.stop = load_seq_stop,
};
/**
* smk_open_load - open() for /smack/load
* @inode: inode structure representing file
* @file: "load" file pointer
*
* For reading, use load_seq_* seq_file reading operations.
*/
static int smk_open_load(struct inode *inode, struct file *file)
{
return seq_open(file, &load_seq_ops);
}
/**
* smk_write_load - write() for /smack/load
* @file: file pointer, not actually used
* @buf: where to get the data from
* @count: bytes sent
* @ppos: where to start - must be 0
*
*/
static ssize_t smk_write_load(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
/*
* Must have privilege.
* No partial writes.
* Enough data must be present.
*/
if (!capable(CAP_MAC_ADMIN))
return -EPERM;
return smk_write_load_list(file, buf, count, ppos, &smack_rule_list,
&smack_list_lock);
}
static const struct file_operations smk_load_ops = {
.open = smk_open_load,
.read = seq_read,
@ -1288,6 +1319,112 @@ static const struct file_operations smk_logging_ops = {
.write = smk_write_logging,
.llseek = default_llseek,
};
/*
* Seq_file read operations for /smack/load-self
*/
static void *load_self_seq_start(struct seq_file *s, loff_t *pos)
{
struct task_smack *tsp = current_security();
if (*pos == SEQ_READ_FINISHED)
return NULL;
if (list_empty(&tsp->smk_rules))
return NULL;
return tsp->smk_rules.next;
}
static void *load_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
struct task_smack *tsp = current_security();
struct list_head *list = v;
if (list_is_last(list, &tsp->smk_rules)) {
*pos = SEQ_READ_FINISHED;
return NULL;
}
return list->next;
}
static int load_self_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_rule *srp =
list_entry(list, struct smack_rule, list);
seq_printf(s, "%s %s", (char *)srp->smk_subject,
(char *)srp->smk_object);
seq_putc(s, ' ');
if (srp->smk_access & MAY_READ)
seq_putc(s, 'r');
if (srp->smk_access & MAY_WRITE)
seq_putc(s, 'w');
if (srp->smk_access & MAY_EXEC)
seq_putc(s, 'x');
if (srp->smk_access & MAY_APPEND)
seq_putc(s, 'a');
if (srp->smk_access & MAY_TRANSMUTE)
seq_putc(s, 't');
if (srp->smk_access == 0)
seq_putc(s, '-');
seq_putc(s, '\n');
return 0;
}
static void load_self_seq_stop(struct seq_file *s, void *v)
{
/* No-op */
}
static const struct seq_operations load_self_seq_ops = {
.start = load_self_seq_start,
.next = load_self_seq_next,
.show = load_self_seq_show,
.stop = load_self_seq_stop,
};
/**
* smk_open_load_self - open() for /smack/load-self
* @inode: inode structure representing file
* @file: "load" file pointer
*
* For reading, use load_seq_* seq_file reading operations.
*/
static int smk_open_load_self(struct inode *inode, struct file *file)
{
return seq_open(file, &load_self_seq_ops);
}
/**
* smk_write_load_self - write() for /smack/load-self
* @file: file pointer, not actually used
* @buf: where to get the data from
* @count: bytes sent
* @ppos: where to start - must be 0
*
*/
static ssize_t smk_write_load_self(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct task_smack *tsp = current_security();
return smk_write_load_list(file, buf, count, ppos, &tsp->smk_rules,
&tsp->smk_rules_lock);
}
static const struct file_operations smk_load_self_ops = {
.open = smk_open_load_self,
.read = seq_read,
.llseek = seq_lseek,
.write = smk_write_load_self,
.release = seq_release,
};
/**
* smk_fill_super - fill the /smackfs superblock
* @sb: the empty superblock
@ -1304,23 +1441,26 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
struct inode *root_inode;
static struct tree_descr smack_files[] = {
[SMK_LOAD] =
{"load", &smk_load_ops, S_IRUGO|S_IWUSR},
[SMK_CIPSO] =
{"cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR},
[SMK_DOI] =
{"doi", &smk_doi_ops, S_IRUGO|S_IWUSR},
[SMK_DIRECT] =
{"direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
[SMK_AMBIENT] =
{"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
[SMK_NETLBLADDR] =
{"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR},
[SMK_ONLYCAP] =
{"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
[SMK_LOGGING] =
{"logging", &smk_logging_ops, S_IRUGO|S_IWUSR},
/* last one */ {""}
[SMK_LOAD] = {
"load", &smk_load_ops, S_IRUGO|S_IWUSR},
[SMK_CIPSO] = {
"cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR},
[SMK_DOI] = {
"doi", &smk_doi_ops, S_IRUGO|S_IWUSR},
[SMK_DIRECT] = {
"direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
[SMK_AMBIENT] = {
"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
[SMK_NETLBLADDR] = {
"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR},
[SMK_ONLYCAP] = {
"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
[SMK_LOGGING] = {
"logging", &smk_logging_ops, S_IRUGO|S_IWUSR},
[SMK_LOAD_SELF] = {
"load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO},
/* last one */
{""}
};
rc = simple_fill_super(sb, SMACK_MAGIC, smack_files);

View File

@ -927,7 +927,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
struct path *path, const int flag)
{
const u8 acc_mode = ACC_MODE(flag);
int error = -ENOMEM;
int error = 0;
struct tomoyo_path_info buf;
struct tomoyo_request_info r;
int idx;
@ -938,9 +938,6 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
buf.name = NULL;
r.mode = TOMOYO_CONFIG_DISABLED;
idx = tomoyo_read_lock();
if (!tomoyo_get_realpath(&buf, path))
goto out;
error = 0;
/*
* If the filename is specified by "deny_rewrite" keyword,
* we need to check "allow_rewrite" permission when the filename is not