Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/jmorris/linux-security

Pull security subsystem fixes from James Morris:
 "Two fixes for the security subsystem:

   - keys: split both rcu_dereference_key() and user_key_payload() into
     versions which can be called with or without holding the key
     semaphore.

   - SELinux: fix Android init(8) breakage due to new cgroup security
     labeling support when using older policy"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  selinux: wrap cgroup seclabel support with its own policy capability
  KEYS: Differentiate uses of rcu_dereference_key() and user_key_payload()
  • Loading branch information
torvalds committed Mar 2, 2017
2 parents 4f1f2b8 + 2651225 commit 0f221a3
Show file tree
Hide file tree
Showing 19 changed files with 55 additions and 26 deletions.
17 changes: 15 additions & 2 deletions Documentation/security/keys.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1151,8 +1151,21 @@ access the data:
usage. This is called key->payload.rcu_data0. The following accessors
wrap the RCU calls to this element:

rcu_assign_keypointer(struct key *key, void *data);
void *rcu_dereference_key(struct key *key);
(a) Set or change the first payload pointer:

rcu_assign_keypointer(struct key *key, void *data);

(b) Read the first payload pointer with the key semaphore held:

[const] void *dereference_key_locked([const] struct key *key);

Note that the return value will inherit its constness from the key
parameter. Static analysis will give an error if it things the lock
isn't held.

(c) Read the first payload pointer with the RCU read lock held:

const void *dereference_key_rcu(const struct key *key);


===================
Expand Down
2 changes: 1 addition & 1 deletion drivers/md/dm-crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1536,7 +1536,7 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string

down_read(&key->sem);

ukp = user_key_payload(key);
ukp = user_key_payload_locked(key);
if (!ukp) {
up_read(&key->sem);
key_put(key);
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2455,7 +2455,7 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
}

down_read(&key->sem);
upayload = user_key_payload(key);
upayload = user_key_payload_locked(key);
if (IS_ERR_OR_NULL(upayload)) {
rc = upayload ? PTR_ERR(upayload) : -EINVAL;
goto out_key_put;
Expand Down
2 changes: 1 addition & 1 deletion fs/crypto/keyinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ static int validate_user_key(struct fscrypt_info *crypt_info,
goto out;
}
down_read(&keyring_key->sem);
ukp = user_key_payload(keyring_key);
ukp = user_key_payload_locked(keyring_key);
if (ukp->datalen != sizeof(struct fscrypt_key)) {
res = -EINVAL;
up_read(&keyring_key->sem);
Expand Down
2 changes: 1 addition & 1 deletion fs/ecryptfs/ecryptfs_kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ ecryptfs_get_key_payload_data(struct key *key)

auth_tok = ecryptfs_get_encrypted_key_payload_data(key);
if (!auth_tok)
return (struct ecryptfs_auth_tok *)user_key_payload(key)->data;
return (struct ecryptfs_auth_tok *)user_key_payload_locked(key)->data;
else
return auth_tok;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/fscache/object-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ static void fscache_objlist_config(struct fscache_objlist_data *data)
config = 0;
rcu_read_lock();

confkey = user_key_payload(key);
confkey = user_key_payload_rcu(key);
buf = confkey->data;

for (len = confkey->datalen - 1; len >= 0; len--) {
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/nfs4idmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
if (ret < 0)
goto out_up;

payload = user_key_payload(rkey);
payload = user_key_payload_rcu(rkey);
if (IS_ERR_OR_NULL(payload)) {
ret = PTR_ERR(payload);
goto out_up;
Expand Down
9 changes: 7 additions & 2 deletions include/keys/user-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,14 @@ extern void user_describe(const struct key *user, struct seq_file *m);
extern long user_read(const struct key *key,
char __user *buffer, size_t buflen);

static inline const struct user_key_payload *user_key_payload(const struct key *key)
static inline const struct user_key_payload *user_key_payload_rcu(const struct key *key)
{
return (struct user_key_payload *)rcu_dereference_key(key);
return (struct user_key_payload *)dereference_key_rcu(key);
}

static inline struct user_key_payload *user_key_payload_locked(const struct key *key)
{
return (struct user_key_payload *)dereference_key_locked((struct key *)key);
}

#endif /* CONFIG_KEYS */
Expand Down
5 changes: 4 additions & 1 deletion include/linux/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,10 @@ static inline bool key_is_instantiated(const struct key *key)
!test_bit(KEY_FLAG_NEGATIVE, &key->flags);
}

#define rcu_dereference_key(KEY) \
#define dereference_key_rcu(KEY) \
(rcu_dereference((KEY)->payload.rcu_data0))

#define dereference_key_locked(KEY) \
(rcu_dereference_protected((KEY)->payload.rcu_data0, \
rwsem_is_locked(&((struct key *)(KEY))->sem)))

Expand Down
2 changes: 1 addition & 1 deletion lib/digsig.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ static int digsig_verify_rsa(struct key *key,
struct pubkey_hdr *pkh;

down_read(&key->sem);
ukp = user_key_payload(key);
ukp = user_key_payload_locked(key);

if (ukp->datalen < sizeof(*pkh))
goto err1;
Expand Down
4 changes: 2 additions & 2 deletions net/dns_resolver/dns_query.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ int dns_query(const char *type, const char *name, size_t namelen,
const char *options, char **_result, time64_t *_expiry)
{
struct key *rkey;
const struct user_key_payload *upayload;
struct user_key_payload *upayload;
const struct cred *saved_cred;
size_t typelen, desclen;
char *desc, *cp;
Expand Down Expand Up @@ -141,7 +141,7 @@ int dns_query(const char *type, const char *name, size_t namelen,
if (ret)
goto put;

upayload = user_key_payload(rkey);
upayload = user_key_payload_locked(rkey);
len = upayload->datalen;

ret = -ENOMEM;
Expand Down
2 changes: 1 addition & 1 deletion security/keys/dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ static ssize_t mpi_from_key(key_serial_t keyid, size_t maxlen, MPI *mpi)
if (status == 0) {
const struct user_key_payload *payload;

payload = user_key_payload(key);
payload = user_key_payload_locked(key);

if (maxlen == 0) {
*mpi = NULL;
Expand Down
4 changes: 2 additions & 2 deletions security/keys/encrypted-keys/encrypted.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ static struct key *request_user_key(const char *master_desc, const u8 **master_k
goto error;

down_read(&ukey->sem);
upayload = user_key_payload(ukey);
upayload = user_key_payload_locked(ukey);
*master_key = upayload->data;
*master_keylen = upayload->datalen;
error:
Expand Down Expand Up @@ -926,7 +926,7 @@ static long encrypted_read(const struct key *key, char __user *buffer,
size_t asciiblob_len;
int ret;

epayload = rcu_dereference_key(key);
epayload = dereference_key_locked(key);

/* returns the hex encoded iv, encrypted-data, and hmac as ascii */
asciiblob_len = epayload->datablob_len + ivsize + 1
Expand Down
4 changes: 2 additions & 2 deletions security/keys/trusted.c
Original file line number Diff line number Diff line change
Expand Up @@ -1140,12 +1140,12 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
static long trusted_read(const struct key *key, char __user *buffer,
size_t buflen)
{
struct trusted_key_payload *p;
const struct trusted_key_payload *p;
char *ascii_buf;
char *bufp;
int i;

p = rcu_dereference_key(key);
p = dereference_key_locked(key);
if (!p)
return -EINVAL;
if (!buffer || buflen <= 0)
Expand Down
6 changes: 3 additions & 3 deletions security/keys/user_defined.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ int user_update(struct key *key, struct key_preparsed_payload *prep)
/* attach the new data, displacing the old */
key->expiry = prep->expiry;
if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags))
zap = rcu_dereference_key(key);
zap = dereference_key_locked(key);
rcu_assign_keypointer(key, prep->payload.data[0]);
prep->payload.data[0] = NULL;

Expand All @@ -123,7 +123,7 @@ EXPORT_SYMBOL_GPL(user_update);
*/
void user_revoke(struct key *key)
{
struct user_key_payload *upayload = key->payload.data[0];
struct user_key_payload *upayload = user_key_payload_locked(key);

/* clear the quota */
key_payload_reserve(key, 0);
Expand Down Expand Up @@ -169,7 +169,7 @@ long user_read(const struct key *key, char __user *buffer, size_t buflen)
const struct user_key_payload *upayload;
long ret;

upayload = user_key_payload(key);
upayload = user_key_payload_locked(key);
ret = upayload->datalen;

/* we can return the data as is */
Expand Down
7 changes: 4 additions & 3 deletions security/selinux/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -480,12 +480,13 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
sbsec->behavior == SECURITY_FS_USE_NATIVE ||
/* Special handling. Genfs but also in-core setxattr handler */
!strcmp(sb->s_type->name, "sysfs") ||
!strcmp(sb->s_type->name, "cgroup") ||
!strcmp(sb->s_type->name, "cgroup2") ||
!strcmp(sb->s_type->name, "pstore") ||
!strcmp(sb->s_type->name, "debugfs") ||
!strcmp(sb->s_type->name, "tracefs") ||
!strcmp(sb->s_type->name, "rootfs");
!strcmp(sb->s_type->name, "rootfs") ||
(selinux_policycap_cgroupseclabel &&
(!strcmp(sb->s_type->name, "cgroup") ||
!strcmp(sb->s_type->name, "cgroup2")));
}

static int sb_finish_set_opts(struct super_block *sb)
Expand Down
2 changes: 2 additions & 0 deletions security/selinux/include/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ enum {
POLICYDB_CAPABILITY_OPENPERM,
POLICYDB_CAPABILITY_EXTSOCKCLASS,
POLICYDB_CAPABILITY_ALWAYSNETWORK,
POLICYDB_CAPABILITY_CGROUPSECLABEL,
__POLICYDB_CAPABILITY_MAX
};
#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
Expand All @@ -79,6 +80,7 @@ extern int selinux_policycap_netpeer;
extern int selinux_policycap_openperm;
extern int selinux_policycap_extsockclass;
extern int selinux_policycap_alwaysnetwork;
extern int selinux_policycap_cgroupseclabel;

/*
* type_datum properties
Expand Down
3 changes: 2 additions & 1 deletion security/selinux/selinuxfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ static char *policycap_names[] = {
"network_peer_controls",
"open_perms",
"extended_socket_class",
"always_check_network"
"always_check_network",
"cgroup_seclabel"
};

unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
Expand Down
4 changes: 4 additions & 0 deletions security/selinux/ss/services.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ int selinux_policycap_netpeer;
int selinux_policycap_openperm;
int selinux_policycap_extsockclass;
int selinux_policycap_alwaysnetwork;
int selinux_policycap_cgroupseclabel;

static DEFINE_RWLOCK(policy_rwlock);

Expand Down Expand Up @@ -1993,6 +1994,9 @@ static void security_load_policycaps(void)
POLICYDB_CAPABILITY_EXTSOCKCLASS);
selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps,
POLICYDB_CAPABILITY_ALWAYSNETWORK);
selinux_policycap_cgroupseclabel =
ebitmap_get_bit(&policydb.policycaps,
POLICYDB_CAPABILITY_CGROUPSECLABEL);
}

static int security_preserve_bools(struct policydb *p);
Expand Down

0 comments on commit 0f221a3

Please sign in to comment.