Merge branch 'serge-next-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sergeh/linux-security
Pull security layer updates from Serge Hallyn: "This is a merge of James Morris' security-next tree from 3.14 to yesterday's master, plus four patches from Paul Moore which are in linux-next, plus one patch from Mimi" * 'serge-next-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sergeh/linux-security: ima: audit log files opened with O_DIRECT flag selinux: conditionally reschedule in hashtab_insert while loading selinux policy selinux: conditionally reschedule in mls_convert_context while loading selinux policy selinux: reject setexeccon() on MNT_NOSUID applications with -EACCES selinux: Report permissive mode in avc: denied messages. Warning in scanf string typing Smack: Label cgroup files for systemd Smack: Verify read access on file open - v3 security: Convert use of typedef ctl_table to struct ctl_table Smack: bidirectional UDS connect check Smack: Correctly remove SMACK64TRANSMUTE attribute SMACK: Fix handling value==NULL in post setxattr bugfix patch for SMACK Smack: adds smackfs/ptrace interface Smack: unify all ptrace accesses in the smack Smack: fix the subject/object order in smack_ptrace_traceme() Minor improvement of 'smack_sb_kern_mount' smack: fix key permission verification KEYS: Move the flags representing required permission to linux/key.h
This commit is contained in:
commit
fad0701eaa
|
@ -23,7 +23,7 @@ Description:
|
||||||
[fowner]]
|
[fowner]]
|
||||||
lsm: [[subj_user=] [subj_role=] [subj_type=]
|
lsm: [[subj_user=] [subj_role=] [subj_type=]
|
||||||
[obj_user=] [obj_role=] [obj_type=]]
|
[obj_user=] [obj_role=] [obj_type=]]
|
||||||
option: [[appraise_type=]]
|
option: [[appraise_type=]] [permit_directio]
|
||||||
|
|
||||||
base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
|
base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
|
||||||
mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
|
mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
|
||||||
|
|
|
@ -204,6 +204,16 @@ onlycap
|
||||||
these capabilities are effective at for processes with any
|
these capabilities are effective at for processes with any
|
||||||
label. The value is set by writing the desired label to the
|
label. The value is set by writing the desired label to the
|
||||||
file or cleared by writing "-" to the file.
|
file or cleared by writing "-" to the file.
|
||||||
|
ptrace
|
||||||
|
This is used to define the current ptrace policy
|
||||||
|
0 - default: this is the policy that relies on smack access rules.
|
||||||
|
For the PTRACE_READ a subject needs to have a read access on
|
||||||
|
object. For the PTRACE_ATTACH a read-write access is required.
|
||||||
|
1 - exact: this is the policy that limits PTRACE_ATTACH. Attach is
|
||||||
|
only allowed when subject's and object's labels are equal.
|
||||||
|
PTRACE_READ is not affected. Can be overriden with CAP_SYS_PTRACE.
|
||||||
|
2 - draconian: this policy behaves like the 'exact' above with an
|
||||||
|
exception that it can't be overriden with CAP_SYS_PTRACE.
|
||||||
revoke-subject
|
revoke-subject
|
||||||
Writing a Smack label here sets the access to '-' for all access
|
Writing a Smack label here sets the access to '-' for all access
|
||||||
rules with that subject label.
|
rules with that subject label.
|
||||||
|
|
|
@ -309,6 +309,17 @@ static inline key_serial_t key_serial(const struct key *key)
|
||||||
|
|
||||||
extern void key_set_timeout(struct key *, unsigned);
|
extern void key_set_timeout(struct key *, unsigned);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The permissions required on a key that we're looking up.
|
||||||
|
*/
|
||||||
|
#define KEY_NEED_VIEW 0x01 /* Require permission to view attributes */
|
||||||
|
#define KEY_NEED_READ 0x02 /* Require permission to read content */
|
||||||
|
#define KEY_NEED_WRITE 0x04 /* Require permission to update / modify */
|
||||||
|
#define KEY_NEED_SEARCH 0x08 /* Require permission to search (keyring) or find (key) */
|
||||||
|
#define KEY_NEED_LINK 0x10 /* Require permission to link */
|
||||||
|
#define KEY_NEED_SETATTR 0x20 /* Require permission to change attributes */
|
||||||
|
#define KEY_NEED_ALL 0x3f /* All the above permissions */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* key_is_instantiated - Determine if a key has been positively instantiated
|
* key_is_instantiated - Determine if a key has been positively instantiated
|
||||||
* @key: The key to check.
|
* @key: The key to check.
|
||||||
|
|
|
@ -1708,7 +1708,7 @@ struct security_operations {
|
||||||
void (*key_free) (struct key *key);
|
void (*key_free) (struct key *key);
|
||||||
int (*key_permission) (key_ref_t key_ref,
|
int (*key_permission) (key_ref_t key_ref,
|
||||||
const struct cred *cred,
|
const struct cred *cred,
|
||||||
key_perm_t perm);
|
unsigned perm);
|
||||||
int (*key_getsecurity)(struct key *key, char **_buffer);
|
int (*key_getsecurity)(struct key *key, char **_buffer);
|
||||||
#endif /* CONFIG_KEYS */
|
#endif /* CONFIG_KEYS */
|
||||||
|
|
||||||
|
@ -3034,7 +3034,7 @@ static inline int security_path_chroot(struct path *path)
|
||||||
int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags);
|
int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags);
|
||||||
void security_key_free(struct key *key);
|
void security_key_free(struct key *key);
|
||||||
int security_key_permission(key_ref_t key_ref,
|
int security_key_permission(key_ref_t key_ref,
|
||||||
const struct cred *cred, key_perm_t perm);
|
const struct cred *cred, unsigned perm);
|
||||||
int security_key_getsecurity(struct key *key, char **_buffer);
|
int security_key_getsecurity(struct key *key, char **_buffer);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -3052,7 +3052,7 @@ static inline void security_key_free(struct key *key)
|
||||||
|
|
||||||
static inline int security_key_permission(key_ref_t key_ref,
|
static inline int security_key_permission(key_ref_t key_ref,
|
||||||
const struct cred *cred,
|
const struct cred *cred,
|
||||||
key_perm_t perm)
|
unsigned perm)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -879,7 +879,7 @@ static void cap_key_free(struct key *key)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cap_key_permission(key_ref_t key_ref, const struct cred *cred,
|
static int cap_key_permission(key_ref_t key_ref, const struct cred *cred,
|
||||||
key_perm_t perm)
|
unsigned perm)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,6 +199,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||||
struct evm_ima_xattr_data **xattr_value,
|
struct evm_ima_xattr_data **xattr_value,
|
||||||
int *xattr_len)
|
int *xattr_len)
|
||||||
{
|
{
|
||||||
|
const char *audit_cause = "failed";
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
const char *filename = file->f_dentry->d_name.name;
|
const char *filename = file->f_dentry->d_name.name;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
@ -213,6 +214,12 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||||
if (!(iint->flags & IMA_COLLECTED)) {
|
if (!(iint->flags & IMA_COLLECTED)) {
|
||||||
u64 i_version = file_inode(file)->i_version;
|
u64 i_version = file_inode(file)->i_version;
|
||||||
|
|
||||||
|
if (file->f_flags & O_DIRECT) {
|
||||||
|
audit_cause = "failed(directio)";
|
||||||
|
result = -EACCES;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* use default hash algorithm */
|
/* use default hash algorithm */
|
||||||
hash.hdr.algo = ima_hash_algo;
|
hash.hdr.algo = ima_hash_algo;
|
||||||
|
|
||||||
|
@ -233,9 +240,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||||
result = -ENOMEM;
|
result = -ENOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
if (result)
|
if (result)
|
||||||
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
|
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
|
||||||
filename, "collect_data", "failed",
|
filename, "collect_data", audit_cause,
|
||||||
result, 0);
|
result, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,8 +214,11 @@ static int process_measurement(struct file *file, const char *filename,
|
||||||
xattr_ptr = &xattr_value;
|
xattr_ptr = &xattr_value;
|
||||||
|
|
||||||
rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len);
|
rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len);
|
||||||
if (rc != 0)
|
if (rc != 0) {
|
||||||
|
if (file->f_flags & O_DIRECT)
|
||||||
|
rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES;
|
||||||
goto out_digsig;
|
goto out_digsig;
|
||||||
|
}
|
||||||
|
|
||||||
pathname = filename ?: ima_d_path(&file->f_path, &pathbuf);
|
pathname = filename ?: ima_d_path(&file->f_path, &pathbuf);
|
||||||
|
|
||||||
|
|
|
@ -353,7 +353,7 @@ enum {
|
||||||
Opt_obj_user, Opt_obj_role, Opt_obj_type,
|
Opt_obj_user, Opt_obj_role, Opt_obj_type,
|
||||||
Opt_subj_user, Opt_subj_role, Opt_subj_type,
|
Opt_subj_user, Opt_subj_role, Opt_subj_type,
|
||||||
Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner,
|
Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner,
|
||||||
Opt_appraise_type, Opt_fsuuid
|
Opt_appraise_type, Opt_fsuuid, Opt_permit_directio
|
||||||
};
|
};
|
||||||
|
|
||||||
static match_table_t policy_tokens = {
|
static match_table_t policy_tokens = {
|
||||||
|
@ -375,6 +375,7 @@ static match_table_t policy_tokens = {
|
||||||
{Opt_uid, "uid=%s"},
|
{Opt_uid, "uid=%s"},
|
||||||
{Opt_fowner, "fowner=%s"},
|
{Opt_fowner, "fowner=%s"},
|
||||||
{Opt_appraise_type, "appraise_type=%s"},
|
{Opt_appraise_type, "appraise_type=%s"},
|
||||||
|
{Opt_permit_directio, "permit_directio"},
|
||||||
{Opt_err, NULL}
|
{Opt_err, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -622,6 +623,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
||||||
else
|
else
|
||||||
result = -EINVAL;
|
result = -EINVAL;
|
||||||
break;
|
break;
|
||||||
|
case Opt_permit_directio:
|
||||||
|
entry->flags |= IMA_PERMIT_DIRECTIO;
|
||||||
|
break;
|
||||||
case Opt_err:
|
case Opt_err:
|
||||||
ima_log_string(ab, "UNKNOWN", p);
|
ima_log_string(ab, "UNKNOWN", p);
|
||||||
result = -EINVAL;
|
result = -EINVAL;
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#define IMA_ACTION_FLAGS 0xff000000
|
#define IMA_ACTION_FLAGS 0xff000000
|
||||||
#define IMA_DIGSIG 0x01000000
|
#define IMA_DIGSIG 0x01000000
|
||||||
#define IMA_DIGSIG_REQUIRED 0x02000000
|
#define IMA_DIGSIG_REQUIRED 0x02000000
|
||||||
|
#define IMA_PERMIT_DIRECTIO 0x04000000
|
||||||
|
|
||||||
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
|
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
|
||||||
IMA_APPRAISE_SUBMASK)
|
IMA_APPRAISE_SUBMASK)
|
||||||
|
|
|
@ -176,20 +176,11 @@ extern int key_task_permission(const key_ref_t key_ref,
|
||||||
/*
|
/*
|
||||||
* Check to see whether permission is granted to use a key in the desired way.
|
* Check to see whether permission is granted to use a key in the desired way.
|
||||||
*/
|
*/
|
||||||
static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
|
static inline int key_permission(const key_ref_t key_ref, unsigned perm)
|
||||||
{
|
{
|
||||||
return key_task_permission(key_ref, current_cred(), perm);
|
return key_task_permission(key_ref, current_cred(), perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* required permissions */
|
|
||||||
#define KEY_VIEW 0x01 /* require permission to view attributes */
|
|
||||||
#define KEY_READ 0x02 /* require permission to read content */
|
|
||||||
#define KEY_WRITE 0x04 /* require permission to update / modify */
|
|
||||||
#define KEY_SEARCH 0x08 /* require permission to search (keyring) or find (key) */
|
|
||||||
#define KEY_LINK 0x10 /* require permission to link */
|
|
||||||
#define KEY_SETATTR 0x20 /* require permission to change attributes */
|
|
||||||
#define KEY_ALL 0x3f /* all the above permissions */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Authorisation record for request_key().
|
* Authorisation record for request_key().
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -714,7 +714,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* need write permission on the key to update it */
|
/* need write permission on the key to update it */
|
||||||
ret = key_permission(key_ref, KEY_WRITE);
|
ret = key_permission(key_ref, KEY_NEED_WRITE);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -838,7 +838,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
||||||
|
|
||||||
/* if we're going to allocate a new key, we're going to have
|
/* if we're going to allocate a new key, we're going to have
|
||||||
* to modify the keyring */
|
* to modify the keyring */
|
||||||
ret = key_permission(keyring_ref, KEY_WRITE);
|
ret = key_permission(keyring_ref, KEY_NEED_WRITE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
key_ref = ERR_PTR(ret);
|
key_ref = ERR_PTR(ret);
|
||||||
goto error_link_end;
|
goto error_link_end;
|
||||||
|
@ -928,7 +928,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
|
||||||
key_check(key);
|
key_check(key);
|
||||||
|
|
||||||
/* the key must be writable */
|
/* the key must be writable */
|
||||||
ret = key_permission(key_ref, KEY_WRITE);
|
ret = key_permission(key_ref, KEY_NEED_WRITE);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find the target keyring (which must be writable) */
|
/* find the target keyring (which must be writable) */
|
||||||
keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
|
keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
|
||||||
if (IS_ERR(keyring_ref)) {
|
if (IS_ERR(keyring_ref)) {
|
||||||
ret = PTR_ERR(keyring_ref);
|
ret = PTR_ERR(keyring_ref);
|
||||||
goto error3;
|
goto error3;
|
||||||
|
@ -195,7 +195,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
|
||||||
dest_ref = NULL;
|
dest_ref = NULL;
|
||||||
if (destringid) {
|
if (destringid) {
|
||||||
dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE,
|
dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE,
|
||||||
KEY_WRITE);
|
KEY_NEED_WRITE);
|
||||||
if (IS_ERR(dest_ref)) {
|
if (IS_ERR(dest_ref)) {
|
||||||
ret = PTR_ERR(dest_ref);
|
ret = PTR_ERR(dest_ref);
|
||||||
goto error3;
|
goto error3;
|
||||||
|
@ -253,7 +253,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create)
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
lflags = create ? KEY_LOOKUP_CREATE : 0;
|
lflags = create ? KEY_LOOKUP_CREATE : 0;
|
||||||
key_ref = lookup_user_key(id, lflags, KEY_SEARCH);
|
key_ref = lookup_user_key(id, lflags, KEY_NEED_SEARCH);
|
||||||
if (IS_ERR(key_ref)) {
|
if (IS_ERR(key_ref)) {
|
||||||
ret = PTR_ERR(key_ref);
|
ret = PTR_ERR(key_ref);
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -334,7 +334,7 @@ long keyctl_update_key(key_serial_t id,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find the target key (which must be writable) */
|
/* find the target key (which must be writable) */
|
||||||
key_ref = lookup_user_key(id, 0, KEY_WRITE);
|
key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE);
|
||||||
if (IS_ERR(key_ref)) {
|
if (IS_ERR(key_ref)) {
|
||||||
ret = PTR_ERR(key_ref);
|
ret = PTR_ERR(key_ref);
|
||||||
goto error2;
|
goto error2;
|
||||||
|
@ -365,12 +365,12 @@ long keyctl_revoke_key(key_serial_t id)
|
||||||
key_ref_t key_ref;
|
key_ref_t key_ref;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
key_ref = lookup_user_key(id, 0, KEY_WRITE);
|
key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE);
|
||||||
if (IS_ERR(key_ref)) {
|
if (IS_ERR(key_ref)) {
|
||||||
ret = PTR_ERR(key_ref);
|
ret = PTR_ERR(key_ref);
|
||||||
if (ret != -EACCES)
|
if (ret != -EACCES)
|
||||||
goto error;
|
goto error;
|
||||||
key_ref = lookup_user_key(id, 0, KEY_SETATTR);
|
key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR);
|
||||||
if (IS_ERR(key_ref)) {
|
if (IS_ERR(key_ref)) {
|
||||||
ret = PTR_ERR(key_ref);
|
ret = PTR_ERR(key_ref);
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -401,7 +401,7 @@ long keyctl_invalidate_key(key_serial_t id)
|
||||||
|
|
||||||
kenter("%d", id);
|
kenter("%d", id);
|
||||||
|
|
||||||
key_ref = lookup_user_key(id, 0, KEY_SEARCH);
|
key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
|
||||||
if (IS_ERR(key_ref)) {
|
if (IS_ERR(key_ref)) {
|
||||||
ret = PTR_ERR(key_ref);
|
ret = PTR_ERR(key_ref);
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -428,7 +428,7 @@ long keyctl_keyring_clear(key_serial_t ringid)
|
||||||
key_ref_t keyring_ref;
|
key_ref_t keyring_ref;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
|
keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
|
||||||
if (IS_ERR(keyring_ref)) {
|
if (IS_ERR(keyring_ref)) {
|
||||||
ret = PTR_ERR(keyring_ref);
|
ret = PTR_ERR(keyring_ref);
|
||||||
|
|
||||||
|
@ -470,13 +470,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
|
||||||
key_ref_t keyring_ref, key_ref;
|
key_ref_t keyring_ref, key_ref;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
|
keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
|
||||||
if (IS_ERR(keyring_ref)) {
|
if (IS_ERR(keyring_ref)) {
|
||||||
ret = PTR_ERR(keyring_ref);
|
ret = PTR_ERR(keyring_ref);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK);
|
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_NEED_LINK);
|
||||||
if (IS_ERR(key_ref)) {
|
if (IS_ERR(key_ref)) {
|
||||||
ret = PTR_ERR(key_ref);
|
ret = PTR_ERR(key_ref);
|
||||||
goto error2;
|
goto error2;
|
||||||
|
@ -505,7 +505,7 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
|
||||||
key_ref_t keyring_ref, key_ref;
|
key_ref_t keyring_ref, key_ref;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE);
|
keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_WRITE);
|
||||||
if (IS_ERR(keyring_ref)) {
|
if (IS_ERR(keyring_ref)) {
|
||||||
ret = PTR_ERR(keyring_ref);
|
ret = PTR_ERR(keyring_ref);
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -548,7 +548,7 @@ long keyctl_describe_key(key_serial_t keyid,
|
||||||
char *tmpbuf;
|
char *tmpbuf;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW);
|
key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW);
|
||||||
if (IS_ERR(key_ref)) {
|
if (IS_ERR(key_ref)) {
|
||||||
/* viewing a key under construction is permitted if we have the
|
/* viewing a key under construction is permitted if we have the
|
||||||
* authorisation token handy */
|
* authorisation token handy */
|
||||||
|
@ -639,7 +639,7 @@ long keyctl_keyring_search(key_serial_t ringid,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get the keyring at which to begin the search */
|
/* get the keyring at which to begin the search */
|
||||||
keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH);
|
keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_SEARCH);
|
||||||
if (IS_ERR(keyring_ref)) {
|
if (IS_ERR(keyring_ref)) {
|
||||||
ret = PTR_ERR(keyring_ref);
|
ret = PTR_ERR(keyring_ref);
|
||||||
goto error2;
|
goto error2;
|
||||||
|
@ -649,7 +649,7 @@ long keyctl_keyring_search(key_serial_t ringid,
|
||||||
dest_ref = NULL;
|
dest_ref = NULL;
|
||||||
if (destringid) {
|
if (destringid) {
|
||||||
dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE,
|
dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE,
|
||||||
KEY_WRITE);
|
KEY_NEED_WRITE);
|
||||||
if (IS_ERR(dest_ref)) {
|
if (IS_ERR(dest_ref)) {
|
||||||
ret = PTR_ERR(dest_ref);
|
ret = PTR_ERR(dest_ref);
|
||||||
goto error3;
|
goto error3;
|
||||||
|
@ -676,7 +676,7 @@ long keyctl_keyring_search(key_serial_t ringid,
|
||||||
|
|
||||||
/* link the resulting key to the destination keyring if we can */
|
/* link the resulting key to the destination keyring if we can */
|
||||||
if (dest_ref) {
|
if (dest_ref) {
|
||||||
ret = key_permission(key_ref, KEY_LINK);
|
ret = key_permission(key_ref, KEY_NEED_LINK);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error6;
|
goto error6;
|
||||||
|
|
||||||
|
@ -727,7 +727,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
|
||||||
key = key_ref_to_ptr(key_ref);
|
key = key_ref_to_ptr(key_ref);
|
||||||
|
|
||||||
/* see if we can read it directly */
|
/* see if we can read it directly */
|
||||||
ret = key_permission(key_ref, KEY_READ);
|
ret = key_permission(key_ref, KEY_NEED_READ);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto can_read_key;
|
goto can_read_key;
|
||||||
if (ret != -EACCES)
|
if (ret != -EACCES)
|
||||||
|
@ -799,7 +799,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
|
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
|
||||||
KEY_SETATTR);
|
KEY_NEED_SETATTR);
|
||||||
if (IS_ERR(key_ref)) {
|
if (IS_ERR(key_ref)) {
|
||||||
ret = PTR_ERR(key_ref);
|
ret = PTR_ERR(key_ref);
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -905,7 +905,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
|
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
|
||||||
KEY_SETATTR);
|
KEY_NEED_SETATTR);
|
||||||
if (IS_ERR(key_ref)) {
|
if (IS_ERR(key_ref)) {
|
||||||
ret = PTR_ERR(key_ref);
|
ret = PTR_ERR(key_ref);
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -947,7 +947,7 @@ static long get_instantiation_keyring(key_serial_t ringid,
|
||||||
|
|
||||||
/* if a specific keyring is nominated by ID, then use that */
|
/* if a specific keyring is nominated by ID, then use that */
|
||||||
if (ringid > 0) {
|
if (ringid > 0) {
|
||||||
dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
|
dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
|
||||||
if (IS_ERR(dkref))
|
if (IS_ERR(dkref))
|
||||||
return PTR_ERR(dkref);
|
return PTR_ERR(dkref);
|
||||||
*_dest_keyring = key_ref_to_ptr(dkref);
|
*_dest_keyring = key_ref_to_ptr(dkref);
|
||||||
|
@ -1315,7 +1315,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
|
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
|
||||||
KEY_SETATTR);
|
KEY_NEED_SETATTR);
|
||||||
if (IS_ERR(key_ref)) {
|
if (IS_ERR(key_ref)) {
|
||||||
/* setting the timeout on a key under construction is permitted
|
/* setting the timeout on a key under construction is permitted
|
||||||
* if we have the authorisation token handy */
|
* if we have the authorisation token handy */
|
||||||
|
@ -1418,7 +1418,7 @@ long keyctl_get_security(key_serial_t keyid,
|
||||||
char *context;
|
char *context;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW);
|
key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW);
|
||||||
if (IS_ERR(key_ref)) {
|
if (IS_ERR(key_ref)) {
|
||||||
if (PTR_ERR(key_ref) != -EACCES)
|
if (PTR_ERR(key_ref) != -EACCES)
|
||||||
return PTR_ERR(key_ref);
|
return PTR_ERR(key_ref);
|
||||||
|
@ -1482,7 +1482,7 @@ long keyctl_session_to_parent(void)
|
||||||
struct cred *cred;
|
struct cred *cred;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK);
|
keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_NEED_LINK);
|
||||||
if (IS_ERR(keyring_r))
|
if (IS_ERR(keyring_r))
|
||||||
return PTR_ERR(keyring_r);
|
return PTR_ERR(keyring_r);
|
||||||
|
|
||||||
|
|
|
@ -541,7 +541,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
|
||||||
/* key must have search permissions */
|
/* key must have search permissions */
|
||||||
if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) &&
|
if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) &&
|
||||||
key_task_permission(make_key_ref(key, ctx->possessed),
|
key_task_permission(make_key_ref(key, ctx->possessed),
|
||||||
ctx->cred, KEY_SEARCH) < 0) {
|
ctx->cred, KEY_NEED_SEARCH) < 0) {
|
||||||
ctx->result = ERR_PTR(-EACCES);
|
ctx->result = ERR_PTR(-EACCES);
|
||||||
kleave(" = %d [!perm]", ctx->skipped_ret);
|
kleave(" = %d [!perm]", ctx->skipped_ret);
|
||||||
goto skipped;
|
goto skipped;
|
||||||
|
@ -721,7 +721,7 @@ ascend_to_node:
|
||||||
/* Search a nested keyring */
|
/* Search a nested keyring */
|
||||||
if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) &&
|
if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) &&
|
||||||
key_task_permission(make_key_ref(key, ctx->possessed),
|
key_task_permission(make_key_ref(key, ctx->possessed),
|
||||||
ctx->cred, KEY_SEARCH) < 0)
|
ctx->cred, KEY_NEED_SEARCH) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* stack the current position */
|
/* stack the current position */
|
||||||
|
@ -843,7 +843,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
|
||||||
return ERR_PTR(-ENOTDIR);
|
return ERR_PTR(-ENOTDIR);
|
||||||
|
|
||||||
if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM)) {
|
if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM)) {
|
||||||
err = key_task_permission(keyring_ref, ctx->cred, KEY_SEARCH);
|
err = key_task_permission(keyring_ref, ctx->cred, KEY_NEED_SEARCH);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
@ -973,7 +973,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
|
||||||
|
|
||||||
if (!skip_perm_check &&
|
if (!skip_perm_check &&
|
||||||
key_permission(make_key_ref(keyring, 0),
|
key_permission(make_key_ref(keyring, 0),
|
||||||
KEY_SEARCH) < 0)
|
KEY_NEED_SEARCH) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* we've got a match but we might end up racing with
|
/* we've got a match but we might end up racing with
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
* permissions bits or the LSM check.
|
* permissions bits or the LSM check.
|
||||||
*/
|
*/
|
||||||
int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
|
int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
|
||||||
key_perm_t perm)
|
unsigned perm)
|
||||||
{
|
{
|
||||||
struct key *key;
|
struct key *key;
|
||||||
key_perm_t kperm;
|
key_perm_t kperm;
|
||||||
|
@ -68,7 +68,7 @@ use_these_perms:
|
||||||
if (is_key_possessed(key_ref))
|
if (is_key_possessed(key_ref))
|
||||||
kperm |= key->perm >> 24;
|
kperm |= key->perm >> 24;
|
||||||
|
|
||||||
kperm = kperm & perm & KEY_ALL;
|
kperm = kperm & perm & KEY_NEED_ALL;
|
||||||
|
|
||||||
if (kperm != perm)
|
if (kperm != perm)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
|
@ -108,7 +108,7 @@ static long key_get_persistent(struct user_namespace *ns, kuid_t uid,
|
||||||
return PTR_ERR(persistent_ref);
|
return PTR_ERR(persistent_ref);
|
||||||
|
|
||||||
found:
|
found:
|
||||||
ret = key_task_permission(persistent_ref, current_cred(), KEY_LINK);
|
ret = key_task_permission(persistent_ref, current_cred(), KEY_NEED_LINK);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
persistent = key_ref_to_ptr(persistent_ref);
|
persistent = key_ref_to_ptr(persistent_ref);
|
||||||
ret = key_link(key_ref_to_ptr(dest_ref), persistent);
|
ret = key_link(key_ref_to_ptr(dest_ref), persistent);
|
||||||
|
@ -151,7 +151,7 @@ long keyctl_get_persistent(uid_t _uid, key_serial_t destid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* There must be a destination keyring */
|
/* There must be a destination keyring */
|
||||||
dest_ref = lookup_user_key(destid, KEY_LOOKUP_CREATE, KEY_WRITE);
|
dest_ref = lookup_user_key(destid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
|
||||||
if (IS_ERR(dest_ref))
|
if (IS_ERR(dest_ref))
|
||||||
return PTR_ERR(dest_ref);
|
return PTR_ERR(dest_ref);
|
||||||
if (key_ref_to_ptr(dest_ref)->type != &key_type_keyring) {
|
if (key_ref_to_ptr(dest_ref)->type != &key_type_keyring) {
|
||||||
|
|
|
@ -218,7 +218,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
|
||||||
* - the caller holds a spinlock, and thus the RCU read lock, making our
|
* - the caller holds a spinlock, and thus the RCU read lock, making our
|
||||||
* access to __current_cred() safe
|
* access to __current_cred() safe
|
||||||
*/
|
*/
|
||||||
rc = key_task_permission(key_ref, ctx.cred, KEY_VIEW);
|
rc = key_task_permission(key_ref, ctx.cred, KEY_NEED_VIEW);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
static const int zero, one = 1, max = INT_MAX;
|
static const int zero, one = 1, max = INT_MAX;
|
||||||
|
|
||||||
ctl_table key_sysctls[] = {
|
struct ctl_table key_sysctls[] = {
|
||||||
{
|
{
|
||||||
.procname = "maxkeys",
|
.procname = "maxkeys",
|
||||||
.data = &key_quota_maxkeys,
|
.data = &key_quota_maxkeys,
|
||||||
|
|
|
@ -1425,7 +1425,7 @@ void security_key_free(struct key *key)
|
||||||
}
|
}
|
||||||
|
|
||||||
int security_key_permission(key_ref_t key_ref,
|
int security_key_permission(key_ref_t key_ref,
|
||||||
const struct cred *cred, key_perm_t perm)
|
const struct cred *cred, unsigned perm)
|
||||||
{
|
{
|
||||||
return security_ops->key_permission(key_ref, cred, perm);
|
return security_ops->key_permission(key_ref, cred, perm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -444,11 +444,15 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
|
||||||
avc_dump_query(ab, ad->selinux_audit_data->ssid,
|
avc_dump_query(ab, ad->selinux_audit_data->ssid,
|
||||||
ad->selinux_audit_data->tsid,
|
ad->selinux_audit_data->tsid,
|
||||||
ad->selinux_audit_data->tclass);
|
ad->selinux_audit_data->tclass);
|
||||||
|
if (ad->selinux_audit_data->denied) {
|
||||||
|
audit_log_format(ab, " permissive=%u",
|
||||||
|
ad->selinux_audit_data->result ? 0 : 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is the slow part of avc audit with big stack footprint */
|
/* This is the slow part of avc audit with big stack footprint */
|
||||||
noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
|
noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
|
||||||
u32 requested, u32 audited, u32 denied,
|
u32 requested, u32 audited, u32 denied, int result,
|
||||||
struct common_audit_data *a,
|
struct common_audit_data *a,
|
||||||
unsigned flags)
|
unsigned flags)
|
||||||
{
|
{
|
||||||
|
@ -477,6 +481,7 @@ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
|
||||||
sad.tsid = tsid;
|
sad.tsid = tsid;
|
||||||
sad.audited = audited;
|
sad.audited = audited;
|
||||||
sad.denied = denied;
|
sad.denied = denied;
|
||||||
|
sad.result = result;
|
||||||
|
|
||||||
a->selinux_audit_data = &sad;
|
a->selinux_audit_data = &sad;
|
||||||
|
|
||||||
|
|
|
@ -2123,11 +2123,13 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
|
||||||
new_tsec->exec_sid = 0;
|
new_tsec->exec_sid = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Minimize confusion: if no_new_privs and a transition is
|
* Minimize confusion: if no_new_privs or nosuid and a
|
||||||
* explicitly requested, then fail the exec.
|
* transition is explicitly requested, then fail the exec.
|
||||||
*/
|
*/
|
||||||
if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)
|
if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
|
||||||
|
return -EACCES;
|
||||||
} else {
|
} else {
|
||||||
/* Check for a default transition on this program. */
|
/* Check for a default transition on this program. */
|
||||||
rc = security_transition_sid(old_tsec->sid, isec->sid,
|
rc = security_transition_sid(old_tsec->sid, isec->sid,
|
||||||
|
@ -2770,6 +2772,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
|
||||||
|
|
||||||
static noinline int audit_inode_permission(struct inode *inode,
|
static noinline int audit_inode_permission(struct inode *inode,
|
||||||
u32 perms, u32 audited, u32 denied,
|
u32 perms, u32 audited, u32 denied,
|
||||||
|
int result,
|
||||||
unsigned flags)
|
unsigned flags)
|
||||||
{
|
{
|
||||||
struct common_audit_data ad;
|
struct common_audit_data ad;
|
||||||
|
@ -2780,7 +2783,7 @@ static noinline int audit_inode_permission(struct inode *inode,
|
||||||
ad.u.inode = inode;
|
ad.u.inode = inode;
|
||||||
|
|
||||||
rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms,
|
rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms,
|
||||||
audited, denied, &ad, flags);
|
audited, denied, result, &ad, flags);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2822,7 +2825,7 @@ static int selinux_inode_permission(struct inode *inode, int mask)
|
||||||
if (likely(!audited))
|
if (likely(!audited))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
rc2 = audit_inode_permission(inode, perms, audited, denied, flags);
|
rc2 = audit_inode_permission(inode, perms, audited, denied, rc, flags);
|
||||||
if (rc2)
|
if (rc2)
|
||||||
return rc2;
|
return rc2;
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -5722,7 +5725,7 @@ static void selinux_key_free(struct key *k)
|
||||||
|
|
||||||
static int selinux_key_permission(key_ref_t key_ref,
|
static int selinux_key_permission(key_ref_t key_ref,
|
||||||
const struct cred *cred,
|
const struct cred *cred,
|
||||||
key_perm_t perm)
|
unsigned perm)
|
||||||
{
|
{
|
||||||
struct key *key;
|
struct key *key;
|
||||||
struct key_security_struct *ksec;
|
struct key_security_struct *ksec;
|
||||||
|
|
|
@ -102,7 +102,7 @@ static inline u32 avc_audit_required(u32 requested,
|
||||||
}
|
}
|
||||||
|
|
||||||
int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
|
int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
|
||||||
u32 requested, u32 audited, u32 denied,
|
u32 requested, u32 audited, u32 denied, int result,
|
||||||
struct common_audit_data *a,
|
struct common_audit_data *a,
|
||||||
unsigned flags);
|
unsigned flags);
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
|
||||||
if (likely(!audited))
|
if (likely(!audited))
|
||||||
return 0;
|
return 0;
|
||||||
return slow_avc_audit(ssid, tsid, tclass,
|
return slow_avc_audit(ssid, tsid, tclass,
|
||||||
requested, audited, denied,
|
requested, audited, denied, result,
|
||||||
a, 0);
|
a, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
#include "hashtab.h"
|
#include "hashtab.h"
|
||||||
|
|
||||||
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
|
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
|
||||||
|
@ -40,6 +41,8 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum)
|
||||||
u32 hvalue;
|
u32 hvalue;
|
||||||
struct hashtab_node *prev, *cur, *newnode;
|
struct hashtab_node *prev, *cur, *newnode;
|
||||||
|
|
||||||
|
cond_resched();
|
||||||
|
|
||||||
if (!h || h->nel == HASHTAB_MAX_NODES)
|
if (!h || h->nel == HASHTAB_MAX_NODES)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
|
|
@ -492,6 +492,8 @@ int mls_convert_context(struct policydb *oldp,
|
||||||
rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
|
rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
cond_resched();
|
||||||
}
|
}
|
||||||
ebitmap_destroy(&c->range.level[l].cat);
|
ebitmap_destroy(&c->range.level[l].cat);
|
||||||
c->range.level[l].cat = bitmap;
|
c->range.level[l].cat = bitmap;
|
||||||
|
|
|
@ -80,8 +80,8 @@ struct superblock_smack {
|
||||||
|
|
||||||
struct socket_smack {
|
struct socket_smack {
|
||||||
struct smack_known *smk_out; /* outbound label */
|
struct smack_known *smk_out; /* outbound label */
|
||||||
char *smk_in; /* inbound label */
|
struct smack_known *smk_in; /* inbound label */
|
||||||
char *smk_packet; /* TCP peer label */
|
struct smack_known *smk_packet; /* TCP peer label */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -133,7 +133,7 @@ struct smk_port_label {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct sock *smk_sock; /* socket initialized on */
|
struct sock *smk_sock; /* socket initialized on */
|
||||||
unsigned short smk_port; /* the port number */
|
unsigned short smk_port; /* the port number */
|
||||||
char *smk_in; /* incoming label */
|
struct smack_known *smk_in; /* inbound label */
|
||||||
struct smack_known *smk_out; /* outgoing label */
|
struct smack_known *smk_out; /* outgoing label */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -176,6 +176,14 @@ struct smk_port_label {
|
||||||
*/
|
*/
|
||||||
#define SMACK_CIPSO_MAXCATNUM 184 /* 23 * 8 */
|
#define SMACK_CIPSO_MAXCATNUM 184 /* 23 * 8 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ptrace rules
|
||||||
|
*/
|
||||||
|
#define SMACK_PTRACE_DEFAULT 0
|
||||||
|
#define SMACK_PTRACE_EXACT 1
|
||||||
|
#define SMACK_PTRACE_DRACONIAN 2
|
||||||
|
#define SMACK_PTRACE_MAX SMACK_PTRACE_DRACONIAN
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags for untraditional access modes.
|
* Flags for untraditional access modes.
|
||||||
* It shouldn't be necessary to avoid conflicts with definitions
|
* It shouldn't be necessary to avoid conflicts with definitions
|
||||||
|
@ -225,6 +233,7 @@ struct inode_smack *new_inode_smack(char *);
|
||||||
*/
|
*/
|
||||||
int smk_access_entry(char *, char *, struct list_head *);
|
int smk_access_entry(char *, char *, struct list_head *);
|
||||||
int smk_access(struct smack_known *, char *, int, struct smk_audit_info *);
|
int smk_access(struct smack_known *, char *, int, struct smk_audit_info *);
|
||||||
|
int smk_tskacc(struct task_smack *, char *, u32, struct smk_audit_info *);
|
||||||
int smk_curacc(char *, u32, struct smk_audit_info *);
|
int smk_curacc(char *, u32, struct smk_audit_info *);
|
||||||
struct smack_known *smack_from_secid(const u32);
|
struct smack_known *smack_from_secid(const u32);
|
||||||
char *smk_parse_smack(const char *string, int len);
|
char *smk_parse_smack(const char *string, int len);
|
||||||
|
@ -244,6 +253,7 @@ extern struct smack_known *smack_net_ambient;
|
||||||
extern struct smack_known *smack_onlycap;
|
extern struct smack_known *smack_onlycap;
|
||||||
extern struct smack_known *smack_syslog_label;
|
extern struct smack_known *smack_syslog_label;
|
||||||
extern const char *smack_cipso_option;
|
extern const char *smack_cipso_option;
|
||||||
|
extern int smack_ptrace_rule;
|
||||||
|
|
||||||
extern struct smack_known smack_known_floor;
|
extern struct smack_known smack_known_floor;
|
||||||
extern struct smack_known smack_known_hat;
|
extern struct smack_known smack_known_hat;
|
||||||
|
|
|
@ -192,20 +192,21 @@ out_audit:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_curacc - determine if current has a specific access to an object
|
* smk_tskacc - determine if a task has a specific access to an object
|
||||||
|
* @tsp: a pointer to the subject task
|
||||||
* @obj_label: a pointer to the object's Smack label
|
* @obj_label: a pointer to the object's Smack label
|
||||||
* @mode: the access requested, in "MAY" format
|
* @mode: the access requested, in "MAY" format
|
||||||
* @a : common audit data
|
* @a : common audit data
|
||||||
*
|
*
|
||||||
* This function checks the current subject label/object label pair
|
* This function checks the subject task's label/object label pair
|
||||||
* in the access rule list and returns 0 if the access is permitted,
|
* in the access rule list and returns 0 if the access is permitted,
|
||||||
* non zero otherwise. It allows that current may have the capability
|
* non zero otherwise. It allows that the task may have the capability
|
||||||
* to override the rules.
|
* to override the rules.
|
||||||
*/
|
*/
|
||||||
int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
|
int smk_tskacc(struct task_smack *subject, char *obj_label,
|
||||||
|
u32 mode, struct smk_audit_info *a)
|
||||||
{
|
{
|
||||||
struct task_smack *tsp = current_security();
|
struct smack_known *skp = smk_of_task(subject);
|
||||||
struct smack_known *skp = smk_of_task(tsp);
|
|
||||||
int may;
|
int may;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -219,7 +220,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
|
||||||
* it can further restrict access.
|
* it can further restrict access.
|
||||||
*/
|
*/
|
||||||
may = smk_access_entry(skp->smk_known, obj_label,
|
may = smk_access_entry(skp->smk_known, obj_label,
|
||||||
&tsp->smk_rules);
|
&subject->smk_rules);
|
||||||
if (may < 0)
|
if (may < 0)
|
||||||
goto out_audit;
|
goto out_audit;
|
||||||
if ((mode & may) == mode)
|
if ((mode & may) == mode)
|
||||||
|
@ -241,6 +242,24 @@ out_audit:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smk_curacc - determine if current has a specific access to an object
|
||||||
|
* @obj_label: a pointer to the object's Smack label
|
||||||
|
* @mode: the access requested, in "MAY" format
|
||||||
|
* @a : common audit data
|
||||||
|
*
|
||||||
|
* This function checks the current subject label/object label pair
|
||||||
|
* in the access rule list and returns 0 if the access is permitted,
|
||||||
|
* non zero otherwise. It allows that current may have the capability
|
||||||
|
* to override the rules.
|
||||||
|
*/
|
||||||
|
int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
|
||||||
|
{
|
||||||
|
struct task_smack *tsp = current_security();
|
||||||
|
|
||||||
|
return smk_tskacc(tsp, obj_label, mode, a);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_AUDIT
|
#ifdef CONFIG_AUDIT
|
||||||
/**
|
/**
|
||||||
* smack_str_from_perm : helper to transalate an int to a
|
* smack_str_from_perm : helper to transalate an int to a
|
||||||
|
@ -285,7 +304,10 @@ static void smack_log_callback(struct audit_buffer *ab, void *a)
|
||||||
audit_log_untrustedstring(ab, sad->subject);
|
audit_log_untrustedstring(ab, sad->subject);
|
||||||
audit_log_format(ab, " object=");
|
audit_log_format(ab, " object=");
|
||||||
audit_log_untrustedstring(ab, sad->object);
|
audit_log_untrustedstring(ab, sad->object);
|
||||||
audit_log_format(ab, " requested=%s", sad->request);
|
if (sad->request[0] == '\0')
|
||||||
|
audit_log_format(ab, " labels_differ");
|
||||||
|
else
|
||||||
|
audit_log_format(ab, " requested=%s", sad->request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -157,6 +157,74 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_*
|
||||||
|
* @mode - input mode in form of PTRACE_MODE_*
|
||||||
|
*
|
||||||
|
* Returns a converted MAY_* mode usable by smack rules
|
||||||
|
*/
|
||||||
|
static inline unsigned int smk_ptrace_mode(unsigned int mode)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case PTRACE_MODE_READ:
|
||||||
|
return MAY_READ;
|
||||||
|
case PTRACE_MODE_ATTACH:
|
||||||
|
return MAY_READWRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smk_ptrace_rule_check - helper for ptrace access
|
||||||
|
* @tracer: tracer process
|
||||||
|
* @tracee_label: label of the process that's about to be traced,
|
||||||
|
* the pointer must originate from smack structures
|
||||||
|
* @mode: ptrace attachment mode (PTRACE_MODE_*)
|
||||||
|
* @func: name of the function that called us, used for audit
|
||||||
|
*
|
||||||
|
* Returns 0 on access granted, -error on error
|
||||||
|
*/
|
||||||
|
static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label,
|
||||||
|
unsigned int mode, const char *func)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct smk_audit_info ad, *saip = NULL;
|
||||||
|
struct task_smack *tsp;
|
||||||
|
struct smack_known *skp;
|
||||||
|
|
||||||
|
if ((mode & PTRACE_MODE_NOAUDIT) == 0) {
|
||||||
|
smk_ad_init(&ad, func, LSM_AUDIT_DATA_TASK);
|
||||||
|
smk_ad_setfield_u_tsk(&ad, tracer);
|
||||||
|
saip = &ad;
|
||||||
|
}
|
||||||
|
|
||||||
|
tsp = task_security(tracer);
|
||||||
|
skp = smk_of_task(tsp);
|
||||||
|
|
||||||
|
if ((mode & PTRACE_MODE_ATTACH) &&
|
||||||
|
(smack_ptrace_rule == SMACK_PTRACE_EXACT ||
|
||||||
|
smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) {
|
||||||
|
if (skp->smk_known == tracee_label)
|
||||||
|
rc = 0;
|
||||||
|
else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)
|
||||||
|
rc = -EACCES;
|
||||||
|
else if (capable(CAP_SYS_PTRACE))
|
||||||
|
rc = 0;
|
||||||
|
else
|
||||||
|
rc = -EACCES;
|
||||||
|
|
||||||
|
if (saip)
|
||||||
|
smack_log(skp->smk_known, tracee_label, 0, rc, saip);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
|
||||||
|
rc = smk_tskacc(tsp, tracee_label, smk_ptrace_mode(mode), saip);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LSM hooks.
|
* LSM hooks.
|
||||||
* We he, that is fun!
|
* We he, that is fun!
|
||||||
|
@ -165,16 +233,15 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead,
|
||||||
/**
|
/**
|
||||||
* smack_ptrace_access_check - Smack approval on PTRACE_ATTACH
|
* smack_ptrace_access_check - Smack approval on PTRACE_ATTACH
|
||||||
* @ctp: child task pointer
|
* @ctp: child task pointer
|
||||||
* @mode: ptrace attachment mode
|
* @mode: ptrace attachment mode (PTRACE_MODE_*)
|
||||||
*
|
*
|
||||||
* Returns 0 if access is OK, an error code otherwise
|
* Returns 0 if access is OK, an error code otherwise
|
||||||
*
|
*
|
||||||
* Do the capability checks, and require read and write.
|
* Do the capability checks.
|
||||||
*/
|
*/
|
||||||
static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
|
static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct smk_audit_info ad;
|
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
|
|
||||||
rc = cap_ptrace_access_check(ctp, mode);
|
rc = cap_ptrace_access_check(ctp, mode);
|
||||||
|
@ -182,10 +249,8 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
skp = smk_of_task(task_security(ctp));
|
skp = smk_of_task(task_security(ctp));
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
|
|
||||||
smk_ad_setfield_u_tsk(&ad, ctp);
|
|
||||||
|
|
||||||
rc = smk_curacc(skp->smk_known, mode, &ad);
|
rc = smk_ptrace_rule_check(current, skp->smk_known, mode, __func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,23 +260,21 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
|
||||||
*
|
*
|
||||||
* Returns 0 if access is OK, an error code otherwise
|
* Returns 0 if access is OK, an error code otherwise
|
||||||
*
|
*
|
||||||
* Do the capability checks, and require read and write.
|
* Do the capability checks, and require PTRACE_MODE_ATTACH.
|
||||||
*/
|
*/
|
||||||
static int smack_ptrace_traceme(struct task_struct *ptp)
|
static int smack_ptrace_traceme(struct task_struct *ptp)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct smk_audit_info ad;
|
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
|
|
||||||
rc = cap_ptrace_traceme(ptp);
|
rc = cap_ptrace_traceme(ptp);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
skp = smk_of_task(task_security(ptp));
|
skp = smk_of_task(current_security());
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
|
|
||||||
smk_ad_setfield_u_tsk(&ad, ptp);
|
|
||||||
|
|
||||||
rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad);
|
rc = smk_ptrace_rule_check(ptp, skp->smk_known,
|
||||||
|
PTRACE_MODE_ATTACH, __func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,9 +476,11 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
||||||
* Initialize the root inode.
|
* Initialize the root inode.
|
||||||
*/
|
*/
|
||||||
isp = inode->i_security;
|
isp = inode->i_security;
|
||||||
if (inode->i_security == NULL) {
|
if (isp == NULL) {
|
||||||
inode->i_security = new_inode_smack(sp->smk_root);
|
isp = new_inode_smack(sp->smk_root);
|
||||||
isp = inode->i_security;
|
if (isp == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
inode->i_security = isp;
|
||||||
} else
|
} else
|
||||||
isp->smk_inode = sp->smk_root;
|
isp->smk_inode = sp->smk_root;
|
||||||
|
|
||||||
|
@ -453,7 +518,7 @@ static int smack_sb_statfs(struct dentry *dentry)
|
||||||
* smack_bprm_set_creds - set creds for exec
|
* smack_bprm_set_creds - set creds for exec
|
||||||
* @bprm: the exec information
|
* @bprm: the exec information
|
||||||
*
|
*
|
||||||
* Returns 0 if it gets a blob, -ENOMEM otherwise
|
* Returns 0 if it gets a blob, -EPERM if exec forbidden and -ENOMEM otherwise
|
||||||
*/
|
*/
|
||||||
static int smack_bprm_set_creds(struct linux_binprm *bprm)
|
static int smack_bprm_set_creds(struct linux_binprm *bprm)
|
||||||
{
|
{
|
||||||
|
@ -473,7 +538,22 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
|
||||||
if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task)
|
if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (bprm->unsafe)
|
if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
|
||||||
|
struct task_struct *tracer;
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
tracer = ptrace_parent(current);
|
||||||
|
if (likely(tracer != NULL))
|
||||||
|
rc = smk_ptrace_rule_check(tracer,
|
||||||
|
isp->smk_task->smk_known,
|
||||||
|
PTRACE_MODE_ATTACH,
|
||||||
|
__func__);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
if (rc != 0)
|
||||||
|
return rc;
|
||||||
|
} else if (bprm->unsafe)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
bsp->smk_task = isp->smk_task;
|
bsp->smk_task = isp->smk_task;
|
||||||
|
@ -880,18 +960,20 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
skp = smk_import_entry(value, size);
|
|
||||||
if (strcmp(name, XATTR_NAME_SMACK) == 0) {
|
if (strcmp(name, XATTR_NAME_SMACK) == 0) {
|
||||||
|
skp = smk_import_entry(value, size);
|
||||||
if (skp != NULL)
|
if (skp != NULL)
|
||||||
isp->smk_inode = skp->smk_known;
|
isp->smk_inode = skp->smk_known;
|
||||||
else
|
else
|
||||||
isp->smk_inode = smack_known_invalid.smk_known;
|
isp->smk_inode = smack_known_invalid.smk_known;
|
||||||
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
|
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
|
||||||
|
skp = smk_import_entry(value, size);
|
||||||
if (skp != NULL)
|
if (skp != NULL)
|
||||||
isp->smk_task = skp;
|
isp->smk_task = skp;
|
||||||
else
|
else
|
||||||
isp->smk_task = &smack_known_invalid;
|
isp->smk_task = &smack_known_invalid;
|
||||||
} else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
|
} else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
|
||||||
|
skp = smk_import_entry(value, size);
|
||||||
if (skp != NULL)
|
if (skp != NULL)
|
||||||
isp->smk_mmap = skp;
|
isp->smk_mmap = skp;
|
||||||
else
|
else
|
||||||
|
@ -938,24 +1020,37 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
|
||||||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
|
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
|
||||||
strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
|
strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
|
||||||
strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 ||
|
strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 ||
|
||||||
strcmp(name, XATTR_NAME_SMACKMMAP)) {
|
strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
|
||||||
if (!smack_privileged(CAP_MAC_ADMIN))
|
if (!smack_privileged(CAP_MAC_ADMIN))
|
||||||
rc = -EPERM;
|
rc = -EPERM;
|
||||||
} else
|
} else
|
||||||
rc = cap_inode_removexattr(dentry, name);
|
rc = cap_inode_removexattr(dentry, name);
|
||||||
|
|
||||||
|
if (rc != 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
|
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
|
||||||
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
|
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
|
||||||
if (rc == 0)
|
|
||||||
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
|
|
||||||
|
|
||||||
if (rc == 0) {
|
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
|
||||||
isp = dentry->d_inode->i_security;
|
if (rc != 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
isp = dentry->d_inode->i_security;
|
||||||
|
/*
|
||||||
|
* Don't do anything special for these.
|
||||||
|
* XATTR_NAME_SMACKIPIN
|
||||||
|
* XATTR_NAME_SMACKIPOUT
|
||||||
|
* XATTR_NAME_SMACKEXEC
|
||||||
|
*/
|
||||||
|
if (strcmp(name, XATTR_NAME_SMACK) == 0)
|
||||||
isp->smk_task = NULL;
|
isp->smk_task = NULL;
|
||||||
|
else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0)
|
||||||
isp->smk_mmap = NULL;
|
isp->smk_mmap = NULL;
|
||||||
}
|
else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0)
|
||||||
|
isp->smk_flags &= ~SMK_INODE_TRANSMUTE;
|
||||||
|
|
||||||
return rc;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1000,7 +1095,7 @@ static int smack_inode_getsecurity(const struct inode *inode,
|
||||||
ssp = sock->sk->sk_security;
|
ssp = sock->sk->sk_security;
|
||||||
|
|
||||||
if (strcmp(name, XATTR_SMACK_IPIN) == 0)
|
if (strcmp(name, XATTR_SMACK_IPIN) == 0)
|
||||||
isp = ssp->smk_in;
|
isp = ssp->smk_in->smk_known;
|
||||||
else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
|
else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
|
||||||
isp = ssp->smk_out->smk_known;
|
isp = ssp->smk_out->smk_known;
|
||||||
else
|
else
|
||||||
|
@ -1367,19 +1462,32 @@ static int smack_file_receive(struct file *file)
|
||||||
/**
|
/**
|
||||||
* smack_file_open - Smack dentry open processing
|
* smack_file_open - Smack dentry open processing
|
||||||
* @file: the object
|
* @file: the object
|
||||||
* @cred: unused
|
* @cred: task credential
|
||||||
*
|
*
|
||||||
* Set the security blob in the file structure.
|
* Set the security blob in the file structure.
|
||||||
|
* Allow the open only if the task has read access. There are
|
||||||
|
* many read operations (e.g. fstat) that you can do with an
|
||||||
|
* fd even if you have the file open write-only.
|
||||||
*
|
*
|
||||||
* Returns 0
|
* Returns 0
|
||||||
*/
|
*/
|
||||||
static int smack_file_open(struct file *file, const struct cred *cred)
|
static int smack_file_open(struct file *file, const struct cred *cred)
|
||||||
{
|
{
|
||||||
|
struct task_smack *tsp = cred->security;
|
||||||
struct inode_smack *isp = file_inode(file)->i_security;
|
struct inode_smack *isp = file_inode(file)->i_security;
|
||||||
|
struct smk_audit_info ad;
|
||||||
|
int rc;
|
||||||
|
|
||||||
file->f_security = isp->smk_inode;
|
if (smack_privileged(CAP_MAC_OVERRIDE))
|
||||||
|
return 0;
|
||||||
|
|
||||||
return 0;
|
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
||||||
|
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
||||||
|
rc = smk_access(tsp->smk_task, isp->smk_inode, MAY_READ, &ad);
|
||||||
|
if (rc == 0)
|
||||||
|
file->f_security = isp->smk_inode;
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1764,7 +1872,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
|
||||||
if (ssp == NULL)
|
if (ssp == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ssp->smk_in = skp->smk_known;
|
ssp->smk_in = skp;
|
||||||
ssp->smk_out = skp;
|
ssp->smk_out = skp;
|
||||||
ssp->smk_packet = NULL;
|
ssp->smk_packet = NULL;
|
||||||
|
|
||||||
|
@ -2004,7 +2112,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
|
||||||
|
|
||||||
if (act == SMK_RECEIVING) {
|
if (act == SMK_RECEIVING) {
|
||||||
skp = smack_net_ambient;
|
skp = smack_net_ambient;
|
||||||
object = ssp->smk_in;
|
object = ssp->smk_in->smk_known;
|
||||||
} else {
|
} else {
|
||||||
skp = ssp->smk_out;
|
skp = ssp->smk_out;
|
||||||
object = smack_net_ambient->smk_known;
|
object = smack_net_ambient->smk_known;
|
||||||
|
@ -2034,9 +2142,9 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
|
||||||
list_for_each_entry(spp, &smk_ipv6_port_list, list) {
|
list_for_each_entry(spp, &smk_ipv6_port_list, list) {
|
||||||
if (spp->smk_port != port)
|
if (spp->smk_port != port)
|
||||||
continue;
|
continue;
|
||||||
object = spp->smk_in;
|
object = spp->smk_in->smk_known;
|
||||||
if (act == SMK_CONNECTING)
|
if (act == SMK_CONNECTING)
|
||||||
ssp->smk_packet = spp->smk_out->smk_known;
|
ssp->smk_packet = spp->smk_out;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2076,7 +2184,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (value == NULL || size > SMK_LONGLABEL || size == 0)
|
if (value == NULL || size > SMK_LONGLABEL || size == 0)
|
||||||
return -EACCES;
|
return -EINVAL;
|
||||||
|
|
||||||
skp = smk_import_entry(value, size);
|
skp = smk_import_entry(value, size);
|
||||||
if (skp == NULL)
|
if (skp == NULL)
|
||||||
|
@ -2100,7 +2208,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
|
||||||
ssp = sock->sk->sk_security;
|
ssp = sock->sk->sk_security;
|
||||||
|
|
||||||
if (strcmp(name, XATTR_SMACK_IPIN) == 0)
|
if (strcmp(name, XATTR_SMACK_IPIN) == 0)
|
||||||
ssp->smk_in = skp->smk_known;
|
ssp->smk_in = skp;
|
||||||
else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
|
else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
|
||||||
ssp->smk_out = skp;
|
ssp->smk_out = skp;
|
||||||
if (sock->sk->sk_family == PF_INET) {
|
if (sock->sk->sk_family == PF_INET) {
|
||||||
|
@ -2713,6 +2821,15 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||||
* of the superblock.
|
* of the superblock.
|
||||||
*/
|
*/
|
||||||
if (opt_dentry->d_parent == opt_dentry) {
|
if (opt_dentry->d_parent == opt_dentry) {
|
||||||
|
if (sbp->s_magic == CGROUP_SUPER_MAGIC) {
|
||||||
|
/*
|
||||||
|
* The cgroup filesystem is never mounted,
|
||||||
|
* so there's no opportunity to set the mount
|
||||||
|
* options.
|
||||||
|
*/
|
||||||
|
sbsp->smk_root = smack_known_star.smk_known;
|
||||||
|
sbsp->smk_default = smack_known_star.smk_known;
|
||||||
|
}
|
||||||
isp->smk_inode = sbsp->smk_root;
|
isp->smk_inode = sbsp->smk_root;
|
||||||
isp->smk_flags |= SMK_INODE_INSTANT;
|
isp->smk_flags |= SMK_INODE_INSTANT;
|
||||||
goto unlockandout;
|
goto unlockandout;
|
||||||
|
@ -2726,16 +2843,20 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||||
*/
|
*/
|
||||||
switch (sbp->s_magic) {
|
switch (sbp->s_magic) {
|
||||||
case SMACK_MAGIC:
|
case SMACK_MAGIC:
|
||||||
|
case PIPEFS_MAGIC:
|
||||||
|
case SOCKFS_MAGIC:
|
||||||
|
case CGROUP_SUPER_MAGIC:
|
||||||
/*
|
/*
|
||||||
* Casey says that it's a little embarrassing
|
* Casey says that it's a little embarrassing
|
||||||
* that the smack file system doesn't do
|
* that the smack file system doesn't do
|
||||||
* extended attributes.
|
* extended attributes.
|
||||||
*/
|
*
|
||||||
final = smack_known_star.smk_known;
|
|
||||||
break;
|
|
||||||
case PIPEFS_MAGIC:
|
|
||||||
/*
|
|
||||||
* Casey says pipes are easy (?)
|
* Casey says pipes are easy (?)
|
||||||
|
*
|
||||||
|
* Socket access is controlled by the socket
|
||||||
|
* structures associated with the task involved.
|
||||||
|
*
|
||||||
|
* Cgroupfs is special
|
||||||
*/
|
*/
|
||||||
final = smack_known_star.smk_known;
|
final = smack_known_star.smk_known;
|
||||||
break;
|
break;
|
||||||
|
@ -2747,13 +2868,6 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||||
*/
|
*/
|
||||||
final = ckp->smk_known;
|
final = ckp->smk_known;
|
||||||
break;
|
break;
|
||||||
case SOCKFS_MAGIC:
|
|
||||||
/*
|
|
||||||
* Socket access is controlled by the socket
|
|
||||||
* structures associated with the task involved.
|
|
||||||
*/
|
|
||||||
final = smack_known_star.smk_known;
|
|
||||||
break;
|
|
||||||
case PROC_SUPER_MAGIC:
|
case PROC_SUPER_MAGIC:
|
||||||
/*
|
/*
|
||||||
* Casey says procfs appears not to care.
|
* Casey says procfs appears not to care.
|
||||||
|
@ -2959,30 +3073,34 @@ static int smack_unix_stream_connect(struct sock *sock,
|
||||||
struct sock *other, struct sock *newsk)
|
struct sock *other, struct sock *newsk)
|
||||||
{
|
{
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
|
struct smack_known *okp;
|
||||||
struct socket_smack *ssp = sock->sk_security;
|
struct socket_smack *ssp = sock->sk_security;
|
||||||
struct socket_smack *osp = other->sk_security;
|
struct socket_smack *osp = other->sk_security;
|
||||||
struct socket_smack *nsp = newsk->sk_security;
|
struct socket_smack *nsp = newsk->sk_security;
|
||||||
struct smk_audit_info ad;
|
struct smk_audit_info ad;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
#ifdef CONFIG_AUDIT
|
#ifdef CONFIG_AUDIT
|
||||||
struct lsm_network_audit net;
|
struct lsm_network_audit net;
|
||||||
|
|
||||||
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
|
|
||||||
smk_ad_setfield_u_net_sk(&ad, other);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!smack_privileged(CAP_MAC_OVERRIDE)) {
|
if (!smack_privileged(CAP_MAC_OVERRIDE)) {
|
||||||
skp = ssp->smk_out;
|
skp = ssp->smk_out;
|
||||||
rc = smk_access(skp, osp->smk_in, MAY_WRITE, &ad);
|
okp = osp->smk_out;
|
||||||
|
#ifdef CONFIG_AUDIT
|
||||||
|
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
|
||||||
|
smk_ad_setfield_u_net_sk(&ad, other);
|
||||||
|
#endif
|
||||||
|
rc = smk_access(skp, okp->smk_known, MAY_WRITE, &ad);
|
||||||
|
if (rc == 0)
|
||||||
|
rc = smk_access(okp, okp->smk_known, MAY_WRITE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cross reference the peer labels for SO_PEERSEC.
|
* Cross reference the peer labels for SO_PEERSEC.
|
||||||
*/
|
*/
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
nsp->smk_packet = ssp->smk_out->smk_known;
|
nsp->smk_packet = ssp->smk_out;
|
||||||
ssp->smk_packet = osp->smk_out->smk_known;
|
ssp->smk_packet = osp->smk_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -3014,7 +3132,7 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
skp = ssp->smk_out;
|
skp = ssp->smk_out;
|
||||||
return smk_access(skp, osp->smk_in, MAY_WRITE, &ad);
|
return smk_access(skp, osp->smk_in->smk_known, MAY_WRITE, &ad);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3109,7 +3227,7 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
|
||||||
if (found)
|
if (found)
|
||||||
return skp;
|
return skp;
|
||||||
|
|
||||||
if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known)
|
if (ssp != NULL && ssp->smk_in == &smack_known_star)
|
||||||
return &smack_known_web;
|
return &smack_known_web;
|
||||||
return &smack_known_star;
|
return &smack_known_star;
|
||||||
}
|
}
|
||||||
|
@ -3228,7 +3346,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||||||
* This is the simplist possible security model
|
* This is the simplist possible security model
|
||||||
* for networking.
|
* for networking.
|
||||||
*/
|
*/
|
||||||
rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
|
rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
netlbl_skbuff_err(skb, rc, 0);
|
netlbl_skbuff_err(skb, rc, 0);
|
||||||
break;
|
break;
|
||||||
|
@ -3263,7 +3381,7 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
|
||||||
|
|
||||||
ssp = sock->sk->sk_security;
|
ssp = sock->sk->sk_security;
|
||||||
if (ssp->smk_packet != NULL) {
|
if (ssp->smk_packet != NULL) {
|
||||||
rcp = ssp->smk_packet;
|
rcp = ssp->smk_packet->smk_known;
|
||||||
slen = strlen(rcp) + 1;
|
slen = strlen(rcp) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3348,7 +3466,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ssp = sk->sk_security;
|
ssp = sk->sk_security;
|
||||||
ssp->smk_in = skp->smk_known;
|
ssp->smk_in = skp;
|
||||||
ssp->smk_out = skp;
|
ssp->smk_out = skp;
|
||||||
/* cssp->smk_packet is already set in smack_inet_csk_clone() */
|
/* cssp->smk_packet is already set in smack_inet_csk_clone() */
|
||||||
}
|
}
|
||||||
|
@ -3408,7 +3526,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
||||||
* Receiving a packet requires that the other end be able to write
|
* Receiving a packet requires that the other end be able to write
|
||||||
* here. Read access is not required.
|
* here. Read access is not required.
|
||||||
*/
|
*/
|
||||||
rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
|
rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@ -3452,7 +3570,7 @@ static void smack_inet_csk_clone(struct sock *sk,
|
||||||
|
|
||||||
if (req->peer_secid != 0) {
|
if (req->peer_secid != 0) {
|
||||||
skp = smack_from_secid(req->peer_secid);
|
skp = smack_from_secid(req->peer_secid);
|
||||||
ssp->smk_packet = skp->smk_known;
|
ssp->smk_packet = skp;
|
||||||
} else
|
} else
|
||||||
ssp->smk_packet = NULL;
|
ssp->smk_packet = NULL;
|
||||||
}
|
}
|
||||||
|
@ -3506,11 +3624,12 @@ static void smack_key_free(struct key *key)
|
||||||
* an error code otherwise
|
* an error code otherwise
|
||||||
*/
|
*/
|
||||||
static int smack_key_permission(key_ref_t key_ref,
|
static int smack_key_permission(key_ref_t key_ref,
|
||||||
const struct cred *cred, key_perm_t perm)
|
const struct cred *cred, unsigned perm)
|
||||||
{
|
{
|
||||||
struct key *keyp;
|
struct key *keyp;
|
||||||
struct smk_audit_info ad;
|
struct smk_audit_info ad;
|
||||||
struct smack_known *tkp = smk_of_task(cred->security);
|
struct smack_known *tkp = smk_of_task(cred->security);
|
||||||
|
int request = 0;
|
||||||
|
|
||||||
keyp = key_ref_to_ptr(key_ref);
|
keyp = key_ref_to_ptr(key_ref);
|
||||||
if (keyp == NULL)
|
if (keyp == NULL)
|
||||||
|
@ -3531,7 +3650,11 @@ static int smack_key_permission(key_ref_t key_ref,
|
||||||
ad.a.u.key_struct.key = keyp->serial;
|
ad.a.u.key_struct.key = keyp->serial;
|
||||||
ad.a.u.key_struct.key_desc = keyp->description;
|
ad.a.u.key_struct.key_desc = keyp->description;
|
||||||
#endif
|
#endif
|
||||||
return smk_access(tkp, keyp->security, MAY_READWRITE, &ad);
|
if (perm & KEY_NEED_READ)
|
||||||
|
request = MAY_READ;
|
||||||
|
if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR))
|
||||||
|
request = MAY_WRITE;
|
||||||
|
return smk_access(tkp, keyp->security, request, &ad);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_KEYS */
|
#endif /* CONFIG_KEYS */
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ enum smk_inos {
|
||||||
SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */
|
SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */
|
||||||
SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */
|
SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */
|
||||||
SMK_SYSLOG = 20, /* change syslog label) */
|
SMK_SYSLOG = 20, /* change syslog label) */
|
||||||
|
SMK_PTRACE = 21, /* set ptrace rule */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -100,6 +101,15 @@ struct smack_known *smack_onlycap;
|
||||||
*/
|
*/
|
||||||
struct smack_known *smack_syslog_label;
|
struct smack_known *smack_syslog_label;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ptrace current rule
|
||||||
|
* SMACK_PTRACE_DEFAULT regular smack ptrace rules (/proc based)
|
||||||
|
* SMACK_PTRACE_EXACT labels must match, but can be overriden with
|
||||||
|
* CAP_SYS_PTRACE
|
||||||
|
* SMACK_PTRACE_DRACONIAN lables must match, CAP_SYS_PTRACE has no effect
|
||||||
|
*/
|
||||||
|
int smack_ptrace_rule = SMACK_PTRACE_DEFAULT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Certain IP addresses may be designated as single label hosts.
|
* Certain IP addresses may be designated as single label hosts.
|
||||||
* Packets are sent there unlabeled, but only from tasks that
|
* Packets are sent there unlabeled, but only from tasks that
|
||||||
|
@ -1183,7 +1193,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
|
||||||
|
|
||||||
data[count] = '\0';
|
data[count] = '\0';
|
||||||
|
|
||||||
rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%d %s",
|
rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%u %s",
|
||||||
&host[0], &host[1], &host[2], &host[3], &m, smack);
|
&host[0], &host[1], &host[2], &host[3], &m, smack);
|
||||||
if (rc != 6) {
|
if (rc != 6) {
|
||||||
rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s",
|
rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s",
|
||||||
|
@ -2243,6 +2253,68 @@ static const struct file_operations smk_syslog_ops = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smk_read_ptrace - read() for /smack/ptrace
|
||||||
|
* @filp: file pointer, not actually used
|
||||||
|
* @buf: where to put the result
|
||||||
|
* @count: maximum to send along
|
||||||
|
* @ppos: where to start
|
||||||
|
*
|
||||||
|
* Returns number of bytes read or error code, as appropriate
|
||||||
|
*/
|
||||||
|
static ssize_t smk_read_ptrace(struct file *filp, char __user *buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
char temp[32];
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
if (*ppos != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sprintf(temp, "%d\n", smack_ptrace_rule);
|
||||||
|
rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smk_write_ptrace - write() for /smack/ptrace
|
||||||
|
* @file: file pointer
|
||||||
|
* @buf: data from user space
|
||||||
|
* @count: bytes sent
|
||||||
|
* @ppos: where to start - must be 0
|
||||||
|
*/
|
||||||
|
static ssize_t smk_write_ptrace(struct file *file, const char __user *buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
char temp[32];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!smack_privileged(CAP_MAC_ADMIN))
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
|
if (*ppos != 0 || count >= sizeof(temp) || count == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (copy_from_user(temp, buf, count) != 0)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
temp[count] = '\0';
|
||||||
|
|
||||||
|
if (sscanf(temp, "%d", &i) != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
if (i < SMACK_PTRACE_DEFAULT || i > SMACK_PTRACE_MAX)
|
||||||
|
return -EINVAL;
|
||||||
|
smack_ptrace_rule = i;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations smk_ptrace_ops = {
|
||||||
|
.write = smk_write_ptrace,
|
||||||
|
.read = smk_read_ptrace,
|
||||||
|
.llseek = default_llseek,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_fill_super - fill the smackfs superblock
|
* smk_fill_super - fill the smackfs superblock
|
||||||
* @sb: the empty superblock
|
* @sb: the empty superblock
|
||||||
|
@ -2296,6 +2368,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
"change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR},
|
"change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR},
|
||||||
[SMK_SYSLOG] = {
|
[SMK_SYSLOG] = {
|
||||||
"syslog", &smk_syslog_ops, S_IRUGO|S_IWUSR},
|
"syslog", &smk_syslog_ops, S_IRUGO|S_IWUSR},
|
||||||
|
[SMK_PTRACE] = {
|
||||||
|
"ptrace", &smk_ptrace_ops, S_IRUGO|S_IWUSR},
|
||||||
/* last one */
|
/* last one */
|
||||||
{""}
|
{""}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue