diff options
Diffstat (limited to 'security/selinux/ss/ebitmap.c')
-rw-r--r-- | security/selinux/ss/ebitmap.c | 198 |
1 files changed, 89 insertions, 109 deletions
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index d539346ab3a2..ce492a6b38ed 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c | |||
@@ -6,7 +6,7 @@ | |||
6 | /* | 6 | /* |
7 | * Updated: Hewlett-Packard <paul.moore@hp.com> | 7 | * Updated: Hewlett-Packard <paul.moore@hp.com> |
8 | * | 8 | * |
9 | * Added ebitmap_export() and ebitmap_import() | 9 | * Added support to import/export the NetLabel category bitmap |
10 | * | 10 | * |
11 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | 11 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 |
12 | */ | 12 | */ |
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
17 | #include <net/netlabel.h> | ||
17 | #include "ebitmap.h" | 18 | #include "ebitmap.h" |
18 | #include "policydb.h" | 19 | #include "policydb.h" |
19 | 20 | ||
@@ -67,141 +68,120 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src) | |||
67 | return 0; | 68 | return 0; |
68 | } | 69 | } |
69 | 70 | ||
71 | #ifdef CONFIG_NETLABEL | ||
70 | /** | 72 | /** |
71 | * ebitmap_export - Export an ebitmap to a unsigned char bitmap string | 73 | * ebitmap_netlbl_export - Export an ebitmap into a NetLabel category bitmap |
72 | * @src: the ebitmap to export | 74 | * @ebmap: the ebitmap to export |
73 | * @dst: the resulting bitmap string | 75 | * @catmap: the NetLabel category bitmap |
74 | * @dst_len: length of dst in bytes | ||
75 | * | 76 | * |
76 | * Description: | 77 | * Description: |
77 | * Allocate a buffer at least src->highbit bits long and export the extensible | 78 | * Export a SELinux extensibile bitmap into a NetLabel category bitmap. |
78 | * bitmap into the buffer. The bitmap string will be in little endian format, | 79 | * Returns zero on success, negative values on error. |
79 | * i.e. LSB first. The value returned in dst_len may not the true size of the | ||
80 | * buffer as the length of the buffer is rounded up to a multiple of MAPTYPE. | ||
81 | * The caller must free the buffer when finished. Returns zero on success, | ||
82 | * negative values on failure. | ||
83 | * | 80 | * |
84 | */ | 81 | */ |
85 | int ebitmap_export(const struct ebitmap *src, | 82 | int ebitmap_netlbl_export(struct ebitmap *ebmap, |
86 | unsigned char **dst, | 83 | struct netlbl_lsm_secattr_catmap **catmap) |
87 | size_t *dst_len) | ||
88 | { | 84 | { |
89 | size_t bitmap_len; | 85 | struct ebitmap_node *e_iter = ebmap->node; |
90 | unsigned char *bitmap; | 86 | struct netlbl_lsm_secattr_catmap *c_iter; |
91 | struct ebitmap_node *iter_node; | 87 | u32 cmap_idx; |
92 | MAPTYPE node_val; | 88 | |
93 | size_t bitmap_byte; | 89 | /* This function is a much simpler because SELinux's MAPTYPE happens |
94 | unsigned char bitmask; | 90 | * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is |
95 | 91 | * changed from a u64 this function will most likely need to be changed | |
96 | if (src->highbit == 0) { | 92 | * as well. It's not ideal but I think the tradeoff in terms of |
97 | *dst = NULL; | 93 | * neatness and speed is worth it. */ |
98 | *dst_len = 0; | 94 | |
95 | if (e_iter == NULL) { | ||
96 | *catmap = NULL; | ||
99 | return 0; | 97 | return 0; |
100 | } | 98 | } |
101 | 99 | ||
102 | bitmap_len = src->highbit / 8; | 100 | c_iter = netlbl_secattr_catmap_alloc(GFP_ATOMIC); |
103 | if (src->highbit % 7) | 101 | if (c_iter == NULL) |
104 | bitmap_len += 1; | ||
105 | |||
106 | bitmap = kzalloc((bitmap_len & ~(sizeof(MAPTYPE) - 1)) + | ||
107 | sizeof(MAPTYPE), | ||
108 | GFP_ATOMIC); | ||
109 | if (bitmap == NULL) | ||
110 | return -ENOMEM; | 102 | return -ENOMEM; |
103 | *catmap = c_iter; | ||
104 | c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1); | ||
105 | |||
106 | while (e_iter != NULL) { | ||
107 | if (e_iter->startbit >= | ||
108 | (c_iter->startbit + NETLBL_CATMAP_SIZE)) { | ||
109 | c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
110 | if (c_iter->next == NULL) | ||
111 | goto netlbl_export_failure; | ||
112 | c_iter = c_iter->next; | ||
113 | c_iter->startbit = e_iter->startbit & | ||
114 | ~(NETLBL_CATMAP_SIZE - 1); | ||
115 | } | ||
116 | cmap_idx = (e_iter->startbit - c_iter->startbit) / | ||
117 | NETLBL_CATMAP_MAPSIZE; | ||
118 | c_iter->bitmap[cmap_idx] = e_iter->map; | ||
119 | e_iter = e_iter->next; | ||
120 | } | ||
111 | 121 | ||
112 | iter_node = src->node; | ||
113 | do { | ||
114 | bitmap_byte = iter_node->startbit / 8; | ||
115 | bitmask = 0x80; | ||
116 | node_val = iter_node->map; | ||
117 | do { | ||
118 | if (bitmask == 0) { | ||
119 | bitmap_byte++; | ||
120 | bitmask = 0x80; | ||
121 | } | ||
122 | if (node_val & (MAPTYPE)0x01) | ||
123 | bitmap[bitmap_byte] |= bitmask; | ||
124 | node_val >>= 1; | ||
125 | bitmask >>= 1; | ||
126 | } while (node_val > 0); | ||
127 | iter_node = iter_node->next; | ||
128 | } while (iter_node); | ||
129 | |||
130 | *dst = bitmap; | ||
131 | *dst_len = bitmap_len; | ||
132 | return 0; | 122 | return 0; |
123 | |||
124 | netlbl_export_failure: | ||
125 | netlbl_secattr_catmap_free(*catmap); | ||
126 | return -ENOMEM; | ||
133 | } | 127 | } |
134 | 128 | ||
135 | /** | 129 | /** |
136 | * ebitmap_import - Import an unsigned char bitmap string into an ebitmap | 130 | * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap |
137 | * @src: the bitmap string | 131 | * @ebmap: the ebitmap to export |
138 | * @src_len: the bitmap length in bytes | 132 | * @catmap: the NetLabel category bitmap |
139 | * @dst: the empty ebitmap | ||
140 | * | 133 | * |
141 | * Description: | 134 | * Description: |
142 | * This function takes a little endian bitmap string in src and imports it into | 135 | * Import a NetLabel category bitmap into a SELinux extensibile bitmap. |
143 | * the ebitmap pointed to by dst. Returns zero on success, negative values on | 136 | * Returns zero on success, negative values on error. |
144 | * failure. | ||
145 | * | 137 | * |
146 | */ | 138 | */ |
147 | int ebitmap_import(const unsigned char *src, | 139 | int ebitmap_netlbl_import(struct ebitmap *ebmap, |
148 | size_t src_len, | 140 | struct netlbl_lsm_secattr_catmap *catmap) |
149 | struct ebitmap *dst) | ||
150 | { | 141 | { |
151 | size_t src_off = 0; | 142 | struct ebitmap_node *e_iter = NULL; |
152 | size_t node_limit; | 143 | struct ebitmap_node *emap_prev = NULL; |
153 | struct ebitmap_node *node_new; | 144 | struct netlbl_lsm_secattr_catmap *c_iter = catmap; |
154 | struct ebitmap_node *node_last = NULL; | 145 | u32 c_idx; |
155 | u32 i_byte; | ||
156 | u32 i_bit; | ||
157 | unsigned char src_byte; | ||
158 | |||
159 | while (src_off < src_len) { | ||
160 | if (src_len - src_off >= sizeof(MAPTYPE)) { | ||
161 | if (*(MAPTYPE *)&src[src_off] == 0) { | ||
162 | src_off += sizeof(MAPTYPE); | ||
163 | continue; | ||
164 | } | ||
165 | node_limit = sizeof(MAPTYPE); | ||
166 | } else { | ||
167 | for (src_byte = 0, i_byte = src_off; | ||
168 | i_byte < src_len && src_byte == 0; | ||
169 | i_byte++) | ||
170 | src_byte |= src[i_byte]; | ||
171 | if (src_byte == 0) | ||
172 | break; | ||
173 | node_limit = src_len - src_off; | ||
174 | } | ||
175 | 146 | ||
176 | node_new = kzalloc(sizeof(*node_new), GFP_ATOMIC); | 147 | /* This function is a much simpler because SELinux's MAPTYPE happens |
177 | if (unlikely(node_new == NULL)) { | 148 | * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is |
178 | ebitmap_destroy(dst); | 149 | * changed from a u64 this function will most likely need to be changed |
179 | return -ENOMEM; | 150 | * as well. It's not ideal but I think the tradeoff in terms of |
180 | } | 151 | * neatness and speed is worth it. */ |
181 | node_new->startbit = src_off * 8; | ||
182 | for (i_byte = 0; i_byte < node_limit; i_byte++) { | ||
183 | src_byte = src[src_off++]; | ||
184 | for (i_bit = i_byte * 8; src_byte != 0; i_bit++) { | ||
185 | if (src_byte & 0x80) | ||
186 | node_new->map |= MAPBIT << i_bit; | ||
187 | src_byte <<= 1; | ||
188 | } | ||
189 | } | ||
190 | 152 | ||
191 | if (node_last != NULL) | 153 | do { |
192 | node_last->next = node_new; | 154 | for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) { |
193 | else | 155 | if (c_iter->bitmap[c_idx] == 0) |
194 | dst->node = node_new; | 156 | continue; |
195 | node_last = node_new; | 157 | |
196 | } | 158 | e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); |
159 | if (e_iter == NULL) | ||
160 | goto netlbl_import_failure; | ||
161 | if (emap_prev == NULL) | ||
162 | ebmap->node = e_iter; | ||
163 | else | ||
164 | emap_prev->next = e_iter; | ||
165 | emap_prev = e_iter; | ||
197 | 166 | ||
198 | if (likely(node_last != NULL)) | 167 | e_iter->startbit = c_iter->startbit + |
199 | dst->highbit = node_last->startbit + MAPSIZE; | 168 | NETLBL_CATMAP_MAPSIZE * c_idx; |
169 | e_iter->map = c_iter->bitmap[c_idx]; | ||
170 | } | ||
171 | c_iter = c_iter->next; | ||
172 | } while (c_iter != NULL); | ||
173 | if (e_iter != NULL) | ||
174 | ebmap->highbit = e_iter->startbit + MAPSIZE; | ||
200 | else | 175 | else |
201 | ebitmap_init(dst); | 176 | ebitmap_destroy(ebmap); |
202 | 177 | ||
203 | return 0; | 178 | return 0; |
179 | |||
180 | netlbl_import_failure: | ||
181 | ebitmap_destroy(ebmap); | ||
182 | return -ENOMEM; | ||
204 | } | 183 | } |
184 | #endif /* CONFIG_NETLABEL */ | ||
205 | 185 | ||
206 | int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) | 186 | int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) |
207 | { | 187 | { |