mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
Merge branch 'next' into for-linus
This commit is contained in:
commit
a002951c97
@ -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.
|
||||
|
@ -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
|
||||
|
@ -2138,6 +2138,11 @@ config SYSVIPC_COMPAT
|
||||
def_bool y
|
||||
depends on COMPAT && SYSVIPC
|
||||
|
||||
config KEYS_COMPAT
|
||||
bool
|
||||
depends on COMPAT && KEYS
|
||||
default y
|
||||
|
||||
endmenu
|
||||
|
||||
|
||||
|
@ -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;
|
||||
@ -4894,7 +4895,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;
|
||||
|
||||
@ -7106,7 +7107,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;
|
||||
|
@ -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;
|
||||
|
@ -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__ */
|
||||
|
@ -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;
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
@ -932,7 +932,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;
|
||||
|
||||
@ -1395,7 +1395,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;
|
||||
|
@ -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;
|
||||
|
@ -1767,6 +1767,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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -701,7 +701,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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 *);
|
||||
|
@ -798,8 +798,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
|
||||
@ -2200,6 +2199,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);
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
@ -1964,6 +1963,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;
|
||||
@ -2023,6 +2027,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)
|
||||
|
@ -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
|
||||
|
@ -1690,13 +1690,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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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 } },
|
||||
|
@ -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);
|
||||
|
@ -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_ */
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
@ -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 *);
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user