diff options
Diffstat (limited to 'security')
| -rw-r--r-- | security/integrity/ima/ima.h | 7 | ||||
| -rw-r--r-- | security/integrity/ima/ima_api.c | 22 | ||||
| -rw-r--r-- | security/integrity/ima/ima_crypto.c | 17 | ||||
| -rw-r--r-- | security/integrity/ima/ima_fs.c | 14 | ||||
| -rw-r--r-- | security/integrity/ima/ima_init.c | 3 | ||||
| -rw-r--r-- | security/integrity/ima/ima_template.c | 21 | ||||
| -rw-r--r-- | security/integrity/ima/ima_template_lib.c | 6 | ||||
| -rw-r--r-- | security/keys/big_key.c | 2 | ||||
| -rw-r--r-- | security/keys/key.c | 8 | ||||
| -rw-r--r-- | security/keys/keyring.c | 17 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 185 | ||||
| -rw-r--r-- | security/selinux/include/xfrm.h | 8 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 42 | ||||
| -rw-r--r-- | security/selinux/xfrm.c | 62 |
14 files changed, 269 insertions, 145 deletions
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index bf03c6a16cc8..0356e1d437ca 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
| @@ -26,7 +26,8 @@ | |||
| 26 | 26 | ||
| 27 | #include "../integrity.h" | 27 | #include "../integrity.h" |
| 28 | 28 | ||
| 29 | enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_ASCII }; | 29 | enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN, |
| 30 | IMA_SHOW_ASCII }; | ||
| 30 | enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; | 31 | enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; |
| 31 | 32 | ||
| 32 | /* digest size for IMA, fits SHA1 or MD5 */ | 33 | /* digest size for IMA, fits SHA1 or MD5 */ |
| @@ -97,7 +98,8 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, | |||
| 97 | const char *op, struct inode *inode, | 98 | const char *op, struct inode *inode, |
| 98 | const unsigned char *filename); | 99 | const unsigned char *filename); |
| 99 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash); | 100 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash); |
| 100 | int ima_calc_field_array_hash(struct ima_field_data *field_data, int num_fields, | 101 | int ima_calc_field_array_hash(struct ima_field_data *field_data, |
| 102 | struct ima_template_desc *desc, int num_fields, | ||
| 101 | struct ima_digest_data *hash); | 103 | struct ima_digest_data *hash); |
| 102 | int __init ima_calc_boot_aggregate(struct ima_digest_data *hash); | 104 | int __init ima_calc_boot_aggregate(struct ima_digest_data *hash); |
| 103 | void ima_add_violation(struct file *file, const unsigned char *filename, | 105 | void ima_add_violation(struct file *file, const unsigned char *filename, |
| @@ -146,6 +148,7 @@ int ima_alloc_init_template(struct integrity_iint_cache *iint, | |||
| 146 | int xattr_len, struct ima_template_entry **entry); | 148 | int xattr_len, struct ima_template_entry **entry); |
| 147 | int ima_store_template(struct ima_template_entry *entry, int violation, | 149 | int ima_store_template(struct ima_template_entry *entry, int violation, |
| 148 | struct inode *inode, const unsigned char *filename); | 150 | struct inode *inode, const unsigned char *filename); |
| 151 | void ima_free_template_entry(struct ima_template_entry *entry); | ||
| 149 | const char *ima_d_path(struct path *path, char **pathbuf); | 152 | const char *ima_d_path(struct path *path, char **pathbuf); |
| 150 | 153 | ||
| 151 | /* rbtree tree calls to lookup, insert, delete | 154 | /* rbtree tree calls to lookup, insert, delete |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 0e7540863fc2..c38bbce8c6a6 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
| @@ -22,6 +22,19 @@ | |||
| 22 | #include "ima.h" | 22 | #include "ima.h" |
| 23 | 23 | ||
| 24 | /* | 24 | /* |
| 25 | * ima_free_template_entry - free an existing template entry | ||
| 26 | */ | ||
| 27 | void ima_free_template_entry(struct ima_template_entry *entry) | ||
| 28 | { | ||
| 29 | int i; | ||
| 30 | |||
| 31 | for (i = 0; i < entry->template_desc->num_fields; i++) | ||
| 32 | kfree(entry->template_data[i].data); | ||
| 33 | |||
| 34 | kfree(entry); | ||
| 35 | } | ||
| 36 | |||
| 37 | /* | ||
| 25 | * ima_alloc_init_template - create and initialize a new template entry | 38 | * ima_alloc_init_template - create and initialize a new template entry |
| 26 | */ | 39 | */ |
| 27 | int ima_alloc_init_template(struct integrity_iint_cache *iint, | 40 | int ima_alloc_init_template(struct integrity_iint_cache *iint, |
| @@ -37,6 +50,7 @@ int ima_alloc_init_template(struct integrity_iint_cache *iint, | |||
| 37 | if (!*entry) | 50 | if (!*entry) |
| 38 | return -ENOMEM; | 51 | return -ENOMEM; |
| 39 | 52 | ||
| 53 | (*entry)->template_desc = template_desc; | ||
| 40 | for (i = 0; i < template_desc->num_fields; i++) { | 54 | for (i = 0; i < template_desc->num_fields; i++) { |
| 41 | struct ima_template_field *field = template_desc->fields[i]; | 55 | struct ima_template_field *field = template_desc->fields[i]; |
| 42 | u32 len; | 56 | u32 len; |
| @@ -51,10 +65,9 @@ int ima_alloc_init_template(struct integrity_iint_cache *iint, | |||
| 51 | (*entry)->template_data_len += sizeof(len); | 65 | (*entry)->template_data_len += sizeof(len); |
| 52 | (*entry)->template_data_len += len; | 66 | (*entry)->template_data_len += len; |
| 53 | } | 67 | } |
| 54 | (*entry)->template_desc = template_desc; | ||
| 55 | return 0; | 68 | return 0; |
| 56 | out: | 69 | out: |
| 57 | kfree(*entry); | 70 | ima_free_template_entry(*entry); |
| 58 | *entry = NULL; | 71 | *entry = NULL; |
| 59 | return result; | 72 | return result; |
| 60 | } | 73 | } |
| @@ -94,6 +107,7 @@ int ima_store_template(struct ima_template_entry *entry, | |||
| 94 | /* this function uses default algo */ | 107 | /* this function uses default algo */ |
| 95 | hash.hdr.algo = HASH_ALGO_SHA1; | 108 | hash.hdr.algo = HASH_ALGO_SHA1; |
| 96 | result = ima_calc_field_array_hash(&entry->template_data[0], | 109 | result = ima_calc_field_array_hash(&entry->template_data[0], |
| 110 | entry->template_desc, | ||
| 97 | num_fields, &hash.hdr); | 111 | num_fields, &hash.hdr); |
| 98 | if (result < 0) { | 112 | if (result < 0) { |
| 99 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, | 113 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, |
| @@ -133,7 +147,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, | |||
| 133 | } | 147 | } |
| 134 | result = ima_store_template(entry, violation, inode, filename); | 148 | result = ima_store_template(entry, violation, inode, filename); |
| 135 | if (result < 0) | 149 | if (result < 0) |
| 136 | kfree(entry); | 150 | ima_free_template_entry(entry); |
| 137 | err_out: | 151 | err_out: |
| 138 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, | 152 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, |
| 139 | op, cause, result, 0); | 153 | op, cause, result, 0); |
| @@ -268,7 +282,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, | |||
| 268 | if (!result || result == -EEXIST) | 282 | if (!result || result == -EEXIST) |
| 269 | iint->flags |= IMA_MEASURED; | 283 | iint->flags |= IMA_MEASURED; |
| 270 | if (result < 0) | 284 | if (result < 0) |
| 271 | kfree(entry); | 285 | ima_free_template_entry(entry); |
| 272 | } | 286 | } |
| 273 | 287 | ||
| 274 | void ima_audit_measurement(struct integrity_iint_cache *iint, | 288 | void ima_audit_measurement(struct integrity_iint_cache *iint, |
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 676e0292dfec..fdf60def52e9 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
| @@ -140,6 +140,7 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) | |||
| 140 | * Calculate the hash of template data | 140 | * Calculate the hash of template data |
| 141 | */ | 141 | */ |
| 142 | static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, | 142 | static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, |
| 143 | struct ima_template_desc *td, | ||
| 143 | int num_fields, | 144 | int num_fields, |
| 144 | struct ima_digest_data *hash, | 145 | struct ima_digest_data *hash, |
| 145 | struct crypto_shash *tfm) | 146 | struct crypto_shash *tfm) |
| @@ -160,9 +161,13 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, | |||
| 160 | return rc; | 161 | return rc; |
| 161 | 162 | ||
| 162 | for (i = 0; i < num_fields; i++) { | 163 | for (i = 0; i < num_fields; i++) { |
| 163 | rc = crypto_shash_update(&desc.shash, | 164 | if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) { |
| 164 | (const u8 *) &field_data[i].len, | 165 | rc = crypto_shash_update(&desc.shash, |
| 165 | sizeof(field_data[i].len)); | 166 | (const u8 *) &field_data[i].len, |
| 167 | sizeof(field_data[i].len)); | ||
| 168 | if (rc) | ||
| 169 | break; | ||
| 170 | } | ||
| 166 | rc = crypto_shash_update(&desc.shash, field_data[i].data, | 171 | rc = crypto_shash_update(&desc.shash, field_data[i].data, |
| 167 | field_data[i].len); | 172 | field_data[i].len); |
| 168 | if (rc) | 173 | if (rc) |
| @@ -175,7 +180,8 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, | |||
| 175 | return rc; | 180 | return rc; |
| 176 | } | 181 | } |
| 177 | 182 | ||
| 178 | int ima_calc_field_array_hash(struct ima_field_data *field_data, int num_fields, | 183 | int ima_calc_field_array_hash(struct ima_field_data *field_data, |
| 184 | struct ima_template_desc *desc, int num_fields, | ||
| 179 | struct ima_digest_data *hash) | 185 | struct ima_digest_data *hash) |
| 180 | { | 186 | { |
| 181 | struct crypto_shash *tfm; | 187 | struct crypto_shash *tfm; |
| @@ -185,7 +191,8 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data, int num_fields, | |||
| 185 | if (IS_ERR(tfm)) | 191 | if (IS_ERR(tfm)) |
| 186 | return PTR_ERR(tfm); | 192 | return PTR_ERR(tfm); |
| 187 | 193 | ||
| 188 | rc = ima_calc_field_array_hash_tfm(field_data, num_fields, hash, tfm); | 194 | rc = ima_calc_field_array_hash_tfm(field_data, desc, num_fields, |
| 195 | hash, tfm); | ||
| 189 | 196 | ||
| 190 | ima_free_tfm(tfm); | 197 | ima_free_tfm(tfm); |
| 191 | 198 | ||
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index d47a7c86a21d..db01125926bd 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c | |||
| @@ -120,6 +120,7 @@ static int ima_measurements_show(struct seq_file *m, void *v) | |||
| 120 | struct ima_template_entry *e; | 120 | struct ima_template_entry *e; |
| 121 | int namelen; | 121 | int namelen; |
| 122 | u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; | 122 | u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; |
| 123 | bool is_ima_template = false; | ||
| 123 | int i; | 124 | int i; |
| 124 | 125 | ||
| 125 | /* get entry */ | 126 | /* get entry */ |
| @@ -145,14 +146,21 @@ static int ima_measurements_show(struct seq_file *m, void *v) | |||
| 145 | ima_putc(m, e->template_desc->name, namelen); | 146 | ima_putc(m, e->template_desc->name, namelen); |
| 146 | 147 | ||
| 147 | /* 5th: template length (except for 'ima' template) */ | 148 | /* 5th: template length (except for 'ima' template) */ |
| 148 | if (strcmp(e->template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) | 149 | if (strcmp(e->template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) |
| 150 | is_ima_template = true; | ||
| 151 | |||
| 152 | if (!is_ima_template) | ||
| 149 | ima_putc(m, &e->template_data_len, | 153 | ima_putc(m, &e->template_data_len, |
| 150 | sizeof(e->template_data_len)); | 154 | sizeof(e->template_data_len)); |
| 151 | 155 | ||
| 152 | /* 6th: template specific data */ | 156 | /* 6th: template specific data */ |
| 153 | for (i = 0; i < e->template_desc->num_fields; i++) { | 157 | for (i = 0; i < e->template_desc->num_fields; i++) { |
| 154 | e->template_desc->fields[i]->field_show(m, IMA_SHOW_BINARY, | 158 | enum ima_show_type show = IMA_SHOW_BINARY; |
| 155 | &e->template_data[i]); | 159 | struct ima_template_field *field = e->template_desc->fields[i]; |
| 160 | |||
| 161 | if (is_ima_template && strcmp(field->field_id, "d") == 0) | ||
| 162 | show = IMA_SHOW_BINARY_NO_FIELD_LEN; | ||
| 163 | field->field_show(m, show, &e->template_data[i]); | ||
| 156 | } | 164 | } |
| 157 | return 0; | 165 | return 0; |
| 158 | } | 166 | } |
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 15f34bd40abe..37122768554a 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c | |||
| @@ -63,7 +63,6 @@ static void __init ima_add_boot_aggregate(void) | |||
| 63 | result = ima_calc_boot_aggregate(&hash.hdr); | 63 | result = ima_calc_boot_aggregate(&hash.hdr); |
| 64 | if (result < 0) { | 64 | if (result < 0) { |
| 65 | audit_cause = "hashing_error"; | 65 | audit_cause = "hashing_error"; |
| 66 | kfree(entry); | ||
| 67 | goto err_out; | 66 | goto err_out; |
| 68 | } | 67 | } |
| 69 | } | 68 | } |
| @@ -76,7 +75,7 @@ static void __init ima_add_boot_aggregate(void) | |||
| 76 | result = ima_store_template(entry, violation, NULL, | 75 | result = ima_store_template(entry, violation, NULL, |
| 77 | boot_aggregate_name); | 76 | boot_aggregate_name); |
| 78 | if (result < 0) | 77 | if (result < 0) |
| 79 | kfree(entry); | 78 | ima_free_template_entry(entry); |
| 80 | return; | 79 | return; |
| 81 | err_out: | 80 | err_out: |
| 82 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op, | 81 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op, |
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 4e5da990630b..635695f6a185 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c | |||
| @@ -90,7 +90,7 @@ static struct ima_template_field *lookup_template_field(const char *field_id) | |||
| 90 | return NULL; | 90 | return NULL; |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | static int template_fmt_size(char *template_fmt) | 93 | static int template_fmt_size(const char *template_fmt) |
| 94 | { | 94 | { |
| 95 | char c; | 95 | char c; |
| 96 | int template_fmt_len = strlen(template_fmt); | 96 | int template_fmt_len = strlen(template_fmt); |
| @@ -106,22 +106,29 @@ static int template_fmt_size(char *template_fmt) | |||
| 106 | return j + 1; | 106 | return j + 1; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | static int template_desc_init_fields(char *template_fmt, | 109 | static int template_desc_init_fields(const char *template_fmt, |
| 110 | struct ima_template_field ***fields, | 110 | struct ima_template_field ***fields, |
| 111 | int *num_fields) | 111 | int *num_fields) |
| 112 | { | 112 | { |
| 113 | char *c, *template_fmt_ptr = template_fmt; | 113 | char *c, *template_fmt_copy, *template_fmt_ptr; |
| 114 | int template_num_fields = template_fmt_size(template_fmt); | 114 | int template_num_fields = template_fmt_size(template_fmt); |
| 115 | int i, result = 0; | 115 | int i, result = 0; |
| 116 | 116 | ||
| 117 | if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) | 117 | if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) |
| 118 | return -EINVAL; | 118 | return -EINVAL; |
| 119 | 119 | ||
| 120 | /* copying is needed as strsep() modifies the original buffer */ | ||
| 121 | template_fmt_copy = kstrdup(template_fmt, GFP_KERNEL); | ||
| 122 | if (template_fmt_copy == NULL) | ||
| 123 | return -ENOMEM; | ||
| 124 | |||
| 120 | *fields = kzalloc(template_num_fields * sizeof(*fields), GFP_KERNEL); | 125 | *fields = kzalloc(template_num_fields * sizeof(*fields), GFP_KERNEL); |
| 121 | if (*fields == NULL) { | 126 | if (*fields == NULL) { |
| 122 | result = -ENOMEM; | 127 | result = -ENOMEM; |
| 123 | goto out; | 128 | goto out; |
| 124 | } | 129 | } |
| 130 | |||
| 131 | template_fmt_ptr = template_fmt_copy; | ||
| 125 | for (i = 0; (c = strsep(&template_fmt_ptr, "|")) != NULL && | 132 | for (i = 0; (c = strsep(&template_fmt_ptr, "|")) != NULL && |
| 126 | i < template_num_fields; i++) { | 133 | i < template_num_fields; i++) { |
| 127 | struct ima_template_field *f = lookup_template_field(c); | 134 | struct ima_template_field *f = lookup_template_field(c); |
| @@ -133,10 +140,12 @@ static int template_desc_init_fields(char *template_fmt, | |||
| 133 | (*fields)[i] = f; | 140 | (*fields)[i] = f; |
| 134 | } | 141 | } |
| 135 | *num_fields = i; | 142 | *num_fields = i; |
| 136 | return 0; | ||
| 137 | out: | 143 | out: |
| 138 | kfree(*fields); | 144 | if (result < 0) { |
| 139 | *fields = NULL; | 145 | kfree(*fields); |
| 146 | *fields = NULL; | ||
| 147 | } | ||
| 148 | kfree(template_fmt_copy); | ||
| 140 | return result; | 149 | return result; |
| 141 | } | 150 | } |
| 142 | 151 | ||
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 6d66ad6ed265..c38adcc910fb 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c | |||
| @@ -109,9 +109,12 @@ static void ima_show_template_data_binary(struct seq_file *m, | |||
| 109 | enum data_formats datafmt, | 109 | enum data_formats datafmt, |
| 110 | struct ima_field_data *field_data) | 110 | struct ima_field_data *field_data) |
| 111 | { | 111 | { |
| 112 | ima_putc(m, &field_data->len, sizeof(u32)); | 112 | if (show != IMA_SHOW_BINARY_NO_FIELD_LEN) |
| 113 | ima_putc(m, &field_data->len, sizeof(u32)); | ||
| 114 | |||
| 113 | if (!field_data->len) | 115 | if (!field_data->len) |
| 114 | return; | 116 | return; |
| 117 | |||
| 115 | ima_putc(m, field_data->data, field_data->len); | 118 | ima_putc(m, field_data->data, field_data->len); |
| 116 | } | 119 | } |
| 117 | 120 | ||
| @@ -125,6 +128,7 @@ static void ima_show_template_field_data(struct seq_file *m, | |||
| 125 | ima_show_template_data_ascii(m, show, datafmt, field_data); | 128 | ima_show_template_data_ascii(m, show, datafmt, field_data); |
| 126 | break; | 129 | break; |
| 127 | case IMA_SHOW_BINARY: | 130 | case IMA_SHOW_BINARY: |
| 131 | case IMA_SHOW_BINARY_NO_FIELD_LEN: | ||
| 128 | ima_show_template_data_binary(m, show, datafmt, field_data); | 132 | ima_show_template_data_binary(m, show, datafmt, field_data); |
| 129 | break; | 133 | break; |
| 130 | default: | 134 | default: |
diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 7f44c3207a9b..8137b27d641d 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c | |||
| @@ -70,7 +70,7 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 70 | * | 70 | * |
| 71 | * TODO: Encrypt the stored data with a temporary key. | 71 | * TODO: Encrypt the stored data with a temporary key. |
| 72 | */ | 72 | */ |
| 73 | file = shmem_file_setup("", datalen, 0); | 73 | file = shmem_kernel_file_setup("", datalen, 0); |
| 74 | if (IS_ERR(file)) { | 74 | if (IS_ERR(file)) { |
| 75 | ret = PTR_ERR(file); | 75 | ret = PTR_ERR(file); |
| 76 | goto err_quota; | 76 | goto err_quota; |
diff --git a/security/keys/key.c b/security/keys/key.c index 55d110f0aced..6e21c11e48bc 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -272,7 +272,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
| 272 | } | 272 | } |
| 273 | 273 | ||
| 274 | /* allocate and initialise the key and its description */ | 274 | /* allocate and initialise the key and its description */ |
| 275 | key = kmem_cache_alloc(key_jar, GFP_KERNEL); | 275 | key = kmem_cache_zalloc(key_jar, GFP_KERNEL); |
| 276 | if (!key) | 276 | if (!key) |
| 277 | goto no_memory_2; | 277 | goto no_memory_2; |
| 278 | 278 | ||
| @@ -293,18 +293,12 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
| 293 | key->uid = uid; | 293 | key->uid = uid; |
| 294 | key->gid = gid; | 294 | key->gid = gid; |
| 295 | key->perm = perm; | 295 | key->perm = perm; |
| 296 | key->flags = 0; | ||
| 297 | key->expiry = 0; | ||
| 298 | key->payload.data = NULL; | ||
| 299 | key->security = NULL; | ||
| 300 | 296 | ||
| 301 | if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) | 297 | if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) |
| 302 | key->flags |= 1 << KEY_FLAG_IN_QUOTA; | 298 | key->flags |= 1 << KEY_FLAG_IN_QUOTA; |
| 303 | if (flags & KEY_ALLOC_TRUSTED) | 299 | if (flags & KEY_ALLOC_TRUSTED) |
| 304 | key->flags |= 1 << KEY_FLAG_TRUSTED; | 300 | key->flags |= 1 << KEY_FLAG_TRUSTED; |
| 305 | 301 | ||
| 306 | memset(&key->type_data, 0, sizeof(key->type_data)); | ||
| 307 | |||
| 308 | #ifdef KEY_DEBUGGING | 302 | #ifdef KEY_DEBUGGING |
| 309 | key->magic = KEY_DEBUG_MAGIC; | 303 | key->magic = KEY_DEBUG_MAGIC; |
| 310 | #endif | 304 | #endif |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 69f0cb7bab7e..d46cbc5e335e 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -160,7 +160,7 @@ static u64 mult_64x32_and_fold(u64 x, u32 y) | |||
| 160 | static unsigned long hash_key_type_and_desc(const struct keyring_index_key *index_key) | 160 | static unsigned long hash_key_type_and_desc(const struct keyring_index_key *index_key) |
| 161 | { | 161 | { |
| 162 | const unsigned level_shift = ASSOC_ARRAY_LEVEL_STEP; | 162 | const unsigned level_shift = ASSOC_ARRAY_LEVEL_STEP; |
| 163 | const unsigned long level_mask = ASSOC_ARRAY_LEVEL_STEP_MASK; | 163 | const unsigned long fan_mask = ASSOC_ARRAY_FAN_MASK; |
| 164 | const char *description = index_key->description; | 164 | const char *description = index_key->description; |
| 165 | unsigned long hash, type; | 165 | unsigned long hash, type; |
| 166 | u32 piece; | 166 | u32 piece; |
| @@ -194,10 +194,10 @@ static unsigned long hash_key_type_and_desc(const struct keyring_index_key *inde | |||
| 194 | * ordinary keys by making sure the lowest level segment in the hash is | 194 | * ordinary keys by making sure the lowest level segment in the hash is |
| 195 | * zero for keyrings and non-zero otherwise. | 195 | * zero for keyrings and non-zero otherwise. |
| 196 | */ | 196 | */ |
| 197 | if (index_key->type != &key_type_keyring && (hash & level_mask) == 0) | 197 | if (index_key->type != &key_type_keyring && (hash & fan_mask) == 0) |
| 198 | return hash | (hash >> (ASSOC_ARRAY_KEY_CHUNK_SIZE - level_shift)) | 1; | 198 | return hash | (hash >> (ASSOC_ARRAY_KEY_CHUNK_SIZE - level_shift)) | 1; |
| 199 | if (index_key->type == &key_type_keyring && (hash & level_mask) != 0) | 199 | if (index_key->type == &key_type_keyring && (hash & fan_mask) != 0) |
| 200 | return (hash + (hash << level_shift)) & ~level_mask; | 200 | return (hash + (hash << level_shift)) & ~fan_mask; |
| 201 | return hash; | 201 | return hash; |
| 202 | } | 202 | } |
| 203 | 203 | ||
| @@ -279,12 +279,11 @@ static bool keyring_compare_object(const void *object, const void *data) | |||
| 279 | * Compare the index keys of a pair of objects and determine the bit position | 279 | * Compare the index keys of a pair of objects and determine the bit position |
| 280 | * at which they differ - if they differ. | 280 | * at which they differ - if they differ. |
| 281 | */ | 281 | */ |
| 282 | static int keyring_diff_objects(const void *_a, const void *_b) | 282 | static int keyring_diff_objects(const void *object, const void *data) |
| 283 | { | 283 | { |
| 284 | const struct key *key_a = keyring_ptr_to_key(_a); | 284 | const struct key *key_a = keyring_ptr_to_key(object); |
| 285 | const struct key *key_b = keyring_ptr_to_key(_b); | ||
| 286 | const struct keyring_index_key *a = &key_a->index_key; | 285 | const struct keyring_index_key *a = &key_a->index_key; |
| 287 | const struct keyring_index_key *b = &key_b->index_key; | 286 | const struct keyring_index_key *b = data; |
| 288 | unsigned long seg_a, seg_b; | 287 | unsigned long seg_a, seg_b; |
| 289 | int level, i; | 288 | int level, i; |
| 290 | 289 | ||
| @@ -691,8 +690,8 @@ descend_to_node: | |||
| 691 | smp_read_barrier_depends(); | 690 | smp_read_barrier_depends(); |
| 692 | ptr = ACCESS_ONCE(shortcut->next_node); | 691 | ptr = ACCESS_ONCE(shortcut->next_node); |
| 693 | BUG_ON(!assoc_array_ptr_is_node(ptr)); | 692 | BUG_ON(!assoc_array_ptr_is_node(ptr)); |
| 694 | node = assoc_array_ptr_to_node(ptr); | ||
| 695 | } | 693 | } |
| 694 | node = assoc_array_ptr_to_node(ptr); | ||
| 696 | 695 | ||
| 697 | begin_node: | 696 | begin_node: |
| 698 | kdebug("begin_node"); | 697 | kdebug("begin_node"); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 794c3ca49eac..6625699f497c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #include <net/ip.h> /* for local_port_range[] */ | 53 | #include <net/ip.h> /* for local_port_range[] */ |
| 54 | #include <net/sock.h> | 54 | #include <net/sock.h> |
| 55 | #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ | 55 | #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ |
| 56 | #include <net/inet_connection_sock.h> | ||
| 56 | #include <net/net_namespace.h> | 57 | #include <net/net_namespace.h> |
| 57 | #include <net/netlabel.h> | 58 | #include <net/netlabel.h> |
| 58 | #include <linux/uaccess.h> | 59 | #include <linux/uaccess.h> |
| @@ -95,10 +96,6 @@ | |||
| 95 | #include "audit.h" | 96 | #include "audit.h" |
| 96 | #include "avc_ss.h" | 97 | #include "avc_ss.h" |
| 97 | 98 | ||
| 98 | #define SB_TYPE_FMT "%s%s%s" | ||
| 99 | #define SB_SUBTYPE(sb) (sb->s_subtype && sb->s_subtype[0]) | ||
| 100 | #define SB_TYPE_ARGS(sb) sb->s_type->name, SB_SUBTYPE(sb) ? "." : "", SB_SUBTYPE(sb) ? sb->s_subtype : "" | ||
| 101 | |||
| 102 | extern struct security_operations *security_ops; | 99 | extern struct security_operations *security_ops; |
| 103 | 100 | ||
| 104 | /* SECMARK reference count */ | 101 | /* SECMARK reference count */ |
| @@ -413,8 +410,8 @@ static int sb_finish_set_opts(struct super_block *sb) | |||
| 413 | the first boot of the SELinux kernel before we have | 410 | the first boot of the SELinux kernel before we have |
| 414 | assigned xattr values to the filesystem. */ | 411 | assigned xattr values to the filesystem. */ |
| 415 | if (!root_inode->i_op->getxattr) { | 412 | if (!root_inode->i_op->getxattr) { |
| 416 | printk(KERN_WARNING "SELinux: (dev %s, type "SB_TYPE_FMT") has no " | 413 | printk(KERN_WARNING "SELinux: (dev %s, type %s) has no " |
| 417 | "xattr support\n", sb->s_id, SB_TYPE_ARGS(sb)); | 414 | "xattr support\n", sb->s_id, sb->s_type->name); |
| 418 | rc = -EOPNOTSUPP; | 415 | rc = -EOPNOTSUPP; |
| 419 | goto out; | 416 | goto out; |
| 420 | } | 417 | } |
| @@ -422,22 +419,22 @@ static int sb_finish_set_opts(struct super_block *sb) | |||
| 422 | if (rc < 0 && rc != -ENODATA) { | 419 | if (rc < 0 && rc != -ENODATA) { |
| 423 | if (rc == -EOPNOTSUPP) | 420 | if (rc == -EOPNOTSUPP) |
| 424 | printk(KERN_WARNING "SELinux: (dev %s, type " | 421 | printk(KERN_WARNING "SELinux: (dev %s, type " |
| 425 | SB_TYPE_FMT") has no security xattr handler\n", | 422 | "%s) has no security xattr handler\n", |
| 426 | sb->s_id, SB_TYPE_ARGS(sb)); | 423 | sb->s_id, sb->s_type->name); |
| 427 | else | 424 | else |
| 428 | printk(KERN_WARNING "SELinux: (dev %s, type " | 425 | printk(KERN_WARNING "SELinux: (dev %s, type " |
| 429 | SB_TYPE_FMT") getxattr errno %d\n", sb->s_id, | 426 | "%s) getxattr errno %d\n", sb->s_id, |
| 430 | SB_TYPE_ARGS(sb), -rc); | 427 | sb->s_type->name, -rc); |
| 431 | goto out; | 428 | goto out; |
| 432 | } | 429 | } |
| 433 | } | 430 | } |
| 434 | 431 | ||
| 435 | if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) | 432 | if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) |
| 436 | printk(KERN_ERR "SELinux: initialized (dev %s, type "SB_TYPE_FMT"), unknown behavior\n", | 433 | printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", |
| 437 | sb->s_id, SB_TYPE_ARGS(sb)); | 434 | sb->s_id, sb->s_type->name); |
| 438 | else | 435 | else |
| 439 | printk(KERN_DEBUG "SELinux: initialized (dev %s, type "SB_TYPE_FMT"), %s\n", | 436 | printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n", |
| 440 | sb->s_id, SB_TYPE_ARGS(sb), | 437 | sb->s_id, sb->s_type->name, |
| 441 | labeling_behaviors[sbsec->behavior-1]); | 438 | labeling_behaviors[sbsec->behavior-1]); |
| 442 | 439 | ||
| 443 | sbsec->flags |= SE_SBINITIALIZED; | 440 | sbsec->flags |= SE_SBINITIALIZED; |
| @@ -600,6 +597,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
| 600 | const struct cred *cred = current_cred(); | 597 | const struct cred *cred = current_cred(); |
| 601 | int rc = 0, i; | 598 | int rc = 0, i; |
| 602 | struct superblock_security_struct *sbsec = sb->s_security; | 599 | struct superblock_security_struct *sbsec = sb->s_security; |
| 600 | const char *name = sb->s_type->name; | ||
| 603 | struct inode *inode = sbsec->sb->s_root->d_inode; | 601 | struct inode *inode = sbsec->sb->s_root->d_inode; |
| 604 | struct inode_security_struct *root_isec = inode->i_security; | 602 | struct inode_security_struct *root_isec = inode->i_security; |
| 605 | u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; | 603 | u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; |
| @@ -658,8 +656,8 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
| 658 | strlen(mount_options[i]), &sid); | 656 | strlen(mount_options[i]), &sid); |
| 659 | if (rc) { | 657 | if (rc) { |
| 660 | printk(KERN_WARNING "SELinux: security_context_to_sid" | 658 | printk(KERN_WARNING "SELinux: security_context_to_sid" |
| 661 | "(%s) failed for (dev %s, type "SB_TYPE_FMT") errno=%d\n", | 659 | "(%s) failed for (dev %s, type %s) errno=%d\n", |
| 662 | mount_options[i], sb->s_id, SB_TYPE_ARGS(sb), rc); | 660 | mount_options[i], sb->s_id, name, rc); |
| 663 | goto out; | 661 | goto out; |
| 664 | } | 662 | } |
| 665 | switch (flags[i]) { | 663 | switch (flags[i]) { |
| @@ -806,8 +804,7 @@ out: | |||
| 806 | out_double_mount: | 804 | out_double_mount: |
| 807 | rc = -EINVAL; | 805 | rc = -EINVAL; |
| 808 | printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different " | 806 | printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different " |
| 809 | "security settings for (dev %s, type "SB_TYPE_FMT")\n", sb->s_id, | 807 | "security settings for (dev %s, type %s)\n", sb->s_id, name); |
| 810 | SB_TYPE_ARGS(sb)); | ||
| 811 | goto out; | 808 | goto out; |
| 812 | } | 809 | } |
| 813 | 810 | ||
| @@ -2480,8 +2477,8 @@ static int selinux_sb_remount(struct super_block *sb, void *data) | |||
| 2480 | rc = security_context_to_sid(mount_options[i], len, &sid); | 2477 | rc = security_context_to_sid(mount_options[i], len, &sid); |
| 2481 | if (rc) { | 2478 | if (rc) { |
| 2482 | printk(KERN_WARNING "SELinux: security_context_to_sid" | 2479 | printk(KERN_WARNING "SELinux: security_context_to_sid" |
| 2483 | "(%s) failed for (dev %s, type "SB_TYPE_FMT") errno=%d\n", | 2480 | "(%s) failed for (dev %s, type %s) errno=%d\n", |
| 2484 | mount_options[i], sb->s_id, SB_TYPE_ARGS(sb), rc); | 2481 | mount_options[i], sb->s_id, sb->s_type->name, rc); |
| 2485 | goto out_free_opts; | 2482 | goto out_free_opts; |
| 2486 | } | 2483 | } |
| 2487 | rc = -EINVAL; | 2484 | rc = -EINVAL; |
| @@ -2519,8 +2516,8 @@ out_free_secdata: | |||
| 2519 | return rc; | 2516 | return rc; |
| 2520 | out_bad_option: | 2517 | out_bad_option: |
| 2521 | printk(KERN_WARNING "SELinux: unable to change security options " | 2518 | printk(KERN_WARNING "SELinux: unable to change security options " |
| 2522 | "during remount (dev %s, type "SB_TYPE_FMT")\n", sb->s_id, | 2519 | "during remount (dev %s, type=%s)\n", sb->s_id, |
| 2523 | SB_TYPE_ARGS(sb)); | 2520 | sb->s_type->name); |
| 2524 | goto out_free_opts; | 2521 | goto out_free_opts; |
| 2525 | } | 2522 | } |
| 2526 | 2523 | ||
| @@ -3828,7 +3825,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) | |||
| 3828 | u32 nlbl_sid; | 3825 | u32 nlbl_sid; |
| 3829 | u32 nlbl_type; | 3826 | u32 nlbl_type; |
| 3830 | 3827 | ||
| 3831 | err = selinux_skb_xfrm_sid(skb, &xfrm_sid); | 3828 | err = selinux_xfrm_skb_sid(skb, &xfrm_sid); |
| 3832 | if (unlikely(err)) | 3829 | if (unlikely(err)) |
| 3833 | return -EACCES; | 3830 | return -EACCES; |
| 3834 | err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid); | 3831 | err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid); |
| @@ -3846,6 +3843,30 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) | |||
| 3846 | return 0; | 3843 | return 0; |
| 3847 | } | 3844 | } |
| 3848 | 3845 | ||
| 3846 | /** | ||
| 3847 | * selinux_conn_sid - Determine the child socket label for a connection | ||
| 3848 | * @sk_sid: the parent socket's SID | ||
| 3849 | * @skb_sid: the packet's SID | ||
| 3850 | * @conn_sid: the resulting connection SID | ||
| 3851 | * | ||
| 3852 | * If @skb_sid is valid then the user:role:type information from @sk_sid is | ||
| 3853 | * combined with the MLS information from @skb_sid in order to create | ||
| 3854 | * @conn_sid. If @skb_sid is not valid then then @conn_sid is simply a copy | ||
| 3855 | * of @sk_sid. Returns zero on success, negative values on failure. | ||
| 3856 | * | ||
| 3857 | */ | ||
| 3858 | static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid) | ||
| 3859 | { | ||
| 3860 | int err = 0; | ||
| 3861 | |||
| 3862 | if (skb_sid != SECSID_NULL) | ||
| 3863 | err = security_sid_mls_copy(sk_sid, skb_sid, conn_sid); | ||
| 3864 | else | ||
| 3865 | *conn_sid = sk_sid; | ||
| 3866 | |||
| 3867 | return err; | ||
| 3868 | } | ||
| 3869 | |||
| 3849 | /* socket security operations */ | 3870 | /* socket security operations */ |
| 3850 | 3871 | ||
| 3851 | static int socket_sockcreate_sid(const struct task_security_struct *tsec, | 3872 | static int socket_sockcreate_sid(const struct task_security_struct *tsec, |
| @@ -4313,8 +4334,10 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 4313 | } | 4334 | } |
| 4314 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, | 4335 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, |
| 4315 | PEER__RECV, &ad); | 4336 | PEER__RECV, &ad); |
| 4316 | if (err) | 4337 | if (err) { |
| 4317 | selinux_netlbl_err(skb, err, 0); | 4338 | selinux_netlbl_err(skb, err, 0); |
| 4339 | return err; | ||
| 4340 | } | ||
| 4318 | } | 4341 | } |
| 4319 | 4342 | ||
| 4320 | if (secmark_active) { | 4343 | if (secmark_active) { |
| @@ -4452,7 +4475,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 4452 | struct sk_security_struct *sksec = sk->sk_security; | 4475 | struct sk_security_struct *sksec = sk->sk_security; |
| 4453 | int err; | 4476 | int err; |
| 4454 | u16 family = sk->sk_family; | 4477 | u16 family = sk->sk_family; |
| 4455 | u32 newsid; | 4478 | u32 connsid; |
| 4456 | u32 peersid; | 4479 | u32 peersid; |
| 4457 | 4480 | ||
| 4458 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ | 4481 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
| @@ -4462,16 +4485,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 4462 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); | 4485 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); |
| 4463 | if (err) | 4486 | if (err) |
| 4464 | return err; | 4487 | return err; |
| 4465 | if (peersid == SECSID_NULL) { | 4488 | err = selinux_conn_sid(sksec->sid, peersid, &connsid); |
| 4466 | req->secid = sksec->sid; | 4489 | if (err) |
| 4467 | req->peer_secid = SECSID_NULL; | 4490 | return err; |
| 4468 | } else { | 4491 | req->secid = connsid; |
| 4469 | err = security_sid_mls_copy(sksec->sid, peersid, &newsid); | 4492 | req->peer_secid = peersid; |
| 4470 | if (err) | ||
| 4471 | return err; | ||
| 4472 | req->secid = newsid; | ||
| 4473 | req->peer_secid = peersid; | ||
| 4474 | } | ||
| 4475 | 4493 | ||
| 4476 | return selinux_netlbl_inet_conn_request(req, family); | 4494 | return selinux_netlbl_inet_conn_request(req, family); |
| 4477 | } | 4495 | } |
| @@ -4731,6 +4749,7 @@ static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops, | |||
| 4731 | static unsigned int selinux_ip_output(struct sk_buff *skb, | 4749 | static unsigned int selinux_ip_output(struct sk_buff *skb, |
| 4732 | u16 family) | 4750 | u16 family) |
| 4733 | { | 4751 | { |
| 4752 | struct sock *sk; | ||
| 4734 | u32 sid; | 4753 | u32 sid; |
| 4735 | 4754 | ||
| 4736 | if (!netlbl_enabled()) | 4755 | if (!netlbl_enabled()) |
| @@ -4739,8 +4758,27 @@ static unsigned int selinux_ip_output(struct sk_buff *skb, | |||
| 4739 | /* we do this in the LOCAL_OUT path and not the POST_ROUTING path | 4758 | /* we do this in the LOCAL_OUT path and not the POST_ROUTING path |
| 4740 | * because we want to make sure we apply the necessary labeling | 4759 | * because we want to make sure we apply the necessary labeling |
| 4741 | * before IPsec is applied so we can leverage AH protection */ | 4760 | * before IPsec is applied so we can leverage AH protection */ |
| 4742 | if (skb->sk) { | 4761 | sk = skb->sk; |
| 4743 | struct sk_security_struct *sksec = skb->sk->sk_security; | 4762 | if (sk) { |
| 4763 | struct sk_security_struct *sksec; | ||
| 4764 | |||
| 4765 | if (sk->sk_state == TCP_LISTEN) | ||
| 4766 | /* if the socket is the listening state then this | ||
| 4767 | * packet is a SYN-ACK packet which means it needs to | ||
| 4768 | * be labeled based on the connection/request_sock and | ||
| 4769 | * not the parent socket. unfortunately, we can't | ||
| 4770 | * lookup the request_sock yet as it isn't queued on | ||
| 4771 | * the parent socket until after the SYN-ACK is sent. | ||
| 4772 | * the "solution" is to simply pass the packet as-is | ||
| 4773 | * as any IP option based labeling should be copied | ||
| 4774 | * from the initial connection request (in the IP | ||
| 4775 | * layer). it is far from ideal, but until we get a | ||
| 4776 | * security label in the packet itself this is the | ||
| 4777 | * best we can do. */ | ||
| 4778 | return NF_ACCEPT; | ||
| 4779 | |||
| 4780 | /* standard practice, label using the parent socket */ | ||
| 4781 | sksec = sk->sk_security; | ||
| 4744 | sid = sksec->sid; | 4782 | sid = sksec->sid; |
| 4745 | } else | 4783 | } else |
| 4746 | sid = SECINITSID_KERNEL; | 4784 | sid = SECINITSID_KERNEL; |
| @@ -4810,27 +4848,36 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4810 | * as fast and as clean as possible. */ | 4848 | * as fast and as clean as possible. */ |
| 4811 | if (!selinux_policycap_netpeer) | 4849 | if (!selinux_policycap_netpeer) |
| 4812 | return selinux_ip_postroute_compat(skb, ifindex, family); | 4850 | return selinux_ip_postroute_compat(skb, ifindex, family); |
| 4851 | |||
| 4852 | secmark_active = selinux_secmark_enabled(); | ||
| 4853 | peerlbl_active = selinux_peerlbl_enabled(); | ||
| 4854 | if (!secmark_active && !peerlbl_active) | ||
| 4855 | return NF_ACCEPT; | ||
| 4856 | |||
| 4857 | sk = skb->sk; | ||
| 4858 | |||
| 4813 | #ifdef CONFIG_XFRM | 4859 | #ifdef CONFIG_XFRM |
| 4814 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec | 4860 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec |
| 4815 | * packet transformation so allow the packet to pass without any checks | 4861 | * packet transformation so allow the packet to pass without any checks |
| 4816 | * since we'll have another chance to perform access control checks | 4862 | * since we'll have another chance to perform access control checks |
| 4817 | * when the packet is on it's final way out. | 4863 | * when the packet is on it's final way out. |
| 4818 | * NOTE: there appear to be some IPv6 multicast cases where skb->dst | 4864 | * NOTE: there appear to be some IPv6 multicast cases where skb->dst |
| 4819 | * is NULL, in this case go ahead and apply access control. */ | 4865 | * is NULL, in this case go ahead and apply access control. |
| 4820 | if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL) | 4866 | * NOTE: if this is a local socket (skb->sk != NULL) that is in the |
| 4867 | * TCP listening state we cannot wait until the XFRM processing | ||
| 4868 | * is done as we will miss out on the SA label if we do; | ||
| 4869 | * unfortunately, this means more work, but it is only once per | ||
| 4870 | * connection. */ | ||
| 4871 | if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL && | ||
| 4872 | !(sk != NULL && sk->sk_state == TCP_LISTEN)) | ||
| 4821 | return NF_ACCEPT; | 4873 | return NF_ACCEPT; |
| 4822 | #endif | 4874 | #endif |
| 4823 | secmark_active = selinux_secmark_enabled(); | ||
| 4824 | peerlbl_active = selinux_peerlbl_enabled(); | ||
| 4825 | if (!secmark_active && !peerlbl_active) | ||
| 4826 | return NF_ACCEPT; | ||
| 4827 | 4875 | ||
| 4828 | /* if the packet is being forwarded then get the peer label from the | ||
| 4829 | * packet itself; otherwise check to see if it is from a local | ||
| 4830 | * application or the kernel, if from an application get the peer label | ||
| 4831 | * from the sending socket, otherwise use the kernel's sid */ | ||
| 4832 | sk = skb->sk; | ||
| 4833 | if (sk == NULL) { | 4876 | if (sk == NULL) { |
| 4877 | /* Without an associated socket the packet is either coming | ||
| 4878 | * from the kernel or it is being forwarded; check the packet | ||
| 4879 | * to determine which and if the packet is being forwarded | ||
| 4880 | * query the packet directly to determine the security label. */ | ||
| 4834 | if (skb->skb_iif) { | 4881 | if (skb->skb_iif) { |
| 4835 | secmark_perm = PACKET__FORWARD_OUT; | 4882 | secmark_perm = PACKET__FORWARD_OUT; |
| 4836 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | 4883 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) |
| @@ -4839,7 +4886,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4839 | secmark_perm = PACKET__SEND; | 4886 | secmark_perm = PACKET__SEND; |
| 4840 | peer_sid = SECINITSID_KERNEL; | 4887 | peer_sid = SECINITSID_KERNEL; |
| 4841 | } | 4888 | } |
| 4889 | } else if (sk->sk_state == TCP_LISTEN) { | ||
| 4890 | /* Locally generated packet but the associated socket is in the | ||
| 4891 | * listening state which means this is a SYN-ACK packet. In | ||
| 4892 | * this particular case the correct security label is assigned | ||
| 4893 | * to the connection/request_sock but unfortunately we can't | ||
| 4894 | * query the request_sock as it isn't queued on the parent | ||
| 4895 | * socket until after the SYN-ACK packet is sent; the only | ||
| 4896 | * viable choice is to regenerate the label like we do in | ||
| 4897 | * selinux_inet_conn_request(). See also selinux_ip_output() | ||
| 4898 | * for similar problems. */ | ||
| 4899 | u32 skb_sid; | ||
| 4900 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 4901 | if (selinux_skb_peerlbl_sid(skb, family, &skb_sid)) | ||
| 4902 | return NF_DROP; | ||
| 4903 | /* At this point, if the returned skb peerlbl is SECSID_NULL | ||
| 4904 | * and the packet has been through at least one XFRM | ||
| 4905 | * transformation then we must be dealing with the "final" | ||
| 4906 | * form of labeled IPsec packet; since we've already applied | ||
| 4907 | * all of our access controls on this packet we can safely | ||
| 4908 | * pass the packet. */ | ||
| 4909 | if (skb_sid == SECSID_NULL) { | ||
| 4910 | switch (family) { | ||
| 4911 | case PF_INET: | ||
| 4912 | if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) | ||
| 4913 | return NF_ACCEPT; | ||
| 4914 | break; | ||
| 4915 | case PF_INET6: | ||
| 4916 | if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) | ||
| 4917 | return NF_ACCEPT; | ||
| 4918 | default: | ||
| 4919 | return NF_DROP_ERR(-ECONNREFUSED); | ||
| 4920 | } | ||
| 4921 | } | ||
| 4922 | if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid)) | ||
| 4923 | return NF_DROP; | ||
| 4924 | secmark_perm = PACKET__SEND; | ||
| 4842 | } else { | 4925 | } else { |
| 4926 | /* Locally generated packet, fetch the security label from the | ||
| 4927 | * associated socket. */ | ||
| 4843 | struct sk_security_struct *sksec = sk->sk_security; | 4928 | struct sk_security_struct *sksec = sk->sk_security; |
| 4844 | peer_sid = sksec->sid; | 4929 | peer_sid = sksec->sid; |
| 4845 | secmark_perm = PACKET__SEND; | 4930 | secmark_perm = PACKET__SEND; |
| @@ -5503,11 +5588,11 @@ static int selinux_setprocattr(struct task_struct *p, | |||
| 5503 | /* Check for ptracing, and update the task SID if ok. | 5588 | /* Check for ptracing, and update the task SID if ok. |
| 5504 | Otherwise, leave SID unchanged and fail. */ | 5589 | Otherwise, leave SID unchanged and fail. */ |
| 5505 | ptsid = 0; | 5590 | ptsid = 0; |
| 5506 | task_lock(p); | 5591 | rcu_read_lock(); |
| 5507 | tracer = ptrace_parent(p); | 5592 | tracer = ptrace_parent(p); |
| 5508 | if (tracer) | 5593 | if (tracer) |
| 5509 | ptsid = task_sid(tracer); | 5594 | ptsid = task_sid(tracer); |
| 5510 | task_unlock(p); | 5595 | rcu_read_unlock(); |
| 5511 | 5596 | ||
| 5512 | if (tracer) { | 5597 | if (tracer) { |
| 5513 | error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, | 5598 | error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, |
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 0dec76c64cf5..48c3cc94c168 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h | |||
| @@ -39,6 +39,7 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb, | |||
| 39 | int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb, | 39 | int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb, |
| 40 | struct common_audit_data *ad, u8 proto); | 40 | struct common_audit_data *ad, u8 proto); |
| 41 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); | 41 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); |
| 42 | int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid); | ||
| 42 | 43 | ||
| 43 | static inline void selinux_xfrm_notify_policyload(void) | 44 | static inline void selinux_xfrm_notify_policyload(void) |
| 44 | { | 45 | { |
| @@ -79,11 +80,12 @@ static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, | |||
| 79 | static inline void selinux_xfrm_notify_policyload(void) | 80 | static inline void selinux_xfrm_notify_policyload(void) |
| 80 | { | 81 | { |
| 81 | } | 82 | } |
| 82 | #endif | ||
| 83 | 83 | ||
| 84 | static inline int selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid) | 84 | static inline int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid) |
| 85 | { | 85 | { |
| 86 | return selinux_xfrm_decode_session(skb, sid, 0); | 86 | *sid = SECSID_NULL; |
| 87 | return 0; | ||
| 87 | } | 88 | } |
| 89 | #endif | ||
| 88 | 90 | ||
| 89 | #endif /* _SELINUX_XFRM_H_ */ | 91 | #endif /* _SELINUX_XFRM_H_ */ |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index ee470a0b5c27..d106733ad987 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -2334,50 +2334,16 @@ int security_fs_use(struct super_block *sb) | |||
| 2334 | struct ocontext *c; | 2334 | struct ocontext *c; |
| 2335 | struct superblock_security_struct *sbsec = sb->s_security; | 2335 | struct superblock_security_struct *sbsec = sb->s_security; |
| 2336 | const char *fstype = sb->s_type->name; | 2336 | const char *fstype = sb->s_type->name; |
| 2337 | const char *subtype = (sb->s_subtype && sb->s_subtype[0]) ? sb->s_subtype : NULL; | ||
| 2338 | struct ocontext *base = NULL; | ||
| 2339 | 2337 | ||
| 2340 | read_lock(&policy_rwlock); | 2338 | read_lock(&policy_rwlock); |
| 2341 | 2339 | ||
| 2342 | for (c = policydb.ocontexts[OCON_FSUSE]; c; c = c->next) { | 2340 | c = policydb.ocontexts[OCON_FSUSE]; |
| 2343 | char *sub; | 2341 | while (c) { |
| 2344 | int baselen; | 2342 | if (strcmp(fstype, c->u.name) == 0) |
| 2345 | |||
| 2346 | baselen = strlen(fstype); | ||
| 2347 | |||
| 2348 | /* if base does not match, this is not the one */ | ||
| 2349 | if (strncmp(fstype, c->u.name, baselen)) | ||
| 2350 | continue; | ||
| 2351 | |||
| 2352 | /* if there is no subtype, this is the one! */ | ||
| 2353 | if (!subtype) | ||
| 2354 | break; | ||
| 2355 | |||
| 2356 | /* skip past the base in this entry */ | ||
| 2357 | sub = c->u.name + baselen; | ||
| 2358 | |||
| 2359 | /* entry is only a base. save it. keep looking for subtype */ | ||
| 2360 | if (sub[0] == '\0') { | ||
| 2361 | base = c; | ||
| 2362 | continue; | ||
| 2363 | } | ||
| 2364 | |||
| 2365 | /* entry is not followed by a subtype, so it is not a match */ | ||
| 2366 | if (sub[0] != '.') | ||
| 2367 | continue; | ||
| 2368 | |||
| 2369 | /* whew, we found a subtype of this fstype */ | ||
| 2370 | sub++; /* move past '.' */ | ||
| 2371 | |||
| 2372 | /* exact match of fstype AND subtype */ | ||
| 2373 | if (!strcmp(subtype, sub)) | ||
| 2374 | break; | 2343 | break; |
| 2344 | c = c->next; | ||
| 2375 | } | 2345 | } |
| 2376 | 2346 | ||
| 2377 | /* in case we had found an fstype match but no subtype match */ | ||
| 2378 | if (!c) | ||
| 2379 | c = base; | ||
| 2380 | |||
| 2381 | if (c) { | 2347 | if (c) { |
| 2382 | sbsec->behavior = c->v.behavior; | 2348 | sbsec->behavior = c->v.behavior; |
| 2383 | if (!c->sid[0]) { | 2349 | if (!c->sid[0]) { |
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index a91d205ec0c6..0462cb3ff0a7 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
| @@ -209,19 +209,26 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, | |||
| 209 | NULL) ? 0 : 1); | 209 | NULL) ? 0 : 1); |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | /* | 212 | static u32 selinux_xfrm_skb_sid_egress(struct sk_buff *skb) |
| 213 | * LSM hook implementation that checks and/or returns the xfrm sid for the | ||
| 214 | * incoming packet. | ||
| 215 | */ | ||
| 216 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) | ||
| 217 | { | 213 | { |
| 218 | u32 sid_session = SECSID_NULL; | 214 | struct dst_entry *dst = skb_dst(skb); |
| 219 | struct sec_path *sp; | 215 | struct xfrm_state *x; |
| 220 | 216 | ||
| 221 | if (skb == NULL) | 217 | if (dst == NULL) |
| 222 | goto out; | 218 | return SECSID_NULL; |
| 219 | x = dst->xfrm; | ||
| 220 | if (x == NULL || !selinux_authorizable_xfrm(x)) | ||
| 221 | return SECSID_NULL; | ||
| 222 | |||
| 223 | return x->security->ctx_sid; | ||
| 224 | } | ||
| 225 | |||
| 226 | static int selinux_xfrm_skb_sid_ingress(struct sk_buff *skb, | ||
| 227 | u32 *sid, int ckall) | ||
| 228 | { | ||
| 229 | u32 sid_session = SECSID_NULL; | ||
| 230 | struct sec_path *sp = skb->sp; | ||
| 223 | 231 | ||
| 224 | sp = skb->sp; | ||
| 225 | if (sp) { | 232 | if (sp) { |
| 226 | int i; | 233 | int i; |
| 227 | 234 | ||
| @@ -248,6 +255,30 @@ out: | |||
| 248 | } | 255 | } |
| 249 | 256 | ||
| 250 | /* | 257 | /* |
| 258 | * LSM hook implementation that checks and/or returns the xfrm sid for the | ||
| 259 | * incoming packet. | ||
| 260 | */ | ||
| 261 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) | ||
| 262 | { | ||
| 263 | if (skb == NULL) { | ||
| 264 | *sid = SECSID_NULL; | ||
| 265 | return 0; | ||
| 266 | } | ||
| 267 | return selinux_xfrm_skb_sid_ingress(skb, sid, ckall); | ||
| 268 | } | ||
| 269 | |||
| 270 | int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid) | ||
| 271 | { | ||
| 272 | int rc; | ||
| 273 | |||
| 274 | rc = selinux_xfrm_skb_sid_ingress(skb, sid, 0); | ||
| 275 | if (rc == 0 && *sid == SECSID_NULL) | ||
| 276 | *sid = selinux_xfrm_skb_sid_egress(skb); | ||
| 277 | |||
| 278 | return rc; | ||
| 279 | } | ||
| 280 | |||
| 281 | /* | ||
| 251 | * LSM hook implementation that allocs and transfers uctx spec to xfrm_policy. | 282 | * LSM hook implementation that allocs and transfers uctx spec to xfrm_policy. |
| 252 | */ | 283 | */ |
| 253 | int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, | 284 | int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, |
| @@ -327,19 +358,22 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x, | |||
| 327 | return rc; | 358 | return rc; |
| 328 | 359 | ||
| 329 | ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC); | 360 | ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC); |
| 330 | if (!ctx) | 361 | if (!ctx) { |
| 331 | return -ENOMEM; | 362 | rc = -ENOMEM; |
| 363 | goto out; | ||
| 364 | } | ||
| 332 | 365 | ||
| 333 | ctx->ctx_doi = XFRM_SC_DOI_LSM; | 366 | ctx->ctx_doi = XFRM_SC_DOI_LSM; |
| 334 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; | 367 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; |
| 335 | ctx->ctx_sid = secid; | 368 | ctx->ctx_sid = secid; |
| 336 | ctx->ctx_len = str_len; | 369 | ctx->ctx_len = str_len; |
| 337 | memcpy(ctx->ctx_str, ctx_str, str_len); | 370 | memcpy(ctx->ctx_str, ctx_str, str_len); |
| 338 | kfree(ctx_str); | ||
| 339 | 371 | ||
| 340 | x->security = ctx; | 372 | x->security = ctx; |
| 341 | atomic_inc(&selinux_xfrm_refcount); | 373 | atomic_inc(&selinux_xfrm_refcount); |
| 342 | return 0; | 374 | out: |
| 375 | kfree(ctx_str); | ||
| 376 | return rc; | ||
| 343 | } | 377 | } |
| 344 | 378 | ||
| 345 | /* | 379 | /* |
