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:
Linus Torvalds 2014-06-10 10:05:36 -07:00
commit fad0701eaa
27 changed files with 407 additions and 137 deletions

View File

@ -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]

View File

@ -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.

View File

@ -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.

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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().
*/ */

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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,

View File

@ -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);
} }

View File

@ -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;

View File

@ -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;

View File

@ -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);
} }

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
} }
/** /**

View File

@ -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 */

View File

@ -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 */
{""} {""}
}; };