aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorPaul Moore <pmoore@redhat.com>2014-08-01 11:17:17 -0400
committerPaul Moore <pmoore@redhat.com>2014-08-01 11:17:17 -0400
commit4b8feff251da3d7058b5779e21b33a85c686b974 (patch)
tree600fb14c92a11abf730e9f26236d33ba5ae9c278 /security
parent41c3bd2039e0d7b3dc32313141773f20716ec524 (diff)
netlabel: fix the horribly broken catmap functions
The NetLabel secattr catmap functions, and the SELinux import/export glue routines, were broken in many horrible ways and the SELinux glue code fiddled with the NetLabel catmap structures in ways that we probably shouldn't allow. At some point this "worked", but that was likely due to a bit of dumb luck and sub-par testing (both inflicted by yours truly). This patch corrects these problems by basically gutting the code in favor of something less obtuse and restoring the NetLabel abstractions in the SELinux catmap glue code. Everything is working now, and if it decides to break itself in the future this code will be much easier to debug than the code it replaces. One noteworthy side effect of the changes is that it is no longer necessary to allocate a NetLabel catmap before calling one of the NetLabel APIs to set a bit in the catmap. NetLabel will automatically allocate the catmap nodes when needed, resulting in less allocations when the lowest bit is greater than 255 and less code in the LSMs. Cc: stable@vger.kernel.org Reported-by: Christian Evans <frodox@zoho.com> Signed-off-by: Paul Moore <pmoore@redhat.com> Tested-by: Casey Schaufler <casey@schaufler-ca.com>
Diffstat (limited to 'security')
-rw-r--r--security/selinux/ss/ebitmap.c127
-rw-r--r--security/smack/smack_access.c5
2 files changed, 50 insertions, 82 deletions
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index 820313a04d49..842deca9484d 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -89,48 +89,33 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
89 struct netlbl_lsm_secattr_catmap **catmap) 89 struct netlbl_lsm_secattr_catmap **catmap)
90{ 90{
91 struct ebitmap_node *e_iter = ebmap->node; 91 struct ebitmap_node *e_iter = ebmap->node;
92 struct netlbl_lsm_secattr_catmap *c_iter; 92 unsigned long e_map;
93 u32 cmap_idx, cmap_sft; 93 u32 offset;
94 int i; 94 unsigned int iter;
95 95 int rc;
96 /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
97 * however, it is not always compatible with an array of unsigned long
98 * in ebitmap_node.
99 * In addition, you should pay attention the following implementation
100 * assumes unsigned long has a width equal with or less than 64-bit.
101 */
102 96
103 if (e_iter == NULL) { 97 if (e_iter == NULL) {
104 *catmap = NULL; 98 *catmap = NULL;
105 return 0; 99 return 0;
106 } 100 }
107 101
108 c_iter = netlbl_secattr_catmap_alloc(GFP_ATOMIC); 102 if (*catmap != NULL)
109 if (c_iter == NULL) 103 netlbl_secattr_catmap_free(*catmap);
110 return -ENOMEM; 104 *catmap = NULL;
111 *catmap = c_iter;
112 c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
113 105
114 while (e_iter) { 106 while (e_iter) {
115 for (i = 0; i < EBITMAP_UNIT_NUMS; i++) { 107 offset = e_iter->startbit;
116 unsigned int delta, e_startbit, c_endbit; 108 for (iter = 0; iter < EBITMAP_UNIT_NUMS; iter++) {
117 109 e_map = e_iter->maps[iter];
118 e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE; 110 if (e_map != 0) {
119 c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE; 111 rc = netlbl_secattr_catmap_setlong(catmap,
120 if (e_startbit >= c_endbit) { 112 offset,
121 c_iter->next 113 e_map,
122 = netlbl_secattr_catmap_alloc(GFP_ATOMIC); 114 GFP_ATOMIC);
123 if (c_iter->next == NULL) 115 if (rc != 0)
124 goto netlbl_export_failure; 116 goto netlbl_export_failure;
125 c_iter = c_iter->next;
126 c_iter->startbit
127 = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
128 } 117 }
129 delta = e_startbit - c_iter->startbit; 118 offset += EBITMAP_UNIT_SIZE;
130 cmap_idx = delta / NETLBL_CATMAP_MAPSIZE;
131 cmap_sft = delta % NETLBL_CATMAP_MAPSIZE;
132 c_iter->bitmap[cmap_idx]
133 |= e_iter->maps[i] << cmap_sft;
134 } 119 }
135 e_iter = e_iter->next; 120 e_iter = e_iter->next;
136 } 121 }
@@ -155,56 +140,42 @@ netlbl_export_failure:
155int ebitmap_netlbl_import(struct ebitmap *ebmap, 140int ebitmap_netlbl_import(struct ebitmap *ebmap,
156 struct netlbl_lsm_secattr_catmap *catmap) 141 struct netlbl_lsm_secattr_catmap *catmap)
157{ 142{
143 int rc;
158 struct ebitmap_node *e_iter = NULL; 144 struct ebitmap_node *e_iter = NULL;
159 struct ebitmap_node *emap_prev = NULL; 145 struct ebitmap_node *e_prev = NULL;
160 struct netlbl_lsm_secattr_catmap *c_iter = catmap; 146 u32 offset = 0, idx;
161 u32 c_idx, c_pos, e_idx, e_sft; 147 unsigned long bitmap;
162 148
163 /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, 149 for (;;) {
164 * however, it is not always compatible with an array of unsigned long 150 rc = netlbl_secattr_catmap_getlong(catmap, &offset, &bitmap);
165 * in ebitmap_node. 151 if (rc < 0)
166 * In addition, you should pay attention the following implementation 152 goto netlbl_import_failure;
167 * assumes unsigned long has a width equal with or less than 64-bit. 153 if (offset == (u32)-1)
168 */ 154 return 0;
169
170 do {
171 for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
172 unsigned int delta;
173 u64 map = c_iter->bitmap[c_idx];
174
175 if (!map)
176 continue;
177 155
178 c_pos = c_iter->startbit 156 if (e_iter == NULL ||
179 + c_idx * NETLBL_CATMAP_MAPSIZE; 157 offset >= e_iter->startbit + EBITMAP_SIZE) {
180 if (!e_iter 158 e_prev = e_iter;
181 || c_pos >= e_iter->startbit + EBITMAP_SIZE) { 159 e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
182 e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); 160 if (e_iter == NULL)
183 if (!e_iter) 161 goto netlbl_import_failure;
184 goto netlbl_import_failure; 162 e_iter->startbit = offset & ~(EBITMAP_SIZE - 1);
185 e_iter->startbit 163 if (e_prev == NULL)
186 = c_pos - (c_pos % EBITMAP_SIZE); 164 ebmap->node = e_iter;
187 if (emap_prev == NULL) 165 else
188 ebmap->node = e_iter; 166 e_prev->next = e_iter;
189 else 167 ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
190 emap_prev->next = e_iter;
191 emap_prev = e_iter;
192 }
193 delta = c_pos - e_iter->startbit;
194 e_idx = delta / EBITMAP_UNIT_SIZE;
195 e_sft = delta % EBITMAP_UNIT_SIZE;
196 while (map) {
197 e_iter->maps[e_idx++] |= map & (-1UL);
198 map = EBITMAP_SHIFT_UNIT_SIZE(map);
199 }
200 } 168 }
201 c_iter = c_iter->next;
202 } while (c_iter);
203 if (e_iter != NULL)
204 ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
205 else
206 ebitmap_destroy(ebmap);
207 169
170 /* offset will always be aligned to an unsigned long */
171 idx = EBITMAP_NODE_INDEX(e_iter, offset);
172 e_iter->maps[idx] = bitmap;
173
174 /* next */
175 offset += EBITMAP_UNIT_SIZE;
176 }
177
178 /* NOTE: we should never reach this return */
208 return 0; 179 return 0;
209 180
210netlbl_import_failure: 181netlbl_import_failure:
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 9ecf4f4b67a1..ea1bc5055792 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -435,10 +435,7 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
435 435
436 sap->flags |= NETLBL_SECATTR_MLS_CAT; 436 sap->flags |= NETLBL_SECATTR_MLS_CAT;
437 sap->attr.mls.lvl = level; 437 sap->attr.mls.lvl = level;
438 sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); 438 sap->attr.mls.cat = NULL;
439 if (!sap->attr.mls.cat)
440 return -ENOMEM;
441 sap->attr.mls.cat->startbit = 0;
442 439
443 for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) 440 for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++)
444 for (m = 0x80; m != 0; m >>= 1, cat++) { 441 for (m = 0x80; m != 0; m >>= 1, cat++) {