forked from Minki/linux
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (30 commits) MAINTAINERS: Add tomoyo-dev-en ML. SELinux: define permissions for DCB netlink messages encrypted-keys: style and other cleanup encrypted-keys: verify datablob size before converting to binary trusted-keys: kzalloc and other cleanup trusted-keys: additional TSS return code and other error handling syslog: check cap_syslog when dmesg_restrict Smack: Transmute labels on specified directories selinux: cache sidtab_context_to_sid results SELinux: do not compute transition labels on mountpoint labeled filesystems This patch adds a new security attribute to Smack called SMACK64EXEC. It defines label that is used while task is running. SELinux: merge policydb_index_classes and policydb_index_others selinux: convert part of the sym_val_to_name array to use flex_array selinux: convert type_val_to_struct to flex_array flex_array: fix flex_array_put_ptr macro to be valid C SELinux: do not set automatic i_ino in selinuxfs selinux: rework security_netlbl_secattr_to_sid SELinux: standardize return code handling in selinuxfs.c SELinux: standardize return code handling in selinuxfs.c SELinux: standardize return code handling in policydb.c ...
This commit is contained in:
commit
e0e736fc0d
145
Documentation/keys-trusted-encrypted.txt
Normal file
145
Documentation/keys-trusted-encrypted.txt
Normal file
@ -0,0 +1,145 @@
|
||||
Trusted and Encrypted Keys
|
||||
|
||||
Trusted and Encrypted Keys are two new key types added to the existing kernel
|
||||
key ring service. Both of these new types are variable length symmetic keys,
|
||||
and in both cases all keys are created in the kernel, and user space sees,
|
||||
stores, and loads only encrypted blobs. Trusted Keys require the availability
|
||||
of a Trusted Platform Module (TPM) chip for greater security, while Encrypted
|
||||
Keys can be used on any system. All user level blobs, are displayed and loaded
|
||||
in hex ascii for convenience, and are integrity verified.
|
||||
|
||||
Trusted Keys use a TPM both to generate and to seal the keys. Keys are sealed
|
||||
under a 2048 bit RSA key in the TPM, and optionally sealed to specified PCR
|
||||
(integrity measurement) values, and only unsealed by the TPM, if PCRs and blob
|
||||
integrity verifications match. A loaded Trusted Key can be updated with new
|
||||
(future) PCR values, so keys are easily migrated to new pcr values, such as
|
||||
when the kernel and initramfs are updated. The same key can have many saved
|
||||
blobs under different PCR values, so multiple boots are easily supported.
|
||||
|
||||
By default, trusted keys are sealed under the SRK, which has the default
|
||||
authorization value (20 zeros). This can be set at takeownership time with the
|
||||
trouser's utility: "tpm_takeownership -u -z".
|
||||
|
||||
Usage:
|
||||
keyctl add trusted name "new keylen [options]" ring
|
||||
keyctl add trusted name "load hex_blob [pcrlock=pcrnum]" ring
|
||||
keyctl update key "update [options]"
|
||||
keyctl print keyid
|
||||
|
||||
options:
|
||||
keyhandle= ascii hex value of sealing key default 0x40000000 (SRK)
|
||||
keyauth= ascii hex auth for sealing key default 0x00...i
|
||||
(40 ascii zeros)
|
||||
blobauth= ascii hex auth for sealed data default 0x00...
|
||||
(40 ascii zeros)
|
||||
blobauth= ascii hex auth for sealed data default 0x00...
|
||||
(40 ascii zeros)
|
||||
pcrinfo= ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
|
||||
pcrlock= pcr number to be extended to "lock" blob
|
||||
migratable= 0|1 indicating permission to reseal to new PCR values,
|
||||
default 1 (resealing allowed)
|
||||
|
||||
"keyctl print" returns an ascii hex copy of the sealed key, which is in standard
|
||||
TPM_STORED_DATA format. The key length for new keys are always in bytes.
|
||||
Trusted Keys can be 32 - 128 bytes (256 - 1024 bits), the upper limit is to fit
|
||||
within the 2048 bit SRK (RSA) keylength, with all necessary structure/padding.
|
||||
|
||||
Encrypted keys do not depend on a TPM, and are faster, as they use AES for
|
||||
encryption/decryption. New keys are created from kernel generated random
|
||||
numbers, and are encrypted/decrypted using a specified 'master' key. The
|
||||
'master' key can either be a trusted-key or user-key type. The main
|
||||
disadvantage of encrypted keys is that if they are not rooted in a trusted key,
|
||||
they are only as secure as the user key encrypting them. The master user key
|
||||
should therefore be loaded in as secure a way as possible, preferably early in
|
||||
boot.
|
||||
|
||||
Usage:
|
||||
keyctl add encrypted name "new key-type:master-key-name keylen" ring
|
||||
keyctl add encrypted name "load hex_blob" ring
|
||||
keyctl update keyid "update key-type:master-key-name"
|
||||
|
||||
where 'key-type' is either 'trusted' or 'user'.
|
||||
|
||||
Examples of trusted and encrypted key usage:
|
||||
|
||||
Create and save a trusted key named "kmk" of length 32 bytes:
|
||||
|
||||
$ keyctl add trusted kmk "new 32" @u
|
||||
440502848
|
||||
|
||||
$ keyctl show
|
||||
Session Keyring
|
||||
-3 --alswrv 500 500 keyring: _ses
|
||||
97833714 --alswrv 500 -1 \_ keyring: _uid.500
|
||||
440502848 --alswrv 500 500 \_ trusted: kmk
|
||||
|
||||
$ keyctl print 440502848
|
||||
0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
|
||||
3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
|
||||
27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
|
||||
a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
|
||||
d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
|
||||
dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
|
||||
f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
|
||||
e4a8aea2b607ec96931e6f4d4fe563ba
|
||||
|
||||
$ keyctl pipe 440502848 > kmk.blob
|
||||
|
||||
Load a trusted key from the saved blob:
|
||||
|
||||
$ keyctl add trusted kmk "load `cat kmk.blob`" @u
|
||||
268728824
|
||||
|
||||
$ keyctl print 268728824
|
||||
0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
|
||||
3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
|
||||
27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
|
||||
a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
|
||||
d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
|
||||
dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
|
||||
f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
|
||||
e4a8aea2b607ec96931e6f4d4fe563ba
|
||||
|
||||
Reseal a trusted key under new pcr values:
|
||||
|
||||
$ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`"
|
||||
$ keyctl print 268728824
|
||||
010100000000002c0002800093c35a09b70fff26e7a98ae786c641e678ec6ffb6b46d805
|
||||
77c8a6377aed9d3219c6dfec4b23ffe3000001005d37d472ac8a44023fbb3d18583a4f73
|
||||
d3a076c0858f6f1dcaa39ea0f119911ff03f5406df4f7f27f41da8d7194f45c9f4e00f2e
|
||||
df449f266253aa3f52e55c53de147773e00f0f9aca86c64d94c95382265968c354c5eab4
|
||||
9638c5ae99c89de1e0997242edfb0b501744e11ff9762dfd951cffd93227cc513384e7e6
|
||||
e782c29435c7ec2edafaa2f4c1fe6e7a781b59549ff5296371b42133777dcc5b8b971610
|
||||
94bc67ede19e43ddb9dc2baacad374a36feaf0314d700af0a65c164b7082401740e489c9
|
||||
7ef6a24defe4846104209bf0c3eced7fa1a672ed5b125fc9d8cd88b476a658a4434644ef
|
||||
df8ae9a178e9f83ba9f08d10fa47e4226b98b0702f06b3b8
|
||||
|
||||
Create and save an encrypted key "evm" using the above trusted key "kmk":
|
||||
|
||||
$ keyctl add encrypted evm "new trusted:kmk 32" @u
|
||||
159771175
|
||||
|
||||
$ keyctl print 159771175
|
||||
trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b382dbbc55
|
||||
be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e024717c64
|
||||
5972dcb82ab2dde83376d82b2e3c09ffc
|
||||
|
||||
$ keyctl pipe 159771175 > evm.blob
|
||||
|
||||
Load an encrypted key "evm" from saved blob:
|
||||
|
||||
$ keyctl add encrypted evm "load `cat evm.blob`" @u
|
||||
831684262
|
||||
|
||||
$ keyctl print 831684262
|
||||
trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b382dbbc55
|
||||
be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e024717c64
|
||||
5972dcb82ab2dde83376d82b2e3c09ffc
|
||||
|
||||
|
||||
The initial consumer of trusted keys is EVM, which at boot time needs a high
|
||||
quality symmetric key for HMAC protection of file metadata. The use of a
|
||||
trusted key provides strong guarantees that the EVM key has not been
|
||||
compromised by a user level problem, and when sealed to specific boot PCR
|
||||
values, protects against boot and offline attacks. Other uses for trusted and
|
||||
encrypted keys, such as for disk and file encryption are anticipated.
|
@ -219,7 +219,7 @@ dmesg_restrict:
|
||||
This toggle indicates whether unprivileged users are prevented from using
|
||||
dmesg(8) to view messages from the kernel's log buffer. When
|
||||
dmesg_restrict is set to (0) there are no restrictions. When
|
||||
dmesg_restrict is set set to (1), users must have CAP_SYS_ADMIN to use
|
||||
dmesg_restrict is set set to (1), users must have CAP_SYSLOG to use
|
||||
dmesg(8).
|
||||
|
||||
The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the default
|
||||
|
@ -5930,7 +5930,8 @@ F: drivers/net/tlan.*
|
||||
TOMOYO SECURITY MODULE
|
||||
M: Kentaro Takeda <takedakn@nttdata.co.jp>
|
||||
M: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
|
||||
L: tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for developers and users in English)
|
||||
L: tomoyo-dev-en@lists.sourceforge.jp (subscribers-only, for developers in English)
|
||||
L: tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for users in English)
|
||||
L: tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
|
||||
L: tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
|
||||
W: http://tomoyo.sourceforge.jp/
|
||||
|
@ -736,7 +736,7 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
|
||||
if (chip == NULL)
|
||||
return -ENODEV;
|
||||
rc = __tpm_pcr_read(chip, pcr_idx, res_buf);
|
||||
module_put(chip->dev->driver->owner);
|
||||
tpm_chip_put(chip);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_pcr_read);
|
||||
@ -775,11 +775,27 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
|
||||
rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
|
||||
"attempting extend a PCR value");
|
||||
|
||||
module_put(chip->dev->driver->owner);
|
||||
tpm_chip_put(chip);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_pcr_extend);
|
||||
|
||||
int tpm_send(u32 chip_num, void *cmd, size_t buflen)
|
||||
{
|
||||
struct tpm_chip *chip;
|
||||
int rc;
|
||||
|
||||
chip = tpm_chip_find_get(chip_num);
|
||||
if (chip == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
|
||||
|
||||
tpm_chip_put(chip);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_send);
|
||||
|
||||
ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
|
@ -113,6 +113,11 @@ struct tpm_chip {
|
||||
|
||||
#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
|
||||
|
||||
static inline void tpm_chip_put(struct tpm_chip *chip)
|
||||
{
|
||||
module_put(chip->dev->driver->owner);
|
||||
}
|
||||
|
||||
static inline int tpm_read_index(int base, int index)
|
||||
{
|
||||
outb(index, base);
|
||||
|
29
include/keys/encrypted-type.h
Normal file
29
include/keys/encrypted-type.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2010 IBM Corporation
|
||||
* Author: Mimi Zohar <zohar@us.ibm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 of the License.
|
||||
*/
|
||||
|
||||
#ifndef _KEYS_ENCRYPTED_TYPE_H
|
||||
#define _KEYS_ENCRYPTED_TYPE_H
|
||||
|
||||
#include <linux/key.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
struct encrypted_key_payload {
|
||||
struct rcu_head rcu;
|
||||
char *master_desc; /* datablob: master key name */
|
||||
char *datalen; /* datablob: decrypted key length */
|
||||
u8 *iv; /* datablob: iv */
|
||||
u8 *encrypted_data; /* datablob: encrypted data */
|
||||
unsigned short datablob_len; /* length of datablob */
|
||||
unsigned short decrypted_datalen; /* decrypted data length */
|
||||
u8 decrypted_data[0]; /* decrypted data + datablob + hmac */
|
||||
};
|
||||
|
||||
extern struct key_type key_type_encrypted;
|
||||
|
||||
#endif /* _KEYS_ENCRYPTED_TYPE_H */
|
31
include/keys/trusted-type.h
Normal file
31
include/keys/trusted-type.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2010 IBM Corporation
|
||||
* Author: David Safford <safford@us.ibm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 of the License.
|
||||
*/
|
||||
|
||||
#ifndef _KEYS_TRUSTED_TYPE_H
|
||||
#define _KEYS_TRUSTED_TYPE_H
|
||||
|
||||
#include <linux/key.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
#define MIN_KEY_SIZE 32
|
||||
#define MAX_KEY_SIZE 128
|
||||
#define MAX_BLOB_SIZE 320
|
||||
|
||||
struct trusted_key_payload {
|
||||
struct rcu_head rcu;
|
||||
unsigned int key_len;
|
||||
unsigned int blob_len;
|
||||
unsigned char migratable;
|
||||
unsigned char key[MAX_KEY_SIZE + 1];
|
||||
unsigned char blob[MAX_BLOB_SIZE];
|
||||
};
|
||||
|
||||
extern struct key_type key_type_trusted;
|
||||
|
||||
#endif /* _KEYS_TRUSTED_TYPE_H */
|
@ -246,7 +246,6 @@ struct cpu_vfs_cap_data {
|
||||
/* Allow configuration of the secure attention key */
|
||||
/* Allow administration of the random device */
|
||||
/* Allow examination and configuration of disk quotas */
|
||||
/* Allow configuring the kernel's syslog (printk behaviour) */
|
||||
/* Allow setting the domainname */
|
||||
/* Allow setting the hostname */
|
||||
/* Allow calling bdflush() */
|
||||
@ -352,7 +351,11 @@ struct cpu_vfs_cap_data {
|
||||
|
||||
#define CAP_MAC_ADMIN 33
|
||||
|
||||
#define CAP_LAST_CAP CAP_MAC_ADMIN
|
||||
/* Allow configuring the kernel's syslog (printk behaviour) */
|
||||
|
||||
#define CAP_SYSLOG 34
|
||||
|
||||
#define CAP_LAST_CAP CAP_SYSLOG
|
||||
|
||||
#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
|
||||
|
||||
|
@ -71,7 +71,7 @@ void *flex_array_get(struct flex_array *fa, unsigned int element_nr);
|
||||
int flex_array_shrink(struct flex_array *fa);
|
||||
|
||||
#define flex_array_put_ptr(fa, nr, src, gfp) \
|
||||
flex_array_put(fa, nr, &(void *)(src), gfp)
|
||||
flex_array_put(fa, nr, (void *)&(src), gfp)
|
||||
|
||||
void *flex_array_get_ptr(struct flex_array *fa, unsigned int element_nr);
|
||||
|
||||
|
@ -56,6 +56,8 @@
|
||||
|
||||
#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
|
||||
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
|
||||
|
||||
/* The `const' in roundup() prevents gcc-3.3 from calling __divdi3 */
|
||||
#define roundup(x, y) ( \
|
||||
{ \
|
||||
const typeof(y) __y = y; \
|
||||
@ -263,6 +265,7 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
|
||||
}
|
||||
|
||||
extern int hex_to_bin(char ch);
|
||||
extern void hex2bin(u8 *dst, const char *src, size_t count);
|
||||
|
||||
/*
|
||||
* General tracing related utility functions - trace_printk(),
|
||||
|
@ -1058,8 +1058,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
||||
* @cred points to the credentials to provide the context against which to
|
||||
* evaluate the security data on the key.
|
||||
* @perm describes the combination of permissions required of this key.
|
||||
* Return 1 if permission granted, 0 if permission denied and -ve it the
|
||||
* normal permissions model should be effected.
|
||||
* Return 0 if permission is granted, -ve error otherwise.
|
||||
* @key_getsecurity:
|
||||
* Get a textual representation of the security context attached to a key
|
||||
* for the purposes of honouring KEYCTL_GETSECURITY. This function
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
|
||||
extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
|
||||
extern int tpm_send(u32 chip_num, void *cmd, size_t buflen);
|
||||
#else
|
||||
static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) {
|
||||
return -ENODEV;
|
||||
@ -38,5 +39,8 @@ static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) {
|
||||
static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) {
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) {
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
28
include/linux/tpm_command.h
Normal file
28
include/linux/tpm_command.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef __LINUX_TPM_COMMAND_H__
|
||||
#define __LINUX_TPM_COMMAND_H__
|
||||
|
||||
/*
|
||||
* TPM Command constants from specifications at
|
||||
* http://www.trustedcomputinggroup.org
|
||||
*/
|
||||
|
||||
/* Command TAGS */
|
||||
#define TPM_TAG_RQU_COMMAND 193
|
||||
#define TPM_TAG_RQU_AUTH1_COMMAND 194
|
||||
#define TPM_TAG_RQU_AUTH2_COMMAND 195
|
||||
#define TPM_TAG_RSP_COMMAND 196
|
||||
#define TPM_TAG_RSP_AUTH1_COMMAND 197
|
||||
#define TPM_TAG_RSP_AUTH2_COMMAND 198
|
||||
|
||||
/* Command Ordinals */
|
||||
#define TPM_ORD_GETRANDOM 70
|
||||
#define TPM_ORD_OSAP 11
|
||||
#define TPM_ORD_OIAP 10
|
||||
#define TPM_ORD_SEAL 23
|
||||
#define TPM_ORD_UNSEAL 24
|
||||
|
||||
/* Other constants */
|
||||
#define SRKHANDLE 0x40000000
|
||||
#define TPM_NONCE_SIZE 20
|
||||
|
||||
#endif
|
@ -40,9 +40,13 @@
|
||||
#define XATTR_SMACK_SUFFIX "SMACK64"
|
||||
#define XATTR_SMACK_IPIN "SMACK64IPIN"
|
||||
#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
|
||||
#define XATTR_SMACK_EXEC "SMACK64EXEC"
|
||||
#define XATTR_SMACK_TRANSMUTE "SMACK64TRANSMUTE"
|
||||
#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
|
||||
#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
|
||||
#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
|
||||
#define XATTR_NAME_SMACKEXEC XATTR_SECURITY_PREFIX XATTR_SMACK_EXEC
|
||||
#define XATTR_NAME_SMACKTRANSMUTE XATTR_SECURITY_PREFIX XATTR_SMACK_TRANSMUTE
|
||||
|
||||
#define XATTR_CAPS_SUFFIX "capability"
|
||||
#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
|
||||
|
@ -273,12 +273,12 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
|
||||
* at open time.
|
||||
*/
|
||||
if (type == SYSLOG_ACTION_OPEN || !from_file) {
|
||||
if (dmesg_restrict && !capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
if (dmesg_restrict && !capable(CAP_SYSLOG))
|
||||
goto warn; /* switch to return -EPERM after 2.6.39 */
|
||||
if ((type != SYSLOG_ACTION_READ_ALL &&
|
||||
type != SYSLOG_ACTION_SIZE_BUFFER) &&
|
||||
!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
!capable(CAP_SYSLOG))
|
||||
goto warn; /* switch to return -EPERM after 2.6.39 */
|
||||
}
|
||||
|
||||
error = security_syslog(type);
|
||||
@ -422,6 +422,12 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
|
||||
}
|
||||
out:
|
||||
return error;
|
||||
warn:
|
||||
/* remove after 2.6.39 */
|
||||
if (capable(CAP_SYS_ADMIN))
|
||||
WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN "
|
||||
"but no CAP_SYSLOG (deprecated and denied).\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
|
||||
|
@ -33,6 +33,22 @@ int hex_to_bin(char ch)
|
||||
}
|
||||
EXPORT_SYMBOL(hex_to_bin);
|
||||
|
||||
/**
|
||||
* hex2bin - convert an ascii hexadecimal string to its binary representation
|
||||
* @dst: binary result
|
||||
* @src: ascii hexadecimal string
|
||||
* @count: result length
|
||||
*/
|
||||
void hex2bin(u8 *dst, const char *src, size_t count)
|
||||
{
|
||||
while (count--) {
|
||||
*dst = hex_to_bin(*src++) << 4;
|
||||
*dst += hex_to_bin(*src++);
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(hex2bin);
|
||||
|
||||
/**
|
||||
* hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
|
||||
* @buf: data blob to dump
|
||||
|
@ -21,6 +21,37 @@ config KEYS
|
||||
|
||||
If you are unsure as to whether this is required, answer N.
|
||||
|
||||
config TRUSTED_KEYS
|
||||
tristate "TRUSTED KEYS"
|
||||
depends on KEYS && TCG_TPM
|
||||
select CRYPTO
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_SHA1
|
||||
help
|
||||
This option provides support for creating, sealing, and unsealing
|
||||
keys in the kernel. Trusted keys are random number symmetric keys,
|
||||
generated and RSA-sealed by the TPM. The TPM only unseals the keys,
|
||||
if the boot PCRs and other criteria match. Userspace will only ever
|
||||
see encrypted blobs.
|
||||
|
||||
If you are unsure as to whether this is required, answer N.
|
||||
|
||||
config ENCRYPTED_KEYS
|
||||
tristate "ENCRYPTED KEYS"
|
||||
depends on KEYS && TRUSTED_KEYS
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_CBC
|
||||
select CRYPTO_SHA256
|
||||
select CRYPTO_RNG
|
||||
help
|
||||
This option provides support for create/encrypting/decrypting keys
|
||||
in the kernel. Encrypted keys are kernel generated random numbers,
|
||||
which are encrypted/decrypted with a 'master' symmetric key. The
|
||||
'master' key can be either a trusted-key or user-key type.
|
||||
Userspace only ever sees/stores encrypted blobs.
|
||||
|
||||
If you are unsure as to whether this is required, answer N.
|
||||
|
||||
config KEYS_DEBUG_PROC_KEYS
|
||||
bool "Enable the /proc/keys file by which keys may be viewed"
|
||||
depends on KEYS
|
||||
|
@ -13,6 +13,8 @@ obj-y := \
|
||||
request_key_auth.o \
|
||||
user_defined.o
|
||||
|
||||
obj-$(CONFIG_TRUSTED_KEYS) += trusted_defined.o
|
||||
obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted_defined.o
|
||||
obj-$(CONFIG_KEYS_COMPAT) += compat.o
|
||||
obj-$(CONFIG_PROC_FS) += proc.o
|
||||
obj-$(CONFIG_SYSCTL) += sysctl.o
|
||||
|
903
security/keys/encrypted_defined.c
Normal file
903
security/keys/encrypted_defined.c
Normal file
@ -0,0 +1,903 @@
|
||||
/*
|
||||
* Copyright (C) 2010 IBM Corporation
|
||||
*
|
||||
* Author:
|
||||
* Mimi Zohar <zohar@us.ibm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 of the License.
|
||||
*
|
||||
* See Documentation/keys-trusted-encrypted.txt
|
||||
*/
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/parser.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/err.h>
|
||||
#include <keys/user-type.h>
|
||||
#include <keys/trusted-type.h>
|
||||
#include <keys/encrypted-type.h>
|
||||
#include <linux/key-type.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/sha.h>
|
||||
#include <crypto/aes.h>
|
||||
|
||||
#include "encrypted_defined.h"
|
||||
|
||||
static const char KEY_TRUSTED_PREFIX[] = "trusted:";
|
||||
static const char KEY_USER_PREFIX[] = "user:";
|
||||
static const char hash_alg[] = "sha256";
|
||||
static const char hmac_alg[] = "hmac(sha256)";
|
||||
static const char blkcipher_alg[] = "cbc(aes)";
|
||||
static unsigned int ivsize;
|
||||
static int blksize;
|
||||
|
||||
#define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1)
|
||||
#define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1)
|
||||
#define HASH_SIZE SHA256_DIGEST_SIZE
|
||||
#define MAX_DATA_SIZE 4096
|
||||
#define MIN_DATA_SIZE 20
|
||||
|
||||
struct sdesc {
|
||||
struct shash_desc shash;
|
||||
char ctx[];
|
||||
};
|
||||
|
||||
static struct crypto_shash *hashalg;
|
||||
static struct crypto_shash *hmacalg;
|
||||
|
||||
enum {
|
||||
Opt_err = -1, Opt_new, Opt_load, Opt_update
|
||||
};
|
||||
|
||||
static const match_table_t key_tokens = {
|
||||
{Opt_new, "new"},
|
||||
{Opt_load, "load"},
|
||||
{Opt_update, "update"},
|
||||
{Opt_err, NULL}
|
||||
};
|
||||
|
||||
static int aes_get_sizes(void)
|
||||
{
|
||||
struct crypto_blkcipher *tfm;
|
||||
|
||||
tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm)) {
|
||||
pr_err("encrypted_key: failed to alloc_cipher (%ld)\n",
|
||||
PTR_ERR(tfm));
|
||||
return PTR_ERR(tfm);
|
||||
}
|
||||
ivsize = crypto_blkcipher_ivsize(tfm);
|
||||
blksize = crypto_blkcipher_blocksize(tfm);
|
||||
crypto_free_blkcipher(tfm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* valid_master_desc - verify the 'key-type:desc' of a new/updated master-key
|
||||
*
|
||||
* key-type:= "trusted:" | "encrypted:"
|
||||
* desc:= master-key description
|
||||
*
|
||||
* Verify that 'key-type' is valid and that 'desc' exists. On key update,
|
||||
* only the master key description is permitted to change, not the key-type.
|
||||
* The key-type remains constant.
|
||||
*
|
||||
* On success returns 0, otherwise -EINVAL.
|
||||
*/
|
||||
static int valid_master_desc(const char *new_desc, const char *orig_desc)
|
||||
{
|
||||
if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) {
|
||||
if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN)
|
||||
goto out;
|
||||
if (orig_desc)
|
||||
if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN))
|
||||
goto out;
|
||||
} else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) {
|
||||
if (strlen(new_desc) == KEY_USER_PREFIX_LEN)
|
||||
goto out;
|
||||
if (orig_desc)
|
||||
if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN))
|
||||
goto out;
|
||||
} else
|
||||
goto out;
|
||||
return 0;
|
||||
out:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* datablob_parse - parse the keyctl data
|
||||
*
|
||||
* datablob format:
|
||||
* new <master-key name> <decrypted data length>
|
||||
* load <master-key name> <decrypted data length> <encrypted iv + data>
|
||||
* update <new-master-key name>
|
||||
*
|
||||
* Tokenizes a copy of the keyctl data, returning a pointer to each token,
|
||||
* which is null terminated.
|
||||
*
|
||||
* On success returns 0, otherwise -EINVAL.
|
||||
*/
|
||||
static int datablob_parse(char *datablob, char **master_desc,
|
||||
char **decrypted_datalen, char **hex_encoded_iv)
|
||||
{
|
||||
substring_t args[MAX_OPT_ARGS];
|
||||
int ret = -EINVAL;
|
||||
int key_cmd;
|
||||
char *p;
|
||||
|
||||
p = strsep(&datablob, " \t");
|
||||
if (!p)
|
||||
return ret;
|
||||
key_cmd = match_token(p, key_tokens, args);
|
||||
|
||||
*master_desc = strsep(&datablob, " \t");
|
||||
if (!*master_desc)
|
||||
goto out;
|
||||
|
||||
if (valid_master_desc(*master_desc, NULL) < 0)
|
||||
goto out;
|
||||
|
||||
if (decrypted_datalen) {
|
||||
*decrypted_datalen = strsep(&datablob, " \t");
|
||||
if (!*decrypted_datalen)
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (key_cmd) {
|
||||
case Opt_new:
|
||||
if (!decrypted_datalen)
|
||||
break;
|
||||
ret = 0;
|
||||
break;
|
||||
case Opt_load:
|
||||
if (!decrypted_datalen)
|
||||
break;
|
||||
*hex_encoded_iv = strsep(&datablob, " \t");
|
||||
if (!*hex_encoded_iv)
|
||||
break;
|
||||
ret = 0;
|
||||
break;
|
||||
case Opt_update:
|
||||
if (decrypted_datalen)
|
||||
break;
|
||||
ret = 0;
|
||||
break;
|
||||
case Opt_err:
|
||||
break;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* datablob_format - format as an ascii string, before copying to userspace
|
||||
*/
|
||||
static char *datablob_format(struct encrypted_key_payload *epayload,
|
||||
size_t asciiblob_len)
|
||||
{
|
||||
char *ascii_buf, *bufp;
|
||||
u8 *iv = epayload->iv;
|
||||
int len;
|
||||
int i;
|
||||
|
||||
ascii_buf = kmalloc(asciiblob_len + 1, GFP_KERNEL);
|
||||
if (!ascii_buf)
|
||||
goto out;
|
||||
|
||||
ascii_buf[asciiblob_len] = '\0';
|
||||
|
||||
/* copy datablob master_desc and datalen strings */
|
||||
len = sprintf(ascii_buf, "%s %s ", epayload->master_desc,
|
||||
epayload->datalen);
|
||||
|
||||
/* convert the hex encoded iv, encrypted-data and HMAC to ascii */
|
||||
bufp = &ascii_buf[len];
|
||||
for (i = 0; i < (asciiblob_len - len) / 2; i++)
|
||||
bufp = pack_hex_byte(bufp, iv[i]);
|
||||
out:
|
||||
return ascii_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* request_trusted_key - request the trusted key
|
||||
*
|
||||
* Trusted keys are sealed to PCRs and other metadata. Although userspace
|
||||
* manages both trusted/encrypted key-types, like the encrypted key type
|
||||
* data, trusted key type data is not visible decrypted from userspace.
|
||||
*/
|
||||
static struct key *request_trusted_key(const char *trusted_desc,
|
||||
u8 **master_key, size_t *master_keylen)
|
||||
{
|
||||
struct trusted_key_payload *tpayload;
|
||||
struct key *tkey;
|
||||
|
||||
tkey = request_key(&key_type_trusted, trusted_desc, NULL);
|
||||
if (IS_ERR(tkey))
|
||||
goto error;
|
||||
|
||||
down_read(&tkey->sem);
|
||||
tpayload = rcu_dereference(tkey->payload.data);
|
||||
*master_key = tpayload->key;
|
||||
*master_keylen = tpayload->key_len;
|
||||
error:
|
||||
return tkey;
|
||||
}
|
||||
|
||||
/*
|
||||
* request_user_key - request the user key
|
||||
*
|
||||
* Use a user provided key to encrypt/decrypt an encrypted-key.
|
||||
*/
|
||||
static struct key *request_user_key(const char *master_desc, u8 **master_key,
|
||||
size_t *master_keylen)
|
||||
{
|
||||
struct user_key_payload *upayload;
|
||||
struct key *ukey;
|
||||
|
||||
ukey = request_key(&key_type_user, master_desc, NULL);
|
||||
if (IS_ERR(ukey))
|
||||
goto error;
|
||||
|
||||
down_read(&ukey->sem);
|
||||
upayload = rcu_dereference(ukey->payload.data);
|
||||
*master_key = upayload->data;
|
||||
*master_keylen = upayload->datalen;
|
||||
error:
|
||||
return ukey;
|
||||
}
|
||||
|
||||
static struct sdesc *alloc_sdesc(struct crypto_shash *alg)
|
||||
{
|
||||
struct sdesc *sdesc;
|
||||
int size;
|
||||
|
||||
size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
|
||||
sdesc = kmalloc(size, GFP_KERNEL);
|
||||
if (!sdesc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
sdesc->shash.tfm = alg;
|
||||
sdesc->shash.flags = 0x0;
|
||||
return sdesc;
|
||||
}
|
||||
|
||||
static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen,
|
||||
const u8 *buf, unsigned int buflen)
|
||||
{
|
||||
struct sdesc *sdesc;
|
||||
int ret;
|
||||
|
||||
sdesc = alloc_sdesc(hmacalg);
|
||||
if (IS_ERR(sdesc)) {
|
||||
pr_info("encrypted_key: can't alloc %s\n", hmac_alg);
|
||||
return PTR_ERR(sdesc);
|
||||
}
|
||||
|
||||
ret = crypto_shash_setkey(hmacalg, key, keylen);
|
||||
if (!ret)
|
||||
ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
|
||||
kfree(sdesc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int calc_hash(u8 *digest, const u8 *buf, unsigned int buflen)
|
||||
{
|
||||
struct sdesc *sdesc;
|
||||
int ret;
|
||||
|
||||
sdesc = alloc_sdesc(hashalg);
|
||||
if (IS_ERR(sdesc)) {
|
||||
pr_info("encrypted_key: can't alloc %s\n", hash_alg);
|
||||
return PTR_ERR(sdesc);
|
||||
}
|
||||
|
||||
ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
|
||||
kfree(sdesc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum derived_key_type { ENC_KEY, AUTH_KEY };
|
||||
|
||||
/* Derive authentication/encryption key from trusted key */
|
||||
static int get_derived_key(u8 *derived_key, enum derived_key_type key_type,
|
||||
const u8 *master_key, size_t master_keylen)
|
||||
{
|
||||
u8 *derived_buf;
|
||||
unsigned int derived_buf_len;
|
||||
int ret;
|
||||
|
||||
derived_buf_len = strlen("AUTH_KEY") + 1 + master_keylen;
|
||||
if (derived_buf_len < HASH_SIZE)
|
||||
derived_buf_len = HASH_SIZE;
|
||||
|
||||
derived_buf = kzalloc(derived_buf_len, GFP_KERNEL);
|
||||
if (!derived_buf) {
|
||||
pr_err("encrypted_key: out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (key_type)
|
||||
strcpy(derived_buf, "AUTH_KEY");
|
||||
else
|
||||
strcpy(derived_buf, "ENC_KEY");
|
||||
|
||||
memcpy(derived_buf + strlen(derived_buf) + 1, master_key,
|
||||
master_keylen);
|
||||
ret = calc_hash(derived_key, derived_buf, derived_buf_len);
|
||||
kfree(derived_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key,
|
||||
unsigned int key_len, const u8 *iv,
|
||||
unsigned int ivsize)
|
||||
{
|
||||
int ret;
|
||||
|
||||
desc->tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(desc->tfm)) {
|
||||
pr_err("encrypted_key: failed to load %s transform (%ld)\n",
|
||||
blkcipher_alg, PTR_ERR(desc->tfm));
|
||||
return PTR_ERR(desc->tfm);
|
||||
}
|
||||
desc->flags = 0;
|
||||
|
||||
ret = crypto_blkcipher_setkey(desc->tfm, key, key_len);
|
||||
if (ret < 0) {
|
||||
pr_err("encrypted_key: failed to setkey (%d)\n", ret);
|
||||
crypto_free_blkcipher(desc->tfm);
|
||||
return ret;
|
||||
}
|
||||
crypto_blkcipher_set_iv(desc->tfm, iv, ivsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct key *request_master_key(struct encrypted_key_payload *epayload,
|
||||
u8 **master_key, size_t *master_keylen)
|
||||
{
|
||||
struct key *mkey = NULL;
|
||||
|
||||
if (!strncmp(epayload->master_desc, KEY_TRUSTED_PREFIX,
|
||||
KEY_TRUSTED_PREFIX_LEN)) {
|
||||
mkey = request_trusted_key(epayload->master_desc +
|
||||
KEY_TRUSTED_PREFIX_LEN,
|
||||
master_key, master_keylen);
|
||||
} else if (!strncmp(epayload->master_desc, KEY_USER_PREFIX,
|
||||
KEY_USER_PREFIX_LEN)) {
|
||||
mkey = request_user_key(epayload->master_desc +
|
||||
KEY_USER_PREFIX_LEN,
|
||||
master_key, master_keylen);
|
||||
} else
|
||||
goto out;
|
||||
|
||||
if (IS_ERR(mkey))
|
||||
pr_info("encrypted_key: key %s not found",
|
||||
epayload->master_desc);
|
||||
if (mkey)
|
||||
dump_master_key(*master_key, *master_keylen);
|
||||
out:
|
||||
return mkey;
|
||||
}
|
||||
|
||||
/* Before returning data to userspace, encrypt decrypted data. */
|
||||
static int derived_key_encrypt(struct encrypted_key_payload *epayload,
|
||||
const u8 *derived_key,
|
||||
unsigned int derived_keylen)
|
||||
{
|
||||
struct scatterlist sg_in[2];
|
||||
struct scatterlist sg_out[1];
|
||||
struct blkcipher_desc desc;
|
||||
unsigned int encrypted_datalen;
|
||||
unsigned int padlen;
|
||||
char pad[16];
|
||||
int ret;
|
||||
|
||||
encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
|
||||
padlen = encrypted_datalen - epayload->decrypted_datalen;
|
||||
|
||||
ret = init_blkcipher_desc(&desc, derived_key, derived_keylen,
|
||||
epayload->iv, ivsize);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
dump_decrypted_data(epayload);
|
||||
|
||||
memset(pad, 0, sizeof pad);
|
||||
sg_init_table(sg_in, 2);
|
||||
sg_set_buf(&sg_in[0], epayload->decrypted_data,
|
||||
epayload->decrypted_datalen);
|
||||
sg_set_buf(&sg_in[1], pad, padlen);
|
||||
|
||||
sg_init_table(sg_out, 1);
|
||||
sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen);
|
||||
|
||||
ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, encrypted_datalen);
|
||||
crypto_free_blkcipher(desc.tfm);
|
||||
if (ret < 0)
|
||||
pr_err("encrypted_key: failed to encrypt (%d)\n", ret);
|
||||
else
|
||||
dump_encrypted_data(epayload, encrypted_datalen);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int datablob_hmac_append(struct encrypted_key_payload *epayload,
|
||||
const u8 *master_key, size_t master_keylen)
|
||||
{
|
||||
u8 derived_key[HASH_SIZE];
|
||||
u8 *digest;
|
||||
int ret;
|
||||
|
||||
ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
digest = epayload->master_desc + epayload->datablob_len;
|
||||
ret = calc_hmac(digest, derived_key, sizeof derived_key,
|
||||
epayload->master_desc, epayload->datablob_len);
|
||||
if (!ret)
|
||||
dump_hmac(NULL, digest, HASH_SIZE);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* verify HMAC before decrypting encrypted key */
|
||||
static int datablob_hmac_verify(struct encrypted_key_payload *epayload,
|
||||
const u8 *master_key, size_t master_keylen)
|
||||
{
|
||||
u8 derived_key[HASH_SIZE];
|
||||
u8 digest[HASH_SIZE];
|
||||
int ret;
|
||||
|
||||
ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = calc_hmac(digest, derived_key, sizeof derived_key,
|
||||
epayload->master_desc, epayload->datablob_len);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = memcmp(digest, epayload->master_desc + epayload->datablob_len,
|
||||
sizeof digest);
|
||||
if (ret) {
|
||||
ret = -EINVAL;
|
||||
dump_hmac("datablob",
|
||||
epayload->master_desc + epayload->datablob_len,
|
||||
HASH_SIZE);
|
||||
dump_hmac("calc", digest, HASH_SIZE);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int derived_key_decrypt(struct encrypted_key_payload *epayload,
|
||||
const u8 *derived_key,
|
||||
unsigned int derived_keylen)
|
||||
{
|
||||
struct scatterlist sg_in[1];
|
||||
struct scatterlist sg_out[2];
|
||||
struct blkcipher_desc desc;
|
||||
unsigned int encrypted_datalen;
|
||||
char pad[16];
|
||||
int ret;
|
||||
|
||||
encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
|
||||
ret = init_blkcipher_desc(&desc, derived_key, derived_keylen,
|
||||
epayload->iv, ivsize);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
dump_encrypted_data(epayload, encrypted_datalen);
|
||||
|
||||
memset(pad, 0, sizeof pad);
|
||||
sg_init_table(sg_in, 1);
|
||||
sg_init_table(sg_out, 2);
|
||||
sg_set_buf(sg_in, epayload->encrypted_data, encrypted_datalen);
|
||||
sg_set_buf(&sg_out[0], epayload->decrypted_data,
|
||||
epayload->decrypted_datalen);
|
||||
sg_set_buf(&sg_out[1], pad, sizeof pad);
|
||||
|
||||
ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, encrypted_datalen);
|
||||
crypto_free_blkcipher(desc.tfm);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
dump_decrypted_data(epayload);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Allocate memory for decrypted key and datablob. */
|
||||
static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
|
||||
const char *master_desc,
|
||||
const char *datalen)
|
||||
{
|
||||
struct encrypted_key_payload *epayload = NULL;
|
||||
unsigned short datablob_len;
|
||||
unsigned short decrypted_datalen;
|
||||
unsigned int encrypted_datalen;
|
||||
long dlen;
|
||||
int ret;
|
||||
|
||||
ret = strict_strtol(datalen, 10, &dlen);
|
||||
if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
decrypted_datalen = dlen;
|
||||
encrypted_datalen = roundup(decrypted_datalen, blksize);
|
||||
|
||||
datablob_len = strlen(master_desc) + 1 + strlen(datalen) + 1
|
||||
+ ivsize + 1 + encrypted_datalen;
|
||||
|
||||
ret = key_payload_reserve(key, decrypted_datalen + datablob_len
|
||||
+ HASH_SIZE + 1);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
epayload = kzalloc(sizeof(*epayload) + decrypted_datalen +
|
||||
datablob_len + HASH_SIZE + 1, GFP_KERNEL);
|
||||
if (!epayload)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
epayload->decrypted_datalen = decrypted_datalen;
|
||||
epayload->datablob_len = datablob_len;
|
||||
return epayload;
|
||||
}
|
||||
|
||||
static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
|
||||
const char *hex_encoded_iv)
|
||||
{
|
||||
struct key *mkey;
|
||||
u8 derived_key[HASH_SIZE];
|
||||
u8 *master_key;
|
||||
u8 *hmac;
|
||||
const char *hex_encoded_data;
|
||||
unsigned int encrypted_datalen;
|
||||
size_t master_keylen;
|
||||
size_t asciilen;
|
||||
int ret;
|
||||
|
||||
encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
|
||||
asciilen = (ivsize + 1 + encrypted_datalen + HASH_SIZE) * 2;
|
||||
if (strlen(hex_encoded_iv) != asciilen)
|
||||
return -EINVAL;
|
||||
|
||||
hex_encoded_data = hex_encoded_iv + (2 * ivsize) + 2;
|
||||
hex2bin(epayload->iv, hex_encoded_iv, ivsize);
|
||||
hex2bin(epayload->encrypted_data, hex_encoded_data, encrypted_datalen);
|
||||
|
||||
hmac = epayload->master_desc + epayload->datablob_len;
|
||||
hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), HASH_SIZE);
|
||||
|
||||
mkey = request_master_key(epayload, &master_key, &master_keylen);
|
||||
if (IS_ERR(mkey))
|
||||
return PTR_ERR(mkey);
|
||||
|
||||
ret = datablob_hmac_verify(epayload, master_key, master_keylen);
|
||||
if (ret < 0) {
|
||||
pr_err("encrypted_key: bad hmac (%d)\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = derived_key_decrypt(epayload, derived_key, sizeof derived_key);
|
||||
if (ret < 0)
|
||||
pr_err("encrypted_key: failed to decrypt key (%d)\n", ret);
|
||||
out:
|
||||
up_read(&mkey->sem);
|
||||
key_put(mkey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __ekey_init(struct encrypted_key_payload *epayload,
|
||||
const char *master_desc, const char *datalen)
|
||||
{
|
||||
epayload->master_desc = epayload->decrypted_data
|
||||
+ epayload->decrypted_datalen;
|
||||
epayload->datalen = epayload->master_desc + strlen(master_desc) + 1;
|
||||
epayload->iv = epayload->datalen + strlen(datalen) + 1;
|
||||
epayload->encrypted_data = epayload->iv + ivsize + 1;
|
||||
|
||||
memcpy(epayload->master_desc, master_desc, strlen(master_desc));
|
||||
memcpy(epayload->datalen, datalen, strlen(datalen));
|
||||
}
|
||||
|
||||
/*
|
||||
* encrypted_init - initialize an encrypted key
|
||||
*
|
||||
* For a new key, use a random number for both the iv and data
|
||||
* itself. For an old key, decrypt the hex encoded data.
|
||||
*/
|
||||
static int encrypted_init(struct encrypted_key_payload *epayload,
|
||||
const char *master_desc, const char *datalen,
|
||||
const char *hex_encoded_iv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
__ekey_init(epayload, master_desc, datalen);
|
||||
if (!hex_encoded_iv) {
|
||||
get_random_bytes(epayload->iv, ivsize);
|
||||
|
||||
get_random_bytes(epayload->decrypted_data,
|
||||
epayload->decrypted_datalen);
|
||||
} else
|
||||
ret = encrypted_key_decrypt(epayload, hex_encoded_iv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* encrypted_instantiate - instantiate an encrypted key
|
||||
*
|
||||
* Decrypt an existing encrypted datablob or create a new encrypted key
|
||||
* based on a kernel random number.
|
||||
*
|
||||
* On success, return 0. Otherwise return errno.
|
||||
*/
|
||||
static int encrypted_instantiate(struct key *key, const void *data,
|
||||
size_t datalen)
|
||||
{
|
||||
struct encrypted_key_payload *epayload = NULL;
|
||||
char *datablob = NULL;
|
||||
char *master_desc = NULL;
|
||||
char *decrypted_datalen = NULL;
|
||||
char *hex_encoded_iv = NULL;
|
||||
int ret;
|
||||
|
||||
if (datalen <= 0 || datalen > 32767 || !data)
|
||||
return -EINVAL;
|
||||
|
||||
datablob = kmalloc(datalen + 1, GFP_KERNEL);
|
||||
if (!datablob)
|
||||
return -ENOMEM;
|
||||
datablob[datalen] = 0;
|
||||
memcpy(datablob, data, datalen);
|
||||
ret = datablob_parse(datablob, &master_desc, &decrypted_datalen,
|
||||
&hex_encoded_iv);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
epayload = encrypted_key_alloc(key, master_desc, decrypted_datalen);
|
||||
if (IS_ERR(epayload)) {
|
||||
ret = PTR_ERR(epayload);
|
||||
goto out;
|
||||
}
|
||||
ret = encrypted_init(epayload, master_desc, decrypted_datalen,
|
||||
hex_encoded_iv);
|
||||
if (ret < 0) {
|
||||
kfree(epayload);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(key->payload.data, epayload);
|
||||
out:
|
||||
kfree(datablob);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void encrypted_rcu_free(struct rcu_head *rcu)
|
||||
{
|
||||
struct encrypted_key_payload *epayload;
|
||||
|
||||
epayload = container_of(rcu, struct encrypted_key_payload, rcu);
|
||||
memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
|
||||
kfree(epayload);
|
||||
}
|
||||
|
||||
/*
|
||||
* encrypted_update - update the master key description
|
||||
*
|
||||
* Change the master key description for an existing encrypted key.
|
||||
* The next read will return an encrypted datablob using the new
|
||||
* master key description.
|
||||
*
|
||||
* On success, return 0. Otherwise return errno.
|
||||
*/
|
||||
static int encrypted_update(struct key *key, const void *data, size_t datalen)
|
||||
{
|
||||
struct encrypted_key_payload *epayload = key->payload.data;
|
||||
struct encrypted_key_payload *new_epayload;
|
||||
char *buf;
|
||||
char *new_master_desc = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (datalen <= 0 || datalen > 32767 || !data)
|
||||
return -EINVAL;
|
||||
|
||||
buf = kmalloc(datalen + 1, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
buf[datalen] = 0;
|
||||
memcpy(buf, data, datalen);
|
||||
ret = datablob_parse(buf, &new_master_desc, NULL, NULL);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = valid_master_desc(new_master_desc, epayload->master_desc);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
new_epayload = encrypted_key_alloc(key, new_master_desc,
|
||||
epayload->datalen);
|
||||
if (IS_ERR(new_epayload)) {
|
||||
ret = PTR_ERR(new_epayload);
|
||||
goto out;
|
||||
}
|
||||
|
||||
__ekey_init(new_epayload, new_master_desc, epayload->datalen);
|
||||
|
||||
memcpy(new_epayload->iv, epayload->iv, ivsize);
|
||||
memcpy(new_epayload->decrypted_data, epayload->decrypted_data,
|
||||
epayload->decrypted_datalen);
|
||||
|
||||
rcu_assign_pointer(key->payload.data, new_epayload);
|
||||
call_rcu(&epayload->rcu, encrypted_rcu_free);
|
||||
out:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* encrypted_read - format and copy the encrypted data to userspace
|
||||
*
|
||||
* The resulting datablob format is:
|
||||
* <master-key name> <decrypted data length> <encrypted iv> <encrypted data>
|
||||
*
|
||||
* On success, return to userspace the encrypted key datablob size.
|
||||
*/
|
||||
static long encrypted_read(const struct key *key, char __user *buffer,
|
||||
size_t buflen)
|
||||
{
|
||||
struct encrypted_key_payload *epayload;
|
||||
struct key *mkey;
|
||||
u8 *master_key;
|
||||
size_t master_keylen;
|
||||
char derived_key[HASH_SIZE];
|
||||
char *ascii_buf;
|
||||
size_t asciiblob_len;
|
||||
int ret;
|
||||
|
||||
epayload = rcu_dereference_protected(key->payload.data,
|
||||
rwsem_is_locked(&((struct key *)key)->sem));
|
||||
|
||||
/* returns the hex encoded iv, encrypted-data, and hmac as ascii */
|
||||
asciiblob_len = epayload->datablob_len + ivsize + 1
|
||||
+ roundup(epayload->decrypted_datalen, blksize)
|
||||
+ (HASH_SIZE * 2);
|
||||
|
||||
if (!buffer || buflen < asciiblob_len)
|
||||
return asciiblob_len;
|
||||
|
||||
mkey = request_master_key(epayload, &master_key, &master_keylen);
|
||||
if (IS_ERR(mkey))
|
||||
return PTR_ERR(mkey);
|
||||
|
||||
ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = derived_key_encrypt(epayload, derived_key, sizeof derived_key);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = datablob_hmac_append(epayload, master_key, master_keylen);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ascii_buf = datablob_format(epayload, asciiblob_len);
|
||||
if (!ascii_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
up_read(&mkey->sem);
|
||||
key_put(mkey);
|
||||
|
||||
if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0)
|
||||
ret = -EFAULT;
|
||||
kfree(ascii_buf);
|
||||
|
||||
return asciiblob_len;
|
||||
out:
|
||||
up_read(&mkey->sem);
|
||||
key_put(mkey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* encrypted_destroy - before freeing the key, clear the decrypted data
|
||||
*
|
||||
* Before freeing the key, clear the memory containing the decrypted
|
||||
* key data.
|
||||
*/
|
||||
static void encrypted_destroy(struct key *key)
|
||||
{
|
||||
struct encrypted_key_payload *epayload = key->payload.data;
|
||||
|
||||
if (!epayload)
|
||||
return;
|
||||
|
||||
memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
|
||||
kfree(key->payload.data);
|
||||
}
|
||||
|
||||
struct key_type key_type_encrypted = {
|
||||
.name = "encrypted",
|
||||
.instantiate = encrypted_instantiate,
|
||||
.update = encrypted_update,
|
||||
.match = user_match,
|
||||
.destroy = encrypted_destroy,
|
||||
.describe = user_describe,
|
||||
.read = encrypted_read,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(key_type_encrypted);
|
||||
|
||||
static void encrypted_shash_release(void)
|
||||
{
|
||||
if (hashalg)
|
||||
crypto_free_shash(hashalg);
|
||||
if (hmacalg)
|
||||
crypto_free_shash(hmacalg);
|
||||
}
|
||||
|
||||
static int __init encrypted_shash_alloc(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(hmacalg)) {
|
||||
pr_info("encrypted_key: could not allocate crypto %s\n",
|
||||
hmac_alg);
|
||||
return PTR_ERR(hmacalg);
|
||||
}
|
||||
|
||||
hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(hashalg)) {
|
||||
pr_info("encrypted_key: could not allocate crypto %s\n",
|
||||
hash_alg);
|
||||
ret = PTR_ERR(hashalg);
|
||||
goto hashalg_fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
hashalg_fail:
|
||||
crypto_free_shash(hmacalg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init init_encrypted(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = encrypted_shash_alloc();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = register_key_type(&key_type_encrypted);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return aes_get_sizes();
|
||||
out:
|
||||
encrypted_shash_release();
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static void __exit cleanup_encrypted(void)
|
||||
{
|
||||
encrypted_shash_release();
|
||||
unregister_key_type(&key_type_encrypted);
|
||||
}
|
||||
|
||||
late_initcall(init_encrypted);
|
||||
module_exit(cleanup_encrypted);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
54
security/keys/encrypted_defined.h
Normal file
54
security/keys/encrypted_defined.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef __ENCRYPTED_KEY_H
|
||||
#define __ENCRYPTED_KEY_H
|
||||
|
||||
#define ENCRYPTED_DEBUG 0
|
||||
|
||||
#if ENCRYPTED_DEBUG
|
||||
static inline void dump_master_key(const u8 *master_key, size_t master_keylen)
|
||||
{
|
||||
print_hex_dump(KERN_ERR, "master key: ", DUMP_PREFIX_NONE, 32, 1,
|
||||
master_key, master_keylen, 0);
|
||||
}
|
||||
|
||||
static inline void dump_decrypted_data(struct encrypted_key_payload *epayload)
|
||||
{
|
||||
print_hex_dump(KERN_ERR, "decrypted data: ", DUMP_PREFIX_NONE, 32, 1,
|
||||
epayload->decrypted_data,
|
||||
epayload->decrypted_datalen, 0);
|
||||
}
|
||||
|
||||
static inline void dump_encrypted_data(struct encrypted_key_payload *epayload,
|
||||
unsigned int encrypted_datalen)
|
||||
{
|
||||
print_hex_dump(KERN_ERR, "encrypted data: ", DUMP_PREFIX_NONE, 32, 1,
|
||||
epayload->encrypted_data, encrypted_datalen, 0);
|
||||
}
|
||||
|
||||
static inline void dump_hmac(const char *str, const u8 *digest,
|
||||
unsigned int hmac_size)
|
||||
{
|
||||
if (str)
|
||||
pr_info("encrypted_key: %s", str);
|
||||
print_hex_dump(KERN_ERR, "hmac: ", DUMP_PREFIX_NONE, 32, 1, digest,
|
||||
hmac_size, 0);
|
||||
}
|
||||
#else
|
||||
static inline void dump_master_key(const u8 *master_key, size_t master_keylen)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dump_decrypted_data(struct encrypted_key_payload *epayload)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dump_encrypted_data(struct encrypted_key_payload *epayload,
|
||||
unsigned int encrypted_datalen)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dump_hmac(const char *str, const u8 *digest,
|
||||
unsigned int hmac_size)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#endif
|
1175
security/keys/trusted_defined.c
Normal file
1175
security/keys/trusted_defined.c
Normal file
File diff suppressed because it is too large
Load Diff
134
security/keys/trusted_defined.h
Normal file
134
security/keys/trusted_defined.h
Normal file
@ -0,0 +1,134 @@
|
||||
#ifndef __TRUSTED_KEY_H
|
||||
#define __TRUSTED_KEY_H
|
||||
|
||||
/* implementation specific TPM constants */
|
||||
#define MAX_PCRINFO_SIZE 64
|
||||
#define MAX_BUF_SIZE 512
|
||||
#define TPM_GETRANDOM_SIZE 14
|
||||
#define TPM_OSAP_SIZE 36
|
||||
#define TPM_OIAP_SIZE 10
|
||||
#define TPM_SEAL_SIZE 87
|
||||
#define TPM_UNSEAL_SIZE 104
|
||||
#define TPM_SIZE_OFFSET 2
|
||||
#define TPM_RETURN_OFFSET 6
|
||||
#define TPM_DATA_OFFSET 10
|
||||
|
||||
#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset]))
|
||||
#define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset])
|
||||
#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset]))
|
||||
|
||||
struct tpm_buf {
|
||||
int len;
|
||||
unsigned char data[MAX_BUF_SIZE];
|
||||
};
|
||||
|
||||
#define INIT_BUF(tb) (tb->len = 0)
|
||||
|
||||
struct osapsess {
|
||||
uint32_t handle;
|
||||
unsigned char secret[SHA1_DIGEST_SIZE];
|
||||
unsigned char enonce[TPM_NONCE_SIZE];
|
||||
};
|
||||
|
||||
/* discrete values, but have to store in uint16_t for TPM use */
|
||||
enum {
|
||||
SEAL_keytype = 1,
|
||||
SRK_keytype = 4
|
||||
};
|
||||
|
||||
struct trusted_key_options {
|
||||
uint16_t keytype;
|
||||
uint32_t keyhandle;
|
||||
unsigned char keyauth[SHA1_DIGEST_SIZE];
|
||||
unsigned char blobauth[SHA1_DIGEST_SIZE];
|
||||
uint32_t pcrinfo_len;
|
||||
unsigned char pcrinfo[MAX_PCRINFO_SIZE];
|
||||
int pcrlock;
|
||||
};
|
||||
|
||||
#define TPM_DEBUG 0
|
||||
|
||||
#if TPM_DEBUG
|
||||
static inline void dump_options(struct trusted_key_options *o)
|
||||
{
|
||||
pr_info("trusted_key: sealing key type %d\n", o->keytype);
|
||||
pr_info("trusted_key: sealing key handle %0X\n", o->keyhandle);
|
||||
pr_info("trusted_key: pcrlock %d\n", o->pcrlock);
|
||||
pr_info("trusted_key: pcrinfo %d\n", o->pcrinfo_len);
|
||||
print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE,
|
||||
16, 1, o->pcrinfo, o->pcrinfo_len, 0);
|
||||
}
|
||||
|
||||
static inline void dump_payload(struct trusted_key_payload *p)
|
||||
{
|
||||
pr_info("trusted_key: key_len %d\n", p->key_len);
|
||||
print_hex_dump(KERN_INFO, "key ", DUMP_PREFIX_NONE,
|
||||
16, 1, p->key, p->key_len, 0);
|
||||
pr_info("trusted_key: bloblen %d\n", p->blob_len);
|
||||
print_hex_dump(KERN_INFO, "blob ", DUMP_PREFIX_NONE,
|
||||
16, 1, p->blob, p->blob_len, 0);
|
||||
pr_info("trusted_key: migratable %d\n", p->migratable);
|
||||
}
|
||||
|
||||
static inline void dump_sess(struct osapsess *s)
|
||||
{
|
||||
print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE,
|
||||
16, 1, &s->handle, 4, 0);
|
||||
pr_info("trusted-key: secret:\n");
|
||||
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
|
||||
16, 1, &s->secret, SHA1_DIGEST_SIZE, 0);
|
||||
pr_info("trusted-key: enonce:\n");
|
||||
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
|
||||
16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0);
|
||||
}
|
||||
|
||||
static inline void dump_tpm_buf(unsigned char *buf)
|
||||
{
|
||||
int len;
|
||||
|
||||
pr_info("\ntrusted-key: tpm buffer\n");
|
||||
len = LOAD32(buf, TPM_SIZE_OFFSET);
|
||||
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0);
|
||||
}
|
||||
#else
|
||||
static inline void dump_options(struct trusted_key_options *o)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dump_payload(struct trusted_key_payload *p)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dump_sess(struct osapsess *s)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dump_tpm_buf(unsigned char *buf)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void store8(struct tpm_buf *buf, const unsigned char value)
|
||||
{
|
||||
buf->data[buf->len++] = value;
|
||||
}
|
||||
|
||||
static inline void store16(struct tpm_buf *buf, const uint16_t value)
|
||||
{
|
||||
*(uint16_t *) & buf->data[buf->len] = htons(value);
|
||||
buf->len += sizeof value;
|
||||
}
|
||||
|
||||
static inline void store32(struct tpm_buf *buf, const uint32_t value)
|
||||
{
|
||||
*(uint32_t *) & buf->data[buf->len] = htonl(value);
|
||||
buf->len += sizeof value;
|
||||
}
|
||||
|
||||
static inline void storebytes(struct tpm_buf *buf, const unsigned char *in,
|
||||
const int len)
|
||||
{
|
||||
memcpy(buf->data + buf->len, in, len);
|
||||
buf->len += len;
|
||||
}
|
||||
#endif
|
@ -2525,7 +2525,10 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
sid = tsec->sid;
|
||||
newsid = tsec->create_sid;
|
||||
|
||||
if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
|
||||
if ((sbsec->flags & SE_SBINITIALIZED) &&
|
||||
(sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
|
||||
newsid = sbsec->mntpoint_sid;
|
||||
else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
|
||||
rc = security_transition_sid(sid, dsec->sid,
|
||||
inode_mode_to_security_class(inode->i_mode),
|
||||
&newsid);
|
||||
|
@ -142,7 +142,7 @@ struct security_class_mapping secclass_map[] = {
|
||||
"node_bind", "name_connect", NULL } },
|
||||
{ "memprotect", { "mmap_zero", NULL } },
|
||||
{ "peer", { "recv", NULL } },
|
||||
{ "capability2", { "mac_override", "mac_admin", NULL } },
|
||||
{ "capability2", { "mac_override", "mac_admin", "syslog", NULL } },
|
||||
{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
|
||||
{ "tun_socket",
|
||||
{ COMMON_SOCK_PERMS, NULL } },
|
||||
|
@ -65,6 +65,8 @@ static struct nlmsg_perm nlmsg_route_perms[] =
|
||||
{ RTM_NEWADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
|
||||
{ RTM_DELADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
|
||||
{ RTM_GETADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_READ },
|
||||
{ RTM_GETDCB, NETLINK_ROUTE_SOCKET__NLMSG_READ },
|
||||
{ RTM_SETDCB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
|
||||
};
|
||||
|
||||
static struct nlmsg_perm nlmsg_firewall_perms[] =
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -193,6 +193,7 @@ int cond_index_bool(void *key, void *datum, void *datap)
|
||||
{
|
||||
struct policydb *p;
|
||||
struct cond_bool_datum *booldatum;
|
||||
struct flex_array *fa;
|
||||
|
||||
booldatum = datum;
|
||||
p = datap;
|
||||
@ -200,7 +201,10 @@ int cond_index_bool(void *key, void *datum, void *datap)
|
||||
if (!booldatum->value || booldatum->value > p->p_bools.nprim)
|
||||
return -EINVAL;
|
||||
|
||||
p->p_bool_val_to_name[booldatum->value - 1] = key;
|
||||
fa = p->sym_val_to_name[SYM_BOOLS];
|
||||
if (flex_array_put_ptr(fa, booldatum->value - 1, key,
|
||||
GFP_KERNEL | __GFP_ZERO))
|
||||
BUG();
|
||||
p->bool_val_to_struct[booldatum->value - 1] = booldatum;
|
||||
|
||||
return 0;
|
||||
|
@ -45,7 +45,7 @@ int mls_compute_context_len(struct context *context)
|
||||
len = 1; /* for the beginning ":" */
|
||||
for (l = 0; l < 2; l++) {
|
||||
int index_sens = context->range.level[l].sens;
|
||||
len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
|
||||
len += strlen(sym_name(&policydb, SYM_LEVELS, index_sens - 1));
|
||||
|
||||
/* categories */
|
||||
head = -2;
|
||||
@ -55,17 +55,17 @@ int mls_compute_context_len(struct context *context)
|
||||
if (i - prev > 1) {
|
||||
/* one or more negative bits are skipped */
|
||||
if (head != prev) {
|
||||
nm = policydb.p_cat_val_to_name[prev];
|
||||
nm = sym_name(&policydb, SYM_CATS, prev);
|
||||
len += strlen(nm) + 1;
|
||||
}
|
||||
nm = policydb.p_cat_val_to_name[i];
|
||||
nm = sym_name(&policydb, SYM_CATS, i);
|
||||
len += strlen(nm) + 1;
|
||||
head = i;
|
||||
}
|
||||
prev = i;
|
||||
}
|
||||
if (prev != head) {
|
||||
nm = policydb.p_cat_val_to_name[prev];
|
||||
nm = sym_name(&policydb, SYM_CATS, prev);
|
||||
len += strlen(nm) + 1;
|
||||
}
|
||||
if (l == 0) {
|
||||
@ -102,8 +102,8 @@ void mls_sid_to_context(struct context *context,
|
||||
scontextp++;
|
||||
|
||||
for (l = 0; l < 2; l++) {
|
||||
strcpy(scontextp,
|
||||
policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
|
||||
strcpy(scontextp, sym_name(&policydb, SYM_LEVELS,
|
||||
context->range.level[l].sens - 1));
|
||||
scontextp += strlen(scontextp);
|
||||
|
||||
/* categories */
|
||||
@ -118,7 +118,7 @@ void mls_sid_to_context(struct context *context,
|
||||
*scontextp++ = '.';
|
||||
else
|
||||
*scontextp++ = ',';
|
||||
nm = policydb.p_cat_val_to_name[prev];
|
||||
nm = sym_name(&policydb, SYM_CATS, prev);
|
||||
strcpy(scontextp, nm);
|
||||
scontextp += strlen(nm);
|
||||
}
|
||||
@ -126,7 +126,7 @@ void mls_sid_to_context(struct context *context,
|
||||
*scontextp++ = ':';
|
||||
else
|
||||
*scontextp++ = ',';
|
||||
nm = policydb.p_cat_val_to_name[i];
|
||||
nm = sym_name(&policydb, SYM_CATS, i);
|
||||
strcpy(scontextp, nm);
|
||||
scontextp += strlen(nm);
|
||||
head = i;
|
||||
@ -139,7 +139,7 @@ void mls_sid_to_context(struct context *context,
|
||||
*scontextp++ = '.';
|
||||
else
|
||||
*scontextp++ = ',';
|
||||
nm = policydb.p_cat_val_to_name[prev];
|
||||
nm = sym_name(&policydb, SYM_CATS, prev);
|
||||
strcpy(scontextp, nm);
|
||||
scontextp += strlen(nm);
|
||||
}
|
||||
@ -166,7 +166,7 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l)
|
||||
if (!l->sens || l->sens > p->p_levels.nprim)
|
||||
return 0;
|
||||
levdatum = hashtab_search(p->p_levels.table,
|
||||
p->p_sens_val_to_name[l->sens - 1]);
|
||||
sym_name(p, SYM_LEVELS, l->sens - 1));
|
||||
if (!levdatum)
|
||||
return 0;
|
||||
|
||||
@ -482,7 +482,8 @@ int mls_convert_context(struct policydb *oldp,
|
||||
|
||||
for (l = 0; l < 2; l++) {
|
||||
levdatum = hashtab_search(newp->p_levels.table,
|
||||
oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
|
||||
sym_name(oldp, SYM_LEVELS,
|
||||
c->range.level[l].sens - 1));
|
||||
|
||||
if (!levdatum)
|
||||
return -EINVAL;
|
||||
@ -493,7 +494,7 @@ int mls_convert_context(struct policydb *oldp,
|
||||
int rc;
|
||||
|
||||
catdatum = hashtab_search(newp->p_cats.table,
|
||||
oldp->p_cat_val_to_name[i]);
|
||||
sym_name(oldp, SYM_CATS, i));
|
||||
if (!catdatum)
|
||||
return -EINVAL;
|
||||
rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -203,21 +203,13 @@ struct policydb {
|
||||
#define p_cats symtab[SYM_CATS]
|
||||
|
||||
/* symbol names indexed by (value - 1) */
|
||||
char **sym_val_to_name[SYM_NUM];
|
||||
#define p_common_val_to_name sym_val_to_name[SYM_COMMONS]
|
||||
#define p_class_val_to_name sym_val_to_name[SYM_CLASSES]
|
||||
#define p_role_val_to_name sym_val_to_name[SYM_ROLES]
|
||||
#define p_type_val_to_name sym_val_to_name[SYM_TYPES]
|
||||
#define p_user_val_to_name sym_val_to_name[SYM_USERS]
|
||||
#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
|
||||
#define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
|
||||
#define p_cat_val_to_name sym_val_to_name[SYM_CATS]
|
||||
struct flex_array *sym_val_to_name[SYM_NUM];
|
||||
|
||||
/* class, role, and user attributes indexed by (value - 1) */
|
||||
struct class_datum **class_val_to_struct;
|
||||
struct role_datum **role_val_to_struct;
|
||||
struct user_datum **user_val_to_struct;
|
||||
struct type_datum **type_val_to_struct;
|
||||
struct flex_array *type_val_to_struct_array;
|
||||
|
||||
/* type enforcement access vectors and transitions */
|
||||
struct avtab te_avtab;
|
||||
@ -321,6 +313,13 @@ static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline char *sym_name(struct policydb *p, unsigned int sym_num, unsigned int element_nr)
|
||||
{
|
||||
struct flex_array *fa = p->sym_val_to_name[sym_num];
|
||||
|
||||
return flex_array_get_ptr(fa, element_nr);
|
||||
}
|
||||
|
||||
extern u16 string_to_security_class(struct policydb *p, const char *name);
|
||||
extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name);
|
||||
|
||||
|
@ -464,7 +464,7 @@ static void security_dump_masked_av(struct context *scontext,
|
||||
if (!permissions)
|
||||
return;
|
||||
|
||||
tclass_name = policydb.p_class_val_to_name[tclass - 1];
|
||||
tclass_name = sym_name(&policydb, SYM_CLASSES, tclass - 1);
|
||||
tclass_dat = policydb.class_val_to_struct[tclass - 1];
|
||||
common_dat = tclass_dat->comdatum;
|
||||
|
||||
@ -530,12 +530,18 @@ static void type_attribute_bounds_av(struct context *scontext,
|
||||
struct context lo_scontext;
|
||||
struct context lo_tcontext;
|
||||
struct av_decision lo_avd;
|
||||
struct type_datum *source
|
||||
= policydb.type_val_to_struct[scontext->type - 1];
|
||||
struct type_datum *target
|
||||
= policydb.type_val_to_struct[tcontext->type - 1];
|
||||
struct type_datum *source;
|
||||
struct type_datum *target;
|
||||
u32 masked = 0;
|
||||
|
||||
source = flex_array_get_ptr(policydb.type_val_to_struct_array,
|
||||
scontext->type - 1);
|
||||
BUG_ON(!source);
|
||||
|
||||
target = flex_array_get_ptr(policydb.type_val_to_struct_array,
|
||||
tcontext->type - 1);
|
||||
BUG_ON(!target);
|
||||
|
||||
if (source->bounds) {
|
||||
memset(&lo_avd, 0, sizeof(lo_avd));
|
||||
|
||||
@ -701,16 +707,16 @@ static int security_validtrans_handle_fail(struct context *ocontext,
|
||||
char *o = NULL, *n = NULL, *t = NULL;
|
||||
u32 olen, nlen, tlen;
|
||||
|
||||
if (context_struct_to_string(ocontext, &o, &olen) < 0)
|
||||
if (context_struct_to_string(ocontext, &o, &olen))
|
||||
goto out;
|
||||
if (context_struct_to_string(ncontext, &n, &nlen) < 0)
|
||||
if (context_struct_to_string(ncontext, &n, &nlen))
|
||||
goto out;
|
||||
if (context_struct_to_string(tcontext, &t, &tlen) < 0)
|
||||
if (context_struct_to_string(tcontext, &t, &tlen))
|
||||
goto out;
|
||||
audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
|
||||
"security_validate_transition: denied for"
|
||||
" oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
|
||||
o, n, t, policydb.p_class_val_to_name[tclass-1]);
|
||||
o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
|
||||
out:
|
||||
kfree(o);
|
||||
kfree(n);
|
||||
@ -801,10 +807,11 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
|
||||
struct context *old_context, *new_context;
|
||||
struct type_datum *type;
|
||||
int index;
|
||||
int rc = -EINVAL;
|
||||
int rc;
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
|
||||
rc = -EINVAL;
|
||||
old_context = sidtab_search(&sidtab, old_sid);
|
||||
if (!old_context) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
|
||||
@ -812,6 +819,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = -EINVAL;
|
||||
new_context = sidtab_search(&sidtab, new_sid);
|
||||
if (!new_context) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
|
||||
@ -819,28 +827,27 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
/* type/domain unchanged */
|
||||
if (old_context->type == new_context->type) {
|
||||
rc = 0;
|
||||
if (old_context->type == new_context->type)
|
||||
goto out;
|
||||
}
|
||||
|
||||
index = new_context->type;
|
||||
while (true) {
|
||||
type = policydb.type_val_to_struct[index - 1];
|
||||
type = flex_array_get_ptr(policydb.type_val_to_struct_array,
|
||||
index - 1);
|
||||
BUG_ON(!type);
|
||||
|
||||
/* not bounded anymore */
|
||||
if (!type->bounds) {
|
||||
rc = -EPERM;
|
||||
rc = -EPERM;
|
||||
if (!type->bounds)
|
||||
break;
|
||||
}
|
||||
|
||||
/* @newsid is bounded by @oldsid */
|
||||
if (type->bounds == old_context->type) {
|
||||
rc = 0;
|
||||
rc = 0;
|
||||
if (type->bounds == old_context->type)
|
||||
break;
|
||||
}
|
||||
|
||||
index = type->bounds;
|
||||
}
|
||||
|
||||
@ -1005,9 +1012,9 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
|
||||
}
|
||||
|
||||
/* Compute the size of the context. */
|
||||
*scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1;
|
||||
*scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1;
|
||||
*scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1;
|
||||
*scontext_len += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1;
|
||||
*scontext_len += strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1;
|
||||
*scontext_len += strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)) + 1;
|
||||
*scontext_len += mls_compute_context_len(context);
|
||||
|
||||
if (!scontext)
|
||||
@ -1023,12 +1030,12 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
|
||||
* Copy the user name, role name and type name into the context.
|
||||
*/
|
||||
sprintf(scontextp, "%s:%s:%s",
|
||||
policydb.p_user_val_to_name[context->user - 1],
|
||||
policydb.p_role_val_to_name[context->role - 1],
|
||||
policydb.p_type_val_to_name[context->type - 1]);
|
||||
scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) +
|
||||
1 + strlen(policydb.p_role_val_to_name[context->role - 1]) +
|
||||
1 + strlen(policydb.p_type_val_to_name[context->type - 1]);
|
||||
sym_name(&policydb, SYM_USERS, context->user - 1),
|
||||
sym_name(&policydb, SYM_ROLES, context->role - 1),
|
||||
sym_name(&policydb, SYM_TYPES, context->type - 1));
|
||||
scontextp += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) +
|
||||
1 + strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) +
|
||||
1 + strlen(sym_name(&policydb, SYM_TYPES, context->type - 1));
|
||||
|
||||
mls_sid_to_context(context, &scontextp);
|
||||
|
||||
@ -1187,16 +1194,13 @@ static int string_to_context_struct(struct policydb *pol,
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if ((p - scontext) < scontext_len) {
|
||||
rc = -EINVAL;
|
||||
rc = -EINVAL;
|
||||
if ((p - scontext) < scontext_len)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check the validity of the new context. */
|
||||
if (!policydb_context_isvalid(pol, ctx)) {
|
||||
rc = -EINVAL;
|
||||
if (!policydb_context_isvalid(pol, ctx))
|
||||
goto out;
|
||||
}
|
||||
rc = 0;
|
||||
out:
|
||||
if (rc)
|
||||
@ -1235,27 +1239,26 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
|
||||
|
||||
if (force) {
|
||||
/* Save another copy for storing in uninterpreted form */
|
||||
rc = -ENOMEM;
|
||||
str = kstrdup(scontext2, gfp_flags);
|
||||
if (!str) {
|
||||
kfree(scontext2);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!str)
|
||||
goto out;
|
||||
}
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
rc = string_to_context_struct(&policydb, &sidtab,
|
||||
scontext2, scontext_len,
|
||||
&context, def_sid);
|
||||
rc = string_to_context_struct(&policydb, &sidtab, scontext2,
|
||||
scontext_len, &context, def_sid);
|
||||
if (rc == -EINVAL && force) {
|
||||
context.str = str;
|
||||
context.len = scontext_len;
|
||||
str = NULL;
|
||||
} else if (rc)
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
rc = sidtab_context_to_sid(&sidtab, &context, sid);
|
||||
context_destroy(&context);
|
||||
out:
|
||||
out_unlock:
|
||||
read_unlock(&policy_rwlock);
|
||||
out:
|
||||
kfree(scontext2);
|
||||
kfree(str);
|
||||
return rc;
|
||||
@ -1319,18 +1322,18 @@ static int compute_sid_handle_invalid_context(
|
||||
char *s = NULL, *t = NULL, *n = NULL;
|
||||
u32 slen, tlen, nlen;
|
||||
|
||||
if (context_struct_to_string(scontext, &s, &slen) < 0)
|
||||
if (context_struct_to_string(scontext, &s, &slen))
|
||||
goto out;
|
||||
if (context_struct_to_string(tcontext, &t, &tlen) < 0)
|
||||
if (context_struct_to_string(tcontext, &t, &tlen))
|
||||
goto out;
|
||||
if (context_struct_to_string(newcontext, &n, &nlen) < 0)
|
||||
if (context_struct_to_string(newcontext, &n, &nlen))
|
||||
goto out;
|
||||
audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
|
||||
"security_compute_sid: invalid context %s"
|
||||
" for scontext=%s"
|
||||
" tcontext=%s"
|
||||
" tclass=%s",
|
||||
n, s, t, policydb.p_class_val_to_name[tclass-1]);
|
||||
n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
|
||||
out:
|
||||
kfree(s);
|
||||
kfree(t);
|
||||
@ -1569,22 +1572,17 @@ static int clone_sid(u32 sid,
|
||||
|
||||
static inline int convert_context_handle_invalid_context(struct context *context)
|
||||
{
|
||||
int rc = 0;
|
||||
char *s;
|
||||
u32 len;
|
||||
|
||||
if (selinux_enforcing) {
|
||||
rc = -EINVAL;
|
||||
} else {
|
||||
char *s;
|
||||
u32 len;
|
||||
if (selinux_enforcing)
|
||||
return -EINVAL;
|
||||
|
||||
if (!context_struct_to_string(context, &s, &len)) {
|
||||
printk(KERN_WARNING
|
||||
"SELinux: Context %s would be invalid if enforcing\n",
|
||||
s);
|
||||
kfree(s);
|
||||
}
|
||||
if (!context_struct_to_string(context, &s, &len)) {
|
||||
printk(KERN_WARNING "SELinux: Context %s would be invalid if enforcing\n", s);
|
||||
kfree(s);
|
||||
}
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct convert_context_args {
|
||||
@ -1621,17 +1619,17 @@ static int convert_context(u32 key,
|
||||
|
||||
if (c->str) {
|
||||
struct context ctx;
|
||||
|
||||
rc = -ENOMEM;
|
||||
s = kstrdup(c->str, GFP_KERNEL);
|
||||
if (!s) {
|
||||
rc = -ENOMEM;
|
||||
if (!s)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = string_to_context_struct(args->newp, NULL, s,
|
||||
c->len, &ctx, SECSID_NULL);
|
||||
kfree(s);
|
||||
if (!rc) {
|
||||
printk(KERN_INFO
|
||||
"SELinux: Context %s became valid (mapped).\n",
|
||||
printk(KERN_INFO "SELinux: Context %s became valid (mapped).\n",
|
||||
c->str);
|
||||
/* Replace string with mapped representation. */
|
||||
kfree(c->str);
|
||||
@ -1643,8 +1641,7 @@ static int convert_context(u32 key,
|
||||
goto out;
|
||||
} else {
|
||||
/* Other error condition, e.g. ENOMEM. */
|
||||
printk(KERN_ERR
|
||||
"SELinux: Unable to map context %s, rc = %d.\n",
|
||||
printk(KERN_ERR "SELinux: Unable to map context %s, rc = %d.\n",
|
||||
c->str, -rc);
|
||||
goto out;
|
||||
}
|
||||
@ -1654,25 +1651,26 @@ static int convert_context(u32 key,
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = -EINVAL;
|
||||
|
||||
/* Convert the user. */
|
||||
rc = -EINVAL;
|
||||
usrdatum = hashtab_search(args->newp->p_users.table,
|
||||
args->oldp->p_user_val_to_name[c->user - 1]);
|
||||
sym_name(args->oldp, SYM_USERS, c->user - 1));
|
||||
if (!usrdatum)
|
||||
goto bad;
|
||||
c->user = usrdatum->value;
|
||||
|
||||
/* Convert the role. */
|
||||
rc = -EINVAL;
|
||||
role = hashtab_search(args->newp->p_roles.table,
|
||||
args->oldp->p_role_val_to_name[c->role - 1]);
|
||||
sym_name(args->oldp, SYM_ROLES, c->role - 1));
|
||||
if (!role)
|
||||
goto bad;
|
||||
c->role = role->value;
|
||||
|
||||
/* Convert the type. */
|
||||
rc = -EINVAL;
|
||||
typdatum = hashtab_search(args->newp->p_types.table,
|
||||
args->oldp->p_type_val_to_name[c->type - 1]);
|
||||
sym_name(args->oldp, SYM_TYPES, c->type - 1));
|
||||
if (!typdatum)
|
||||
goto bad;
|
||||
c->type = typdatum->value;
|
||||
@ -1700,6 +1698,7 @@ static int convert_context(u32 key,
|
||||
oc = args->newp->ocontexts[OCON_ISID];
|
||||
while (oc && oc->sid[0] != SECINITSID_UNLABELED)
|
||||
oc = oc->next;
|
||||
rc = -EINVAL;
|
||||
if (!oc) {
|
||||
printk(KERN_ERR "SELinux: unable to look up"
|
||||
" the initial SIDs list\n");
|
||||
@ -1719,19 +1718,20 @@ static int convert_context(u32 key,
|
||||
}
|
||||
|
||||
context_destroy(&oldc);
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
return rc;
|
||||
bad:
|
||||
/* Map old representation to string and save it. */
|
||||
if (context_struct_to_string(&oldc, &s, &len))
|
||||
return -ENOMEM;
|
||||
rc = context_struct_to_string(&oldc, &s, &len);
|
||||
if (rc)
|
||||
return rc;
|
||||
context_destroy(&oldc);
|
||||
context_destroy(c);
|
||||
c->str = s;
|
||||
c->len = len;
|
||||
printk(KERN_INFO
|
||||
"SELinux: Context %s became invalid (unmapped).\n",
|
||||
printk(KERN_INFO "SELinux: Context %s became invalid (unmapped).\n",
|
||||
c->str);
|
||||
rc = 0;
|
||||
goto out;
|
||||
@ -2012,7 +2012,7 @@ int security_node_sid(u16 domain,
|
||||
u32 addrlen,
|
||||
u32 *out_sid)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc;
|
||||
struct ocontext *c;
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
@ -2021,10 +2021,9 @@ int security_node_sid(u16 domain,
|
||||
case AF_INET: {
|
||||
u32 addr;
|
||||
|
||||
if (addrlen != sizeof(u32)) {
|
||||
rc = -EINVAL;
|
||||
rc = -EINVAL;
|
||||
if (addrlen != sizeof(u32))
|
||||
goto out;
|
||||
}
|
||||
|
||||
addr = *((u32 *)addrp);
|
||||
|
||||
@ -2038,10 +2037,9 @@ int security_node_sid(u16 domain,
|
||||
}
|
||||
|
||||
case AF_INET6:
|
||||
if (addrlen != sizeof(u64) * 2) {
|
||||
rc = -EINVAL;
|
||||
rc = -EINVAL;
|
||||
if (addrlen != sizeof(u64) * 2)
|
||||
goto out;
|
||||
}
|
||||
c = policydb.ocontexts[OCON_NODE6];
|
||||
while (c) {
|
||||
if (match_ipv6_addrmask(addrp, c->u.node6.addr,
|
||||
@ -2052,6 +2050,7 @@ int security_node_sid(u16 domain,
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = 0;
|
||||
*out_sid = SECINITSID_NODE;
|
||||
goto out;
|
||||
}
|
||||
@ -2069,6 +2068,7 @@ int security_node_sid(u16 domain,
|
||||
*out_sid = SECINITSID_NODE;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
read_unlock(&policy_rwlock);
|
||||
return rc;
|
||||
@ -2113,24 +2113,22 @@ int security_get_user_sids(u32 fromsid,
|
||||
|
||||
context_init(&usercon);
|
||||
|
||||
rc = -EINVAL;
|
||||
fromcon = sidtab_search(&sidtab, fromsid);
|
||||
if (!fromcon) {
|
||||
rc = -EINVAL;
|
||||
if (!fromcon)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
rc = -EINVAL;
|
||||
user = hashtab_search(policydb.p_users.table, username);
|
||||
if (!user) {
|
||||
rc = -EINVAL;
|
||||
if (!user)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
usercon.user = user->value;
|
||||
|
||||
rc = -ENOMEM;
|
||||
mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC);
|
||||
if (!mysids) {
|
||||
rc = -ENOMEM;
|
||||
if (!mysids)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
|
||||
role = policydb.role_val_to_struct[i];
|
||||
@ -2147,12 +2145,11 @@ int security_get_user_sids(u32 fromsid,
|
||||
if (mynel < maxnel) {
|
||||
mysids[mynel++] = sid;
|
||||
} else {
|
||||
rc = -ENOMEM;
|
||||
maxnel += SIDS_NEL;
|
||||
mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
|
||||
if (!mysids2) {
|
||||
rc = -ENOMEM;
|
||||
if (!mysids2)
|
||||
goto out_unlock;
|
||||
}
|
||||
memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
|
||||
kfree(mysids);
|
||||
mysids = mysids2;
|
||||
@ -2160,7 +2157,7 @@ int security_get_user_sids(u32 fromsid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
out_unlock:
|
||||
read_unlock(&policy_rwlock);
|
||||
if (rc || !mynel) {
|
||||
@ -2168,9 +2165,9 @@ out_unlock:
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = -ENOMEM;
|
||||
mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
|
||||
if (!mysids2) {
|
||||
rc = -ENOMEM;
|
||||
kfree(mysids);
|
||||
goto out;
|
||||
}
|
||||
@ -2211,7 +2208,7 @@ int security_genfs_sid(const char *fstype,
|
||||
u16 sclass;
|
||||
struct genfs *genfs;
|
||||
struct ocontext *c;
|
||||
int rc = 0, cmp = 0;
|
||||
int rc, cmp = 0;
|
||||
|
||||
while (path[0] == '/' && path[1] == '/')
|
||||
path++;
|
||||
@ -2219,6 +2216,7 @@ int security_genfs_sid(const char *fstype,
|
||||
read_lock(&policy_rwlock);
|
||||
|
||||
sclass = unmap_class(orig_sclass);
|
||||
*sid = SECINITSID_UNLABELED;
|
||||
|
||||
for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
|
||||
cmp = strcmp(fstype, genfs->fstype);
|
||||
@ -2226,11 +2224,9 @@ int security_genfs_sid(const char *fstype,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!genfs || cmp) {
|
||||
*sid = SECINITSID_UNLABELED;
|
||||
rc = -ENOENT;
|
||||
rc = -ENOENT;
|
||||
if (!genfs || cmp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (c = genfs->head; c; c = c->next) {
|
||||
len = strlen(c->u.name);
|
||||
@ -2239,21 +2235,18 @@ int security_genfs_sid(const char *fstype,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!c) {
|
||||
*sid = SECINITSID_UNLABELED;
|
||||
rc = -ENOENT;
|
||||
rc = -ENOENT;
|
||||
if (!c)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!c->sid[0]) {
|
||||
rc = sidtab_context_to_sid(&sidtab,
|
||||
&c->context[0],
|
||||
&c->sid[0]);
|
||||
rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
*sid = c->sid[0];
|
||||
rc = 0;
|
||||
out:
|
||||
read_unlock(&policy_rwlock);
|
||||
return rc;
|
||||
@ -2285,8 +2278,7 @@ int security_fs_use(
|
||||
if (c) {
|
||||
*behavior = c->v.behavior;
|
||||
if (!c->sid[0]) {
|
||||
rc = sidtab_context_to_sid(&sidtab,
|
||||
&c->context[0],
|
||||
rc = sidtab_context_to_sid(&sidtab, &c->context[0],
|
||||
&c->sid[0]);
|
||||
if (rc)
|
||||
goto out;
|
||||
@ -2309,34 +2301,39 @@ out:
|
||||
|
||||
int security_get_bools(int *len, char ***names, int **values)
|
||||
{
|
||||
int i, rc = -ENOMEM;
|
||||
int i, rc;
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
*names = NULL;
|
||||
*values = NULL;
|
||||
|
||||
rc = 0;
|
||||
*len = policydb.p_bools.nprim;
|
||||
if (!*len) {
|
||||
rc = 0;
|
||||
if (!*len)
|
||||
goto out;
|
||||
}
|
||||
|
||||
*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
|
||||
rc = -ENOMEM;
|
||||
*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
|
||||
if (!*names)
|
||||
goto err;
|
||||
|
||||
*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
|
||||
rc = -ENOMEM;
|
||||
*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
|
||||
if (!*values)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < *len; i++) {
|
||||
size_t name_len;
|
||||
|
||||
(*values)[i] = policydb.bool_val_to_struct[i]->state;
|
||||
name_len = strlen(policydb.p_bool_val_to_name[i]) + 1;
|
||||
(*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
|
||||
name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1;
|
||||
|
||||
rc = -ENOMEM;
|
||||
(*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
|
||||
if (!(*names)[i])
|
||||
goto err;
|
||||
strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len);
|
||||
|
||||
strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len);
|
||||
(*names)[i][name_len - 1] = 0;
|
||||
}
|
||||
rc = 0;
|
||||
@ -2355,24 +2352,23 @@ err:
|
||||
|
||||
int security_set_bools(int len, int *values)
|
||||
{
|
||||
int i, rc = 0;
|
||||
int i, rc;
|
||||
int lenp, seqno = 0;
|
||||
struct cond_node *cur;
|
||||
|
||||
write_lock_irq(&policy_rwlock);
|
||||
|
||||
rc = -EFAULT;
|
||||
lenp = policydb.p_bools.nprim;
|
||||
if (len != lenp) {
|
||||
rc = -EFAULT;
|
||||
if (len != lenp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
|
||||
audit_log(current->audit_context, GFP_ATOMIC,
|
||||
AUDIT_MAC_CONFIG_CHANGE,
|
||||
"bool=%s val=%d old_val=%d auid=%u ses=%u",
|
||||
policydb.p_bool_val_to_name[i],
|
||||
sym_name(&policydb, SYM_BOOLS, i),
|
||||
!!values[i],
|
||||
policydb.bool_val_to_struct[i]->state,
|
||||
audit_get_loginuid(current),
|
||||
@ -2391,7 +2387,7 @@ int security_set_bools(int len, int *values)
|
||||
}
|
||||
|
||||
seqno = ++latest_granting;
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
write_unlock_irq(&policy_rwlock);
|
||||
if (!rc) {
|
||||
@ -2405,16 +2401,15 @@ out:
|
||||
|
||||
int security_get_bool_value(int bool)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc;
|
||||
int len;
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
|
||||
rc = -EFAULT;
|
||||
len = policydb.p_bools.nprim;
|
||||
if (bool >= len) {
|
||||
rc = -EFAULT;
|
||||
if (bool >= len)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = policydb.bool_val_to_struct[bool]->state;
|
||||
out:
|
||||
@ -2464,8 +2459,9 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
|
||||
struct context newcon;
|
||||
char *s;
|
||||
u32 len;
|
||||
int rc = 0;
|
||||
int rc;
|
||||
|
||||
rc = 0;
|
||||
if (!ss_initialized || !policydb.mls_enabled) {
|
||||
*new_sid = sid;
|
||||
goto out;
|
||||
@ -2474,19 +2470,20 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
|
||||
context_init(&newcon);
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
|
||||
rc = -EINVAL;
|
||||
context1 = sidtab_search(&sidtab, sid);
|
||||
if (!context1) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
||||
__func__, sid);
|
||||
rc = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
rc = -EINVAL;
|
||||
context2 = sidtab_search(&sidtab, mls_sid);
|
||||
if (!context2) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
||||
__func__, mls_sid);
|
||||
rc = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
@ -2500,20 +2497,17 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
|
||||
/* Check the validity of the new context. */
|
||||
if (!policydb_context_isvalid(&policydb, &newcon)) {
|
||||
rc = convert_context_handle_invalid_context(&newcon);
|
||||
if (rc)
|
||||
goto bad;
|
||||
if (rc) {
|
||||
if (!context_struct_to_string(&newcon, &s, &len)) {
|
||||
audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
|
||||
"security_sid_mls_copy: invalid context %s", s);
|
||||
kfree(s);
|
||||
}
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid);
|
||||
goto out_unlock;
|
||||
|
||||
bad:
|
||||
if (!context_struct_to_string(&newcon, &s, &len)) {
|
||||
audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
|
||||
"security_sid_mls_copy: invalid context %s", s);
|
||||
kfree(s);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
read_unlock(&policy_rwlock);
|
||||
context_destroy(&newcon);
|
||||
@ -2549,6 +2543,8 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
|
||||
struct context *nlbl_ctx;
|
||||
struct context *xfrm_ctx;
|
||||
|
||||
*peer_sid = SECSID_NULL;
|
||||
|
||||
/* handle the common (which also happens to be the set of easy) cases
|
||||
* right away, these two if statements catch everything involving a
|
||||
* single or absent peer SID/label */
|
||||
@ -2567,40 +2563,37 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
|
||||
/* we don't need to check ss_initialized here since the only way both
|
||||
* nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
|
||||
* security server was initialized and ss_initialized was true */
|
||||
if (!policydb.mls_enabled) {
|
||||
*peer_sid = SECSID_NULL;
|
||||
if (!policydb.mls_enabled)
|
||||
return 0;
|
||||
}
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
|
||||
rc = -EINVAL;
|
||||
nlbl_ctx = sidtab_search(&sidtab, nlbl_sid);
|
||||
if (!nlbl_ctx) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
||||
__func__, nlbl_sid);
|
||||
rc = -EINVAL;
|
||||
goto out_slowpath;
|
||||
goto out;
|
||||
}
|
||||
rc = -EINVAL;
|
||||
xfrm_ctx = sidtab_search(&sidtab, xfrm_sid);
|
||||
if (!xfrm_ctx) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
||||
__func__, xfrm_sid);
|
||||
rc = -EINVAL;
|
||||
goto out_slowpath;
|
||||
goto out;
|
||||
}
|
||||
rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
out_slowpath:
|
||||
/* at present NetLabel SIDs/labels really only carry MLS
|
||||
* information so if the MLS portion of the NetLabel SID
|
||||
* matches the MLS portion of the labeled XFRM SID/label
|
||||
* then pass along the XFRM SID as it is the most
|
||||
* expressive */
|
||||
*peer_sid = xfrm_sid;
|
||||
out:
|
||||
read_unlock(&policy_rwlock);
|
||||
if (rc == 0)
|
||||
/* at present NetLabel SIDs/labels really only carry MLS
|
||||
* information so if the MLS portion of the NetLabel SID
|
||||
* matches the MLS portion of the labeled XFRM SID/label
|
||||
* then pass along the XFRM SID as it is the most
|
||||
* expressive */
|
||||
*peer_sid = xfrm_sid;
|
||||
else
|
||||
*peer_sid = SECSID_NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2619,10 +2612,11 @@ static int get_classes_callback(void *k, void *d, void *args)
|
||||
|
||||
int security_get_classes(char ***classes, int *nclasses)
|
||||
{
|
||||
int rc = -ENOMEM;
|
||||
int rc;
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
|
||||
rc = -ENOMEM;
|
||||
*nclasses = policydb.p_classes.nprim;
|
||||
*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
|
||||
if (!*classes)
|
||||
@ -2630,7 +2624,7 @@ int security_get_classes(char ***classes, int *nclasses)
|
||||
|
||||
rc = hashtab_map(policydb.p_classes.table, get_classes_callback,
|
||||
*classes);
|
||||
if (rc < 0) {
|
||||
if (rc) {
|
||||
int i;
|
||||
for (i = 0; i < *nclasses; i++)
|
||||
kfree((*classes)[i]);
|
||||
@ -2657,19 +2651,20 @@ static int get_permissions_callback(void *k, void *d, void *args)
|
||||
|
||||
int security_get_permissions(char *class, char ***perms, int *nperms)
|
||||
{
|
||||
int rc = -ENOMEM, i;
|
||||
int rc, i;
|
||||
struct class_datum *match;
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
|
||||
rc = -EINVAL;
|
||||
match = hashtab_search(policydb.p_classes.table, class);
|
||||
if (!match) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized class %s\n",
|
||||
__func__, class);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = -ENOMEM;
|
||||
*nperms = match->permissions.nprim;
|
||||
*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
|
||||
if (!*perms)
|
||||
@ -2678,13 +2673,13 @@ int security_get_permissions(char *class, char ***perms, int *nperms)
|
||||
if (match->comdatum) {
|
||||
rc = hashtab_map(match->comdatum->permissions.table,
|
||||
get_permissions_callback, *perms);
|
||||
if (rc < 0)
|
||||
if (rc)
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = hashtab_map(match->permissions.table, get_permissions_callback,
|
||||
*perms);
|
||||
if (rc < 0)
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
out:
|
||||
@ -2796,36 +2791,39 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
|
||||
switch (field) {
|
||||
case AUDIT_SUBJ_USER:
|
||||
case AUDIT_OBJ_USER:
|
||||
rc = -EINVAL;
|
||||
userdatum = hashtab_search(policydb.p_users.table, rulestr);
|
||||
if (!userdatum)
|
||||
rc = -EINVAL;
|
||||
else
|
||||
tmprule->au_ctxt.user = userdatum->value;
|
||||
goto out;
|
||||
tmprule->au_ctxt.user = userdatum->value;
|
||||
break;
|
||||
case AUDIT_SUBJ_ROLE:
|
||||
case AUDIT_OBJ_ROLE:
|
||||
rc = -EINVAL;
|
||||
roledatum = hashtab_search(policydb.p_roles.table, rulestr);
|
||||
if (!roledatum)
|
||||
rc = -EINVAL;
|
||||
else
|
||||
tmprule->au_ctxt.role = roledatum->value;
|
||||
goto out;
|
||||
tmprule->au_ctxt.role = roledatum->value;
|
||||
break;
|
||||
case AUDIT_SUBJ_TYPE:
|
||||
case AUDIT_OBJ_TYPE:
|
||||
rc = -EINVAL;
|
||||
typedatum = hashtab_search(policydb.p_types.table, rulestr);
|
||||
if (!typedatum)
|
||||
rc = -EINVAL;
|
||||
else
|
||||
tmprule->au_ctxt.type = typedatum->value;
|
||||
goto out;
|
||||
tmprule->au_ctxt.type = typedatum->value;
|
||||
break;
|
||||
case AUDIT_SUBJ_SEN:
|
||||
case AUDIT_SUBJ_CLR:
|
||||
case AUDIT_OBJ_LEV_LOW:
|
||||
case AUDIT_OBJ_LEV_HIGH:
|
||||
rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
|
||||
if (rc)
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
read_unlock(&policy_rwlock);
|
||||
|
||||
if (rc) {
|
||||
@ -3050,7 +3048,7 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
|
||||
int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
|
||||
u32 *sid)
|
||||
{
|
||||
int rc = -EIDRM;
|
||||
int rc;
|
||||
struct context *ctx;
|
||||
struct context ctx_new;
|
||||
|
||||
@ -3061,16 +3059,15 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
|
||||
if (secattr->flags & NETLBL_SECATTR_CACHE) {
|
||||
if (secattr->flags & NETLBL_SECATTR_CACHE)
|
||||
*sid = *(u32 *)secattr->cache->data;
|
||||
rc = 0;
|
||||
} else if (secattr->flags & NETLBL_SECATTR_SECID) {
|
||||
else if (secattr->flags & NETLBL_SECATTR_SECID)
|
||||
*sid = secattr->attr.secid;
|
||||
rc = 0;
|
||||
} else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
|
||||
else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
|
||||
rc = -EIDRM;
|
||||
ctx = sidtab_search(&sidtab, SECINITSID_NETMSG);
|
||||
if (ctx == NULL)
|
||||
goto netlbl_secattr_to_sid_return;
|
||||
goto out;
|
||||
|
||||
context_init(&ctx_new);
|
||||
ctx_new.user = ctx->user;
|
||||
@ -3078,34 +3075,35 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
|
||||
ctx_new.type = ctx->type;
|
||||
mls_import_netlbl_lvl(&ctx_new, secattr);
|
||||
if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
|
||||
if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
|
||||
secattr->attr.mls.cat) != 0)
|
||||
goto netlbl_secattr_to_sid_return;
|
||||
rc = ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
|
||||
secattr->attr.mls.cat);
|
||||
if (rc)
|
||||
goto out;
|
||||
memcpy(&ctx_new.range.level[1].cat,
|
||||
&ctx_new.range.level[0].cat,
|
||||
sizeof(ctx_new.range.level[0].cat));
|
||||
}
|
||||
if (mls_context_isvalid(&policydb, &ctx_new) != 1)
|
||||
goto netlbl_secattr_to_sid_return_cleanup;
|
||||
rc = -EIDRM;
|
||||
if (!mls_context_isvalid(&policydb, &ctx_new))
|
||||
goto out_free;
|
||||
|
||||
rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
|
||||
if (rc != 0)
|
||||
goto netlbl_secattr_to_sid_return_cleanup;
|
||||
if (rc)
|
||||
goto out_free;
|
||||
|
||||
security_netlbl_cache_add(secattr, *sid);
|
||||
|
||||
ebitmap_destroy(&ctx_new.range.level[0].cat);
|
||||
} else {
|
||||
} else
|
||||
*sid = SECSID_NULL;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
netlbl_secattr_to_sid_return:
|
||||
read_unlock(&policy_rwlock);
|
||||
return 0;
|
||||
out_free:
|
||||
ebitmap_destroy(&ctx_new.range.level[0].cat);
|
||||
out:
|
||||
read_unlock(&policy_rwlock);
|
||||
return rc;
|
||||
netlbl_secattr_to_sid_return_cleanup:
|
||||
ebitmap_destroy(&ctx_new.range.level[0].cat);
|
||||
goto netlbl_secattr_to_sid_return;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3127,28 +3125,23 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
|
||||
return 0;
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
|
||||
rc = -ENOENT;
|
||||
ctx = sidtab_search(&sidtab, sid);
|
||||
if (ctx == NULL) {
|
||||
rc = -ENOENT;
|
||||
goto netlbl_sid_to_secattr_failure;
|
||||
}
|
||||
secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
|
||||
if (ctx == NULL)
|
||||
goto out;
|
||||
|
||||
rc = -ENOMEM;
|
||||
secattr->domain = kstrdup(sym_name(&policydb, SYM_TYPES, ctx->type - 1),
|
||||
GFP_ATOMIC);
|
||||
if (secattr->domain == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto netlbl_sid_to_secattr_failure;
|
||||
}
|
||||
if (secattr->domain == NULL)
|
||||
goto out;
|
||||
|
||||
secattr->attr.secid = sid;
|
||||
secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
|
||||
mls_export_netlbl_lvl(ctx, secattr);
|
||||
rc = mls_export_netlbl_cat(ctx, secattr);
|
||||
if (rc != 0)
|
||||
goto netlbl_sid_to_secattr_failure;
|
||||
read_unlock(&policy_rwlock);
|
||||
|
||||
return 0;
|
||||
|
||||
netlbl_sid_to_secattr_failure:
|
||||
out:
|
||||
read_unlock(&policy_rwlock);
|
||||
return rc;
|
||||
}
|
||||
|
@ -147,6 +147,17 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void sidtab_update_cache(struct sidtab *s, struct sidtab_node *n, int loc)
|
||||
{
|
||||
BUG_ON(loc >= SIDTAB_CACHE_LEN);
|
||||
|
||||
while (loc > 0) {
|
||||
s->cache[loc] = s->cache[loc - 1];
|
||||
loc--;
|
||||
}
|
||||
s->cache[0] = n;
|
||||
}
|
||||
|
||||
static inline u32 sidtab_search_context(struct sidtab *s,
|
||||
struct context *context)
|
||||
{
|
||||
@ -156,14 +167,33 @@ static inline u32 sidtab_search_context(struct sidtab *s,
|
||||
for (i = 0; i < SIDTAB_SIZE; i++) {
|
||||
cur = s->htable[i];
|
||||
while (cur) {
|
||||
if (context_cmp(&cur->context, context))
|
||||
if (context_cmp(&cur->context, context)) {
|
||||
sidtab_update_cache(s, cur, SIDTAB_CACHE_LEN - 1);
|
||||
return cur->sid;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 sidtab_search_cache(struct sidtab *s, struct context *context)
|
||||
{
|
||||
int i;
|
||||
struct sidtab_node *node;
|
||||
|
||||
for (i = 0; i < SIDTAB_CACHE_LEN; i++) {
|
||||
node = s->cache[i];
|
||||
if (unlikely(!node))
|
||||
return 0;
|
||||
if (context_cmp(&node->context, context)) {
|
||||
sidtab_update_cache(s, node, i);
|
||||
return node->sid;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sidtab_context_to_sid(struct sidtab *s,
|
||||
struct context *context,
|
||||
u32 *out_sid)
|
||||
@ -174,7 +204,9 @@ int sidtab_context_to_sid(struct sidtab *s,
|
||||
|
||||
*out_sid = SECSID_NULL;
|
||||
|
||||
sid = sidtab_search_context(s, context);
|
||||
sid = sidtab_search_cache(s, context);
|
||||
if (!sid)
|
||||
sid = sidtab_search_context(s, context);
|
||||
if (!sid) {
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
/* Rescan now that we hold the lock. */
|
||||
@ -259,12 +291,15 @@ void sidtab_destroy(struct sidtab *s)
|
||||
void sidtab_set(struct sidtab *dst, struct sidtab *src)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&src->lock, flags);
|
||||
dst->htable = src->htable;
|
||||
dst->nel = src->nel;
|
||||
dst->next_sid = src->next_sid;
|
||||
dst->shutdown = 0;
|
||||
for (i = 0; i < SIDTAB_CACHE_LEN; i++)
|
||||
dst->cache[i] = NULL;
|
||||
spin_unlock_irqrestore(&src->lock, flags);
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,8 @@ struct sidtab {
|
||||
unsigned int nel; /* number of elements */
|
||||
unsigned int next_sid; /* next SID to allocate */
|
||||
unsigned char shutdown;
|
||||
#define SIDTAB_CACHE_LEN 3
|
||||
struct sidtab_node *cache[SIDTAB_CACHE_LEN];
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
|
@ -51,11 +51,18 @@ struct socket_smack {
|
||||
*/
|
||||
struct inode_smack {
|
||||
char *smk_inode; /* label of the fso */
|
||||
char *smk_task; /* label of the task */
|
||||
struct mutex smk_lock; /* initialization lock */
|
||||
int smk_flags; /* smack inode flags */
|
||||
};
|
||||
|
||||
struct task_smack {
|
||||
char *smk_task; /* label used for access control */
|
||||
char *smk_forked; /* label when forked */
|
||||
};
|
||||
|
||||
#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
|
||||
#define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */
|
||||
|
||||
/*
|
||||
* A label access rule.
|
||||
@ -160,6 +167,10 @@ struct smack_known {
|
||||
#define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */
|
||||
#define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */
|
||||
|
||||
/*
|
||||
* Flag for transmute access
|
||||
*/
|
||||
#define MAY_TRANSMUTE 64
|
||||
/*
|
||||
* Just to make the common cases easier to deal with
|
||||
*/
|
||||
@ -191,6 +202,7 @@ struct inode_smack *new_inode_smack(char *);
|
||||
/*
|
||||
* These functions are in smack_access.c
|
||||
*/
|
||||
int smk_access_entry(char *, char *);
|
||||
int smk_access(char *, char *, int, struct smk_audit_info *);
|
||||
int smk_curacc(char *, u32, struct smk_audit_info *);
|
||||
int smack_to_cipso(const char *, struct smack_cipso *);
|
||||
@ -233,6 +245,15 @@ static inline void smack_catset_bit(int cat, char *catsetp)
|
||||
catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the directory transmuting?
|
||||
*/
|
||||
static inline int smk_inode_transmutable(const struct inode *isp)
|
||||
{
|
||||
struct inode_smack *sip = isp->i_security;
|
||||
return (sip->smk_flags & SMK_INODE_TRANSMUTE) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Present a pointer to the smack label in an inode blob.
|
||||
*/
|
||||
@ -242,6 +263,30 @@ static inline char *smk_of_inode(const struct inode *isp)
|
||||
return sip->smk_inode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Present a pointer to the smack label in an task blob.
|
||||
*/
|
||||
static inline char *smk_of_task(const struct task_smack *tsp)
|
||||
{
|
||||
return tsp->smk_task;
|
||||
}
|
||||
|
||||
/*
|
||||
* Present a pointer to the forked smack label in an task blob.
|
||||
*/
|
||||
static inline char *smk_of_forked(const struct task_smack *tsp)
|
||||
{
|
||||
return tsp->smk_forked;
|
||||
}
|
||||
|
||||
/*
|
||||
* Present a pointer to the smack label in the current task blob.
|
||||
*/
|
||||
static inline char *smk_of_current(void)
|
||||
{
|
||||
return smk_of_task(current_security());
|
||||
}
|
||||
|
||||
/*
|
||||
* logging functions
|
||||
*/
|
||||
|
@ -66,6 +66,46 @@ static u32 smack_next_secid = 10;
|
||||
*/
|
||||
int log_policy = SMACK_AUDIT_DENIED;
|
||||
|
||||
/**
|
||||
* smk_access_entry - look up matching access rule
|
||||
* @subject_label: a pointer to the subject's Smack label
|
||||
* @object_label: a pointer to the object's Smack label
|
||||
*
|
||||
* This function looks up the subject/object pair in the
|
||||
* access rule list and returns pointer to the matching rule if found,
|
||||
* NULL otherwise.
|
||||
*
|
||||
* NOTE:
|
||||
* Even though Smack labels are usually shared on smack_list
|
||||
* labels that come in off the network can't be imported
|
||||
* and added to the list for locking reasons.
|
||||
*
|
||||
* Therefore, it is necessary to check the contents of the labels,
|
||||
* not just the pointer values. Of course, in most cases the labels
|
||||
* will be on the list, so checking the pointers may be a worthwhile
|
||||
* optimization.
|
||||
*/
|
||||
int smk_access_entry(char *subject_label, char *object_label)
|
||||
{
|
||||
u32 may = MAY_NOT;
|
||||
struct smack_rule *srp;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(srp, &smack_rule_list, list) {
|
||||
if (srp->smk_subject == subject_label ||
|
||||
strcmp(srp->smk_subject, subject_label) == 0) {
|
||||
if (srp->smk_object == object_label ||
|
||||
strcmp(srp->smk_object, object_label) == 0) {
|
||||
may = srp->smk_access;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return may;
|
||||
}
|
||||
|
||||
/**
|
||||
* smk_access - determine if a subject has a specific access to an object
|
||||
* @subject_label: a pointer to the subject's Smack label
|
||||
@ -90,7 +130,6 @@ int smk_access(char *subject_label, char *object_label, int request,
|
||||
struct smk_audit_info *a)
|
||||
{
|
||||
u32 may = MAY_NOT;
|
||||
struct smack_rule *srp;
|
||||
int rc = 0;
|
||||
|
||||
/*
|
||||
@ -144,18 +183,7 @@ int smk_access(char *subject_label, char *object_label, int request,
|
||||
* access (e.g. read is included in readwrite) it's
|
||||
* good.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(srp, &smack_rule_list, list) {
|
||||
if (srp->smk_subject == subject_label ||
|
||||
strcmp(srp->smk_subject, subject_label) == 0) {
|
||||
if (srp->smk_object == object_label ||
|
||||
strcmp(srp->smk_object, object_label) == 0) {
|
||||
may = srp->smk_access;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
may = smk_access_entry(subject_label, object_label);
|
||||
/*
|
||||
* This is a bit map operation.
|
||||
*/
|
||||
@ -185,7 +213,7 @@ out_audit:
|
||||
int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
|
||||
{
|
||||
int rc;
|
||||
char *sp = current_security();
|
||||
char *sp = smk_of_current();
|
||||
|
||||
rc = smk_access(sp, obj_label, mode, NULL);
|
||||
if (rc == 0)
|
||||
@ -196,7 +224,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
|
||||
* only one that gets privilege and current does not
|
||||
* have that label.
|
||||
*/
|
||||
if (smack_onlycap != NULL && smack_onlycap != current->cred->security)
|
||||
if (smack_onlycap != NULL && smack_onlycap != sp)
|
||||
goto out_audit;
|
||||
|
||||
if (capable(CAP_MAC_OVERRIDE))
|
||||
|
@ -3,12 +3,14 @@
|
||||
*
|
||||
* This file contains the smack hook function implementations.
|
||||
*
|
||||
* Author:
|
||||
* Authors:
|
||||
* Casey Schaufler <casey@schaufler-ca.com>
|
||||
* Jarkko Sakkinen <ext-jarkko.2.sakkinen@nokia.com>
|
||||
*
|
||||
* Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
|
||||
* Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
|
||||
* Paul Moore <paul.moore@hp.com>
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
@ -35,6 +37,9 @@
|
||||
|
||||
#define task_security(task) (task_cred_xxx((task), security))
|
||||
|
||||
#define TRANS_TRUE "TRUE"
|
||||
#define TRANS_TRUE_SIZE 4
|
||||
|
||||
/**
|
||||
* smk_fetch - Fetch the smack label from a file.
|
||||
* @ip: a pointer to the inode
|
||||
@ -43,7 +48,7 @@
|
||||
* Returns a pointer to the master list entry for the Smack label
|
||||
* or NULL if there was no label to fetch.
|
||||
*/
|
||||
static char *smk_fetch(struct inode *ip, struct dentry *dp)
|
||||
static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp)
|
||||
{
|
||||
int rc;
|
||||
char in[SMK_LABELLEN];
|
||||
@ -51,7 +56,7 @@ static char *smk_fetch(struct inode *ip, struct dentry *dp)
|
||||
if (ip->i_op->getxattr == NULL)
|
||||
return NULL;
|
||||
|
||||
rc = ip->i_op->getxattr(dp, XATTR_NAME_SMACK, in, SMK_LABELLEN);
|
||||
rc = ip->i_op->getxattr(dp, name, in, SMK_LABELLEN);
|
||||
if (rc < 0)
|
||||
return NULL;
|
||||
|
||||
@ -103,8 +108,8 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
sp = current_security();
|
||||
tsp = task_security(ctp);
|
||||
sp = smk_of_current();
|
||||
tsp = smk_of_task(task_security(ctp));
|
||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
|
||||
smk_ad_setfield_u_tsk(&ad, ctp);
|
||||
|
||||
@ -138,8 +143,8 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
|
||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
|
||||
smk_ad_setfield_u_tsk(&ad, ptp);
|
||||
|
||||
sp = current_security();
|
||||
tsp = task_security(ptp);
|
||||
sp = smk_of_current();
|
||||
tsp = smk_of_task(task_security(ptp));
|
||||
/* we won't log here, because rc can be overriden */
|
||||
rc = smk_access(tsp, sp, MAY_READWRITE, NULL);
|
||||
if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE))
|
||||
@ -160,7 +165,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
|
||||
static int smack_syslog(int typefrom_file)
|
||||
{
|
||||
int rc = 0;
|
||||
char *sp = current_security();
|
||||
char *sp = smk_of_current();
|
||||
|
||||
if (capable(CAP_MAC_OVERRIDE))
|
||||
return 0;
|
||||
@ -390,6 +395,40 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
|
||||
return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
|
||||
}
|
||||
|
||||
/*
|
||||
* BPRM hooks
|
||||
*/
|
||||
|
||||
static int smack_bprm_set_creds(struct linux_binprm *bprm)
|
||||
{
|
||||
struct task_smack *tsp = bprm->cred->security;
|
||||
struct inode_smack *isp;
|
||||
struct dentry *dp;
|
||||
int rc;
|
||||
|
||||
rc = cap_bprm_set_creds(bprm);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (bprm->cred_prepared)
|
||||
return 0;
|
||||
|
||||
if (bprm->file == NULL || bprm->file->f_dentry == NULL)
|
||||
return 0;
|
||||
|
||||
dp = bprm->file->f_dentry;
|
||||
|
||||
if (dp->d_inode == NULL)
|
||||
return 0;
|
||||
|
||||
isp = dp->d_inode->i_security;
|
||||
|
||||
if (isp->smk_task != NULL)
|
||||
tsp->smk_task = isp->smk_task;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inode hooks
|
||||
*/
|
||||
@ -402,7 +441,7 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
|
||||
*/
|
||||
static int smack_inode_alloc_security(struct inode *inode)
|
||||
{
|
||||
inode->i_security = new_inode_smack(current_security());
|
||||
inode->i_security = new_inode_smack(smk_of_current());
|
||||
if (inode->i_security == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
@ -434,6 +473,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
char **name, void **value, size_t *len)
|
||||
{
|
||||
char *isp = smk_of_inode(inode);
|
||||
char *dsp = smk_of_inode(dir);
|
||||
u32 may;
|
||||
|
||||
if (name) {
|
||||
*name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL);
|
||||
@ -442,6 +483,16 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
}
|
||||
|
||||
if (value) {
|
||||
may = smk_access_entry(smk_of_current(), dsp);
|
||||
|
||||
/*
|
||||
* If the access rule allows transmutation and
|
||||
* the directory requests transmutation then
|
||||
* by all means transmute.
|
||||
*/
|
||||
if (((may & MAY_TRANSMUTE) != 0) && smk_inode_transmutable(dir))
|
||||
isp = dsp;
|
||||
|
||||
*value = kstrdup(isp, GFP_KERNEL);
|
||||
if (*value == NULL)
|
||||
return -ENOMEM;
|
||||
@ -664,7 +715,8 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
|
||||
if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
|
||||
strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
|
||||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
|
||||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
|
||||
strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
rc = -EPERM;
|
||||
/*
|
||||
@ -674,6 +726,12 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
if (size == 0 || size >= SMK_LABELLEN ||
|
||||
smk_import(value, size) == NULL)
|
||||
rc = -EINVAL;
|
||||
} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
rc = -EPERM;
|
||||
if (size != TRANS_TRUE_SIZE ||
|
||||
strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)
|
||||
rc = -EINVAL;
|
||||
} else
|
||||
rc = cap_inode_setxattr(dentry, name, value, size, flags);
|
||||
|
||||
@ -700,26 +758,23 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
struct inode_smack *isp;
|
||||
char *nsp;
|
||||
struct inode_smack *isp = dentry->d_inode->i_security;
|
||||
|
||||
/*
|
||||
* Not SMACK
|
||||
*/
|
||||
if (strcmp(name, XATTR_NAME_SMACK))
|
||||
return;
|
||||
|
||||
isp = dentry->d_inode->i_security;
|
||||
|
||||
/*
|
||||
* No locking is done here. This is a pointer
|
||||
* assignment.
|
||||
*/
|
||||
nsp = smk_import(value, size);
|
||||
if (nsp != NULL)
|
||||
isp->smk_inode = nsp;
|
||||
else
|
||||
isp->smk_inode = smack_known_invalid.smk_known;
|
||||
if (strcmp(name, XATTR_NAME_SMACK) == 0) {
|
||||
nsp = smk_import(value, size);
|
||||
if (nsp != NULL)
|
||||
isp->smk_inode = nsp;
|
||||
else
|
||||
isp->smk_inode = smack_known_invalid.smk_known;
|
||||
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
|
||||
nsp = smk_import(value, size);
|
||||
if (nsp != NULL)
|
||||
isp->smk_task = nsp;
|
||||
else
|
||||
isp->smk_task = smack_known_invalid.smk_known;
|
||||
} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0)
|
||||
isp->smk_flags |= SMK_INODE_TRANSMUTE;
|
||||
|
||||
return;
|
||||
}
|
||||
@ -752,12 +807,15 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
|
||||
*/
|
||||
static int smack_inode_removexattr(struct dentry *dentry, const char *name)
|
||||
{
|
||||
struct inode_smack *isp;
|
||||
struct smk_audit_info ad;
|
||||
int rc = 0;
|
||||
|
||||
if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
|
||||
strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
|
||||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
|
||||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
|
||||
strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
|
||||
strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
rc = -EPERM;
|
||||
} else
|
||||
@ -768,6 +826,11 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
|
||||
if (rc == 0)
|
||||
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
|
||||
|
||||
if (rc == 0) {
|
||||
isp = dentry->d_inode->i_security;
|
||||
isp->smk_task = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -895,7 +958,7 @@ static int smack_file_permission(struct file *file, int mask)
|
||||
*/
|
||||
static int smack_file_alloc_security(struct file *file)
|
||||
{
|
||||
file->f_security = current_security();
|
||||
file->f_security = smk_of_current();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1005,7 +1068,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
|
||||
*/
|
||||
static int smack_file_set_fowner(struct file *file)
|
||||
{
|
||||
file->f_security = current_security();
|
||||
file->f_security = smk_of_current();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1025,7 +1088,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
|
||||
{
|
||||
struct file *file;
|
||||
int rc;
|
||||
char *tsp = tsk->cred->security;
|
||||
char *tsp = smk_of_task(tsk->cred->security);
|
||||
struct smk_audit_info ad;
|
||||
|
||||
/*
|
||||
@ -1082,7 +1145,9 @@ static int smack_file_receive(struct file *file)
|
||||
*/
|
||||
static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
|
||||
{
|
||||
cred->security = NULL;
|
||||
cred->security = kzalloc(sizeof(struct task_smack), gfp);
|
||||
if (cred->security == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1097,7 +1162,7 @@ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
|
||||
*/
|
||||
static void smack_cred_free(struct cred *cred)
|
||||
{
|
||||
cred->security = NULL;
|
||||
kfree(cred->security);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1111,7 +1176,16 @@ static void smack_cred_free(struct cred *cred)
|
||||
static int smack_cred_prepare(struct cred *new, const struct cred *old,
|
||||
gfp_t gfp)
|
||||
{
|
||||
new->security = old->security;
|
||||
struct task_smack *old_tsp = old->security;
|
||||
struct task_smack *new_tsp;
|
||||
|
||||
new_tsp = kzalloc(sizeof(struct task_smack), gfp);
|
||||
if (new_tsp == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
new_tsp->smk_task = old_tsp->smk_task;
|
||||
new_tsp->smk_forked = old_tsp->smk_task;
|
||||
new->security = new_tsp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1124,7 +1198,11 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
|
||||
*/
|
||||
static void smack_cred_transfer(struct cred *new, const struct cred *old)
|
||||
{
|
||||
new->security = old->security;
|
||||
struct task_smack *old_tsp = old->security;
|
||||
struct task_smack *new_tsp = new->security;
|
||||
|
||||
new_tsp->smk_task = old_tsp->smk_task;
|
||||
new_tsp->smk_forked = old_tsp->smk_task;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1136,12 +1214,13 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old)
|
||||
*/
|
||||
static int smack_kernel_act_as(struct cred *new, u32 secid)
|
||||
{
|
||||
struct task_smack *new_tsp = new->security;
|
||||
char *smack = smack_from_secid(secid);
|
||||
|
||||
if (smack == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
new->security = smack;
|
||||
new_tsp->smk_task = smack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1157,8 +1236,10 @@ static int smack_kernel_create_files_as(struct cred *new,
|
||||
struct inode *inode)
|
||||
{
|
||||
struct inode_smack *isp = inode->i_security;
|
||||
struct task_smack *tsp = new->security;
|
||||
|
||||
new->security = isp->smk_inode;
|
||||
tsp->smk_forked = isp->smk_inode;
|
||||
tsp->smk_task = isp->smk_inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1175,7 +1256,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access)
|
||||
|
||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
|
||||
smk_ad_setfield_u_tsk(&ad, p);
|
||||
return smk_curacc(task_security(p), access, &ad);
|
||||
return smk_curacc(smk_of_task(task_security(p)), access, &ad);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1221,7 +1302,7 @@ static int smack_task_getsid(struct task_struct *p)
|
||||
*/
|
||||
static void smack_task_getsecid(struct task_struct *p, u32 *secid)
|
||||
{
|
||||
*secid = smack_to_secid(task_security(p));
|
||||
*secid = smack_to_secid(smk_of_task(task_security(p)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1333,14 +1414,15 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
|
||||
* can write the receiver.
|
||||
*/
|
||||
if (secid == 0)
|
||||
return smk_curacc(task_security(p), MAY_WRITE, &ad);
|
||||
return smk_curacc(smk_of_task(task_security(p)), MAY_WRITE,
|
||||
&ad);
|
||||
/*
|
||||
* If the secid isn't 0 we're dealing with some USB IO
|
||||
* specific behavior. This is not clean. For one thing
|
||||
* we can't take privilege into account.
|
||||
*/
|
||||
return smk_access(smack_from_secid(secid), task_security(p),
|
||||
MAY_WRITE, &ad);
|
||||
return smk_access(smack_from_secid(secid),
|
||||
smk_of_task(task_security(p)), MAY_WRITE, &ad);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1352,12 +1434,12 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
|
||||
static int smack_task_wait(struct task_struct *p)
|
||||
{
|
||||
struct smk_audit_info ad;
|
||||
char *sp = current_security();
|
||||
char *tsp = task_security(p);
|
||||
char *sp = smk_of_current();
|
||||
char *tsp = smk_of_forked(task_security(p));
|
||||
int rc;
|
||||
|
||||
/* we don't log here, we can be overriden */
|
||||
rc = smk_access(sp, tsp, MAY_WRITE, NULL);
|
||||
rc = smk_access(tsp, sp, MAY_WRITE, NULL);
|
||||
if (rc == 0)
|
||||
goto out_log;
|
||||
|
||||
@ -1378,7 +1460,7 @@ static int smack_task_wait(struct task_struct *p)
|
||||
out_log:
|
||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
|
||||
smk_ad_setfield_u_tsk(&ad, p);
|
||||
smack_log(sp, tsp, MAY_WRITE, rc, &ad);
|
||||
smack_log(tsp, sp, MAY_WRITE, rc, &ad);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1392,7 +1474,7 @@ static int smack_task_wait(struct task_struct *p)
|
||||
static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
|
||||
{
|
||||
struct inode_smack *isp = inode->i_security;
|
||||
isp->smk_inode = task_security(p);
|
||||
isp->smk_inode = smk_of_task(task_security(p));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1411,7 +1493,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
|
||||
*/
|
||||
static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
|
||||
{
|
||||
char *csp = current_security();
|
||||
char *csp = smk_of_current();
|
||||
struct socket_smack *ssp;
|
||||
|
||||
ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
|
||||
@ -1667,10 +1749,13 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
|
||||
ssp->smk_in = sp;
|
||||
else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
|
||||
ssp->smk_out = sp;
|
||||
rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
|
||||
__func__, -rc);
|
||||
if (sock->sk->sk_family != PF_UNIX) {
|
||||
rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING
|
||||
"Smack: \"%s\" netlbl error %d.\n",
|
||||
__func__, -rc);
|
||||
}
|
||||
} else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@ -1749,7 +1834,7 @@ static int smack_flags_to_may(int flags)
|
||||
*/
|
||||
static int smack_msg_msg_alloc_security(struct msg_msg *msg)
|
||||
{
|
||||
msg->security = current_security();
|
||||
msg->security = smk_of_current();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1785,7 +1870,7 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp)
|
||||
{
|
||||
struct kern_ipc_perm *isp = &shp->shm_perm;
|
||||
|
||||
isp->security = current_security();
|
||||
isp->security = smk_of_current();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1908,7 +1993,7 @@ static int smack_sem_alloc_security(struct sem_array *sma)
|
||||
{
|
||||
struct kern_ipc_perm *isp = &sma->sem_perm;
|
||||
|
||||
isp->security = current_security();
|
||||
isp->security = smk_of_current();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2026,7 +2111,7 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq)
|
||||
{
|
||||
struct kern_ipc_perm *kisp = &msq->q_perm;
|
||||
|
||||
kisp->security = current_security();
|
||||
kisp->security = smk_of_current();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2198,9 +2283,11 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||
struct super_block *sbp;
|
||||
struct superblock_smack *sbsp;
|
||||
struct inode_smack *isp;
|
||||
char *csp = current_security();
|
||||
char *csp = smk_of_current();
|
||||
char *fetched;
|
||||
char *final;
|
||||
char trattr[TRANS_TRUE_SIZE];
|
||||
int transflag = 0;
|
||||
struct dentry *dp;
|
||||
|
||||
if (inode == NULL)
|
||||
@ -2267,9 +2354,10 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||
break;
|
||||
case SOCKFS_MAGIC:
|
||||
/*
|
||||
* Casey says sockets get the smack of the task.
|
||||
* Socket access is controlled by the socket
|
||||
* structures associated with the task involved.
|
||||
*/
|
||||
final = csp;
|
||||
final = smack_known_star.smk_known;
|
||||
break;
|
||||
case PROC_SUPER_MAGIC:
|
||||
/*
|
||||
@ -2296,7 +2384,16 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||
/*
|
||||
* This isn't an understood special case.
|
||||
* Get the value from the xattr.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* UNIX domain sockets use lower level socket data.
|
||||
*/
|
||||
if (S_ISSOCK(inode->i_mode)) {
|
||||
final = smack_known_star.smk_known;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* No xattr support means, alas, no SMACK label.
|
||||
* Use the aforeapplied default.
|
||||
* It would be curious if the label of the task
|
||||
@ -2308,9 +2405,21 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||
* Get the dentry for xattr.
|
||||
*/
|
||||
dp = dget(opt_dentry);
|
||||
fetched = smk_fetch(inode, dp);
|
||||
if (fetched != NULL)
|
||||
fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp);
|
||||
if (fetched != NULL) {
|
||||
final = fetched;
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
trattr[0] = '\0';
|
||||
inode->i_op->getxattr(dp,
|
||||
XATTR_NAME_SMACKTRANSMUTE,
|
||||
trattr, TRANS_TRUE_SIZE);
|
||||
if (strncmp(trattr, TRANS_TRUE,
|
||||
TRANS_TRUE_SIZE) == 0)
|
||||
transflag = SMK_INODE_TRANSMUTE;
|
||||
}
|
||||
}
|
||||
isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp);
|
||||
|
||||
dput(dp);
|
||||
break;
|
||||
}
|
||||
@ -2320,7 +2429,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||
else
|
||||
isp->smk_inode = final;
|
||||
|
||||
isp->smk_flags |= SMK_INODE_INSTANT;
|
||||
isp->smk_flags |= (SMK_INODE_INSTANT | transflag);
|
||||
|
||||
unlockandout:
|
||||
mutex_unlock(&isp->smk_lock);
|
||||
@ -2345,7 +2454,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
|
||||
if (strcmp(name, "current") != 0)
|
||||
return -EINVAL;
|
||||
|
||||
cp = kstrdup(task_security(p), GFP_KERNEL);
|
||||
cp = kstrdup(smk_of_task(task_security(p)), GFP_KERNEL);
|
||||
if (cp == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -2369,6 +2478,8 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
|
||||
static int smack_setprocattr(struct task_struct *p, char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
struct task_smack *tsp;
|
||||
struct task_smack *oldtsp;
|
||||
struct cred *new;
|
||||
char *newsmack;
|
||||
|
||||
@ -2398,10 +2509,18 @@ static int smack_setprocattr(struct task_struct *p, char *name,
|
||||
if (newsmack == smack_known_web.smk_known)
|
||||
return -EPERM;
|
||||
|
||||
oldtsp = p->cred->security;
|
||||
new = prepare_creds();
|
||||
if (new == NULL)
|
||||
return -ENOMEM;
|
||||
new->security = newsmack;
|
||||
tsp = kzalloc(sizeof(struct task_smack), GFP_KERNEL);
|
||||
if (tsp == NULL) {
|
||||
kfree(new);
|
||||
return -ENOMEM;
|
||||
}
|
||||
tsp->smk_task = newsmack;
|
||||
tsp->smk_forked = oldtsp->smk_forked;
|
||||
new->security = tsp;
|
||||
commit_creds(new);
|
||||
return size;
|
||||
}
|
||||
@ -2418,14 +2537,18 @@ static int smack_setprocattr(struct task_struct *p, char *name,
|
||||
static int smack_unix_stream_connect(struct sock *sock,
|
||||
struct sock *other, struct sock *newsk)
|
||||
{
|
||||
struct inode *sp = SOCK_INODE(sock->sk_socket);
|
||||
struct inode *op = SOCK_INODE(other->sk_socket);
|
||||
struct socket_smack *ssp = sock->sk_security;
|
||||
struct socket_smack *osp = other->sk_security;
|
||||
struct smk_audit_info ad;
|
||||
int rc = 0;
|
||||
|
||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
|
||||
smk_ad_setfield_u_net_sk(&ad, other);
|
||||
return smk_access(smk_of_inode(sp), smk_of_inode(op),
|
||||
MAY_READWRITE, &ad);
|
||||
|
||||
if (!capable(CAP_MAC_OVERRIDE))
|
||||
rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2438,13 +2561,18 @@ static int smack_unix_stream_connect(struct sock *sock,
|
||||
*/
|
||||
static int smack_unix_may_send(struct socket *sock, struct socket *other)
|
||||
{
|
||||
struct inode *sp = SOCK_INODE(sock);
|
||||
struct inode *op = SOCK_INODE(other);
|
||||
struct socket_smack *ssp = sock->sk->sk_security;
|
||||
struct socket_smack *osp = other->sk->sk_security;
|
||||
struct smk_audit_info ad;
|
||||
int rc = 0;
|
||||
|
||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
|
||||
smk_ad_setfield_u_net_sk(&ad, other->sk);
|
||||
return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE, &ad);
|
||||
|
||||
if (!capable(CAP_MAC_OVERRIDE))
|
||||
rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2629,7 +2757,7 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
|
||||
|
||||
/**
|
||||
* smack_socket_getpeersec_dgram - pull in packet label
|
||||
* @sock: the socket
|
||||
* @sock: the peer socket
|
||||
* @skb: packet data
|
||||
* @secid: pointer to where to put the secid of the packet
|
||||
*
|
||||
@ -2640,41 +2768,39 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
|
||||
|
||||
{
|
||||
struct netlbl_lsm_secattr secattr;
|
||||
struct sock *sk;
|
||||
struct socket_smack *sp;
|
||||
char smack[SMK_LABELLEN];
|
||||
int family = PF_INET;
|
||||
u32 s;
|
||||
int family = PF_UNSPEC;
|
||||
u32 s = 0; /* 0 is the invalid secid */
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Only works for families with packets.
|
||||
*/
|
||||
if (sock != NULL) {
|
||||
sk = sock->sk;
|
||||
if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
|
||||
return 0;
|
||||
family = sk->sk_family;
|
||||
if (skb != NULL) {
|
||||
if (skb->protocol == htons(ETH_P_IP))
|
||||
family = PF_INET;
|
||||
else if (skb->protocol == htons(ETH_P_IPV6))
|
||||
family = PF_INET6;
|
||||
}
|
||||
/*
|
||||
* Translate what netlabel gave us.
|
||||
*/
|
||||
netlbl_secattr_init(&secattr);
|
||||
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||
if (rc == 0)
|
||||
smack_from_secattr(&secattr, smack);
|
||||
netlbl_secattr_destroy(&secattr);
|
||||
if (family == PF_UNSPEC && sock != NULL)
|
||||
family = sock->sk->sk_family;
|
||||
|
||||
/*
|
||||
* Give up if we couldn't get anything
|
||||
*/
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
s = smack_to_secid(smack);
|
||||
if (family == PF_UNIX) {
|
||||
sp = sock->sk->sk_security;
|
||||
s = smack_to_secid(sp->smk_out);
|
||||
} else if (family == PF_INET || family == PF_INET6) {
|
||||
/*
|
||||
* Translate what netlabel gave us.
|
||||
*/
|
||||
netlbl_secattr_init(&secattr);
|
||||
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||
if (rc == 0) {
|
||||
smack_from_secattr(&secattr, smack);
|
||||
s = smack_to_secid(smack);
|
||||
}
|
||||
netlbl_secattr_destroy(&secattr);
|
||||
}
|
||||
*secid = s;
|
||||
if (s == 0)
|
||||
return -EINVAL;
|
||||
|
||||
*secid = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2695,7 +2821,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
|
||||
return;
|
||||
|
||||
ssp = sk->sk_security;
|
||||
ssp->smk_in = ssp->smk_out = current_security();
|
||||
ssp->smk_in = ssp->smk_out = smk_of_current();
|
||||
/* cssp->smk_packet is already set in smack_inet_csk_clone() */
|
||||
}
|
||||
|
||||
@ -2816,7 +2942,7 @@ static void smack_inet_csk_clone(struct sock *sk,
|
||||
static int smack_key_alloc(struct key *key, const struct cred *cred,
|
||||
unsigned long flags)
|
||||
{
|
||||
key->security = cred->security;
|
||||
key->security = smk_of_task(cred->security);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2845,6 +2971,7 @@ static int smack_key_permission(key_ref_t key_ref,
|
||||
{
|
||||
struct key *keyp;
|
||||
struct smk_audit_info ad;
|
||||
char *tsp = smk_of_task(cred->security);
|
||||
|
||||
keyp = key_ref_to_ptr(key_ref);
|
||||
if (keyp == NULL)
|
||||
@ -2858,14 +2985,14 @@ static int smack_key_permission(key_ref_t key_ref,
|
||||
/*
|
||||
* This should not occur
|
||||
*/
|
||||
if (cred->security == NULL)
|
||||
if (tsp == NULL)
|
||||
return -EACCES;
|
||||
#ifdef CONFIG_AUDIT
|
||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY);
|
||||
ad.a.u.key_struct.key = keyp->serial;
|
||||
ad.a.u.key_struct.key_desc = keyp->description;
|
||||
#endif
|
||||
return smk_access(cred->security, keyp->security,
|
||||
return smk_access(tsp, keyp->security,
|
||||
MAY_READWRITE, &ad);
|
||||
}
|
||||
#endif /* CONFIG_KEYS */
|
||||
@ -3067,6 +3194,8 @@ struct security_operations smack_ops = {
|
||||
.sb_mount = smack_sb_mount,
|
||||
.sb_umount = smack_sb_umount,
|
||||
|
||||
.bprm_set_creds = smack_bprm_set_creds,
|
||||
|
||||
.inode_alloc_security = smack_inode_alloc_security,
|
||||
.inode_free_security = smack_inode_free_security,
|
||||
.inode_init_security = smack_inode_init_security,
|
||||
@ -3203,9 +3332,16 @@ static __init void init_smack_know_list(void)
|
||||
static __init int smack_init(void)
|
||||
{
|
||||
struct cred *cred;
|
||||
struct task_smack *tsp;
|
||||
|
||||
if (!security_module_enable(&smack_ops))
|
||||
tsp = kzalloc(sizeof(struct task_smack), GFP_KERNEL);
|
||||
if (tsp == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!security_module_enable(&smack_ops)) {
|
||||
kfree(tsp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "Smack: Initializing.\n");
|
||||
|
||||
@ -3213,7 +3349,9 @@ static __init int smack_init(void)
|
||||
* Set the security state for the initial task.
|
||||
*/
|
||||
cred = (struct cred *) current->cred;
|
||||
cred->security = &smack_known_floor.smk_known;
|
||||
tsp->smk_forked = smack_known_floor.smk_known;
|
||||
tsp->smk_task = smack_known_floor.smk_known;
|
||||
cred->security = tsp;
|
||||
|
||||
/* initialize the smack_know_list */
|
||||
init_smack_know_list();
|
||||
|
@ -109,9 +109,12 @@ const char *smack_cipso_option = SMACK_CIPSO_OPTION;
|
||||
* SMK_ACCESSLEN: Maximum length for a rule access field
|
||||
* SMK_LOADLEN: Smack rule length
|
||||
*/
|
||||
#define SMK_ACCESS "rwxa"
|
||||
#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1)
|
||||
#define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN)
|
||||
#define SMK_OACCESS "rwxa"
|
||||
#define SMK_ACCESS "rwxat"
|
||||
#define SMK_OACCESSLEN (sizeof(SMK_OACCESS) - 1)
|
||||
#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1)
|
||||
#define SMK_OLOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_OACCESSLEN)
|
||||
#define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN)
|
||||
|
||||
/**
|
||||
* smk_netlabel_audit_set - fill a netlbl_audit struct
|
||||
@ -121,7 +124,7 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap)
|
||||
{
|
||||
nap->loginuid = audit_get_loginuid(current);
|
||||
nap->sessionid = audit_get_sessionid(current);
|
||||
nap->secid = smack_to_secid(current_security());
|
||||
nap->secid = smack_to_secid(smk_of_current());
|
||||
}
|
||||
|
||||
/*
|
||||
@ -175,6 +178,8 @@ static int load_seq_show(struct seq_file *s, void *v)
|
||||
seq_putc(s, 'x');
|
||||
if (srp->smk_access & MAY_APPEND)
|
||||
seq_putc(s, 'a');
|
||||
if (srp->smk_access & MAY_TRANSMUTE)
|
||||
seq_putc(s, 't');
|
||||
if (srp->smk_access == 0)
|
||||
seq_putc(s, '-');
|
||||
|
||||
@ -273,10 +278,15 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (*ppos != 0 || count != SMK_LOADLEN)
|
||||
if (*ppos != 0)
|
||||
return -EINVAL;
|
||||
/*
|
||||
* Minor hack for backward compatability
|
||||
*/
|
||||
if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN)
|
||||
return -EINVAL;
|
||||
|
||||
data = kzalloc(count, GFP_KERNEL);
|
||||
data = kzalloc(SMK_LOADLEN, GFP_KERNEL);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -285,6 +295,12 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* More on the minor hack for backward compatability
|
||||
*/
|
||||
if (count == (SMK_OLOADLEN))
|
||||
data[SMK_OLOADLEN] = '-';
|
||||
|
||||
rule = kzalloc(sizeof(*rule), GFP_KERNEL);
|
||||
if (rule == NULL) {
|
||||
rc = -ENOMEM;
|
||||
@ -345,6 +361,17 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
||||
goto out_free_rule;
|
||||
}
|
||||
|
||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) {
|
||||
case '-':
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
rule->smk_access |= MAY_TRANSMUTE;
|
||||
break;
|
||||
default:
|
||||
goto out_free_rule;
|
||||
}
|
||||
|
||||
rc = smk_set_access(rule);
|
||||
|
||||
if (!rc)
|
||||
@ -1160,7 +1187,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char in[SMK_LABELLEN];
|
||||
char *sp = current->cred->security;
|
||||
char *sp = smk_of_task(current->cred->security);
|
||||
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
return -EPERM;
|
||||
|
Loading…
Reference in New Issue
Block a user