diff options
Diffstat (limited to 'net/netlabel')
-rw-r--r-- | net/netlabel/netlabel_kapi.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index b35ebf94918c..e03a3282c551 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c | |||
@@ -40,6 +40,207 @@ | |||
40 | #include "netlabel_user.h" | 40 | #include "netlabel_user.h" |
41 | 41 | ||
42 | /* | 42 | /* |
43 | * Security Attribute Functions | ||
44 | */ | ||
45 | |||
46 | /** | ||
47 | * netlbl_secattr_catmap_walk - Walk a LSM secattr catmap looking for a bit | ||
48 | * @catmap: the category bitmap | ||
49 | * @offset: the offset to start searching at, in bits | ||
50 | * | ||
51 | * Description: | ||
52 | * This function walks a LSM secattr category bitmap starting at @offset and | ||
53 | * returns the spot of the first set bit or -ENOENT if no bits are set. | ||
54 | * | ||
55 | */ | ||
56 | int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap, | ||
57 | u32 offset) | ||
58 | { | ||
59 | struct netlbl_lsm_secattr_catmap *iter = catmap; | ||
60 | u32 node_idx; | ||
61 | u32 node_bit; | ||
62 | NETLBL_CATMAP_MAPTYPE bitmap; | ||
63 | |||
64 | if (offset > iter->startbit) { | ||
65 | while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { | ||
66 | iter = iter->next; | ||
67 | if (iter == NULL) | ||
68 | return -ENOENT; | ||
69 | } | ||
70 | node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE; | ||
71 | node_bit = offset - iter->startbit - | ||
72 | (NETLBL_CATMAP_MAPSIZE * node_idx); | ||
73 | } else { | ||
74 | node_idx = 0; | ||
75 | node_bit = 0; | ||
76 | } | ||
77 | bitmap = iter->bitmap[node_idx] >> node_bit; | ||
78 | |||
79 | for (;;) { | ||
80 | if (bitmap != 0) { | ||
81 | while ((bitmap & NETLBL_CATMAP_BIT) == 0) { | ||
82 | bitmap >>= 1; | ||
83 | node_bit++; | ||
84 | } | ||
85 | return iter->startbit + | ||
86 | (NETLBL_CATMAP_MAPSIZE * node_idx) + node_bit; | ||
87 | } | ||
88 | if (++node_idx >= NETLBL_CATMAP_MAPCNT) { | ||
89 | if (iter->next != NULL) { | ||
90 | iter = iter->next; | ||
91 | node_idx = 0; | ||
92 | } else | ||
93 | return -ENOENT; | ||
94 | } | ||
95 | bitmap = iter->bitmap[node_idx]; | ||
96 | node_bit = 0; | ||
97 | } | ||
98 | |||
99 | return -ENOENT; | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * netlbl_secattr_catmap_walk_rng - Find the end of a string of set bits | ||
104 | * @catmap: the category bitmap | ||
105 | * @offset: the offset to start searching at, in bits | ||
106 | * | ||
107 | * Description: | ||
108 | * This function walks a LSM secattr category bitmap starting at @offset and | ||
109 | * returns the spot of the first cleared bit or -ENOENT if the offset is past | ||
110 | * the end of the bitmap. | ||
111 | * | ||
112 | */ | ||
113 | int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap, | ||
114 | u32 offset) | ||
115 | { | ||
116 | struct netlbl_lsm_secattr_catmap *iter = catmap; | ||
117 | u32 node_idx; | ||
118 | u32 node_bit; | ||
119 | NETLBL_CATMAP_MAPTYPE bitmask; | ||
120 | NETLBL_CATMAP_MAPTYPE bitmap; | ||
121 | |||
122 | if (offset > iter->startbit) { | ||
123 | while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { | ||
124 | iter = iter->next; | ||
125 | if (iter == NULL) | ||
126 | return -ENOENT; | ||
127 | } | ||
128 | node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE; | ||
129 | node_bit = offset - iter->startbit - | ||
130 | (NETLBL_CATMAP_MAPSIZE * node_idx); | ||
131 | } else { | ||
132 | node_idx = 0; | ||
133 | node_bit = 0; | ||
134 | } | ||
135 | bitmask = NETLBL_CATMAP_BIT << node_bit; | ||
136 | |||
137 | for (;;) { | ||
138 | bitmap = iter->bitmap[node_idx]; | ||
139 | while (bitmask != 0 && (bitmap & bitmask) != 0) { | ||
140 | bitmask <<= 1; | ||
141 | node_bit++; | ||
142 | } | ||
143 | |||
144 | if (bitmask != 0) | ||
145 | return iter->startbit + | ||
146 | (NETLBL_CATMAP_MAPSIZE * node_idx) + | ||
147 | node_bit - 1; | ||
148 | else if (++node_idx >= NETLBL_CATMAP_MAPCNT) { | ||
149 | if (iter->next == NULL) | ||
150 | return iter->startbit + NETLBL_CATMAP_SIZE - 1; | ||
151 | iter = iter->next; | ||
152 | node_idx = 0; | ||
153 | } | ||
154 | bitmask = NETLBL_CATMAP_BIT; | ||
155 | node_bit = 0; | ||
156 | } | ||
157 | |||
158 | return -ENOENT; | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * netlbl_secattr_catmap_setbit - Set a bit in a LSM secattr catmap | ||
163 | * @catmap: the category bitmap | ||
164 | * @bit: the bit to set | ||
165 | * @flags: memory allocation flags | ||
166 | * | ||
167 | * Description: | ||
168 | * Set the bit specified by @bit in @catmap. Returns zero on success, | ||
169 | * negative values on failure. | ||
170 | * | ||
171 | */ | ||
172 | int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap, | ||
173 | u32 bit, | ||
174 | gfp_t flags) | ||
175 | { | ||
176 | struct netlbl_lsm_secattr_catmap *iter = catmap; | ||
177 | u32 node_bit; | ||
178 | u32 node_idx; | ||
179 | |||
180 | while (iter->next != NULL && | ||
181 | bit >= (iter->startbit + NETLBL_CATMAP_SIZE)) | ||
182 | iter = iter->next; | ||
183 | if (bit >= (iter->startbit + NETLBL_CATMAP_SIZE)) { | ||
184 | iter->next = netlbl_secattr_catmap_alloc(flags); | ||
185 | if (iter->next == NULL) | ||
186 | return -ENOMEM; | ||
187 | iter = iter->next; | ||
188 | iter->startbit = bit & ~(NETLBL_CATMAP_SIZE - 1); | ||
189 | } | ||
190 | |||
191 | /* gcc always rounds to zero when doing integer division */ | ||
192 | node_idx = (bit - iter->startbit) / NETLBL_CATMAP_MAPSIZE; | ||
193 | node_bit = bit - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx); | ||
194 | iter->bitmap[node_idx] |= NETLBL_CATMAP_BIT << node_bit; | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * netlbl_secattr_catmap_setrng - Set a range of bits in a LSM secattr catmap | ||
201 | * @catmap: the category bitmap | ||
202 | * @start: the starting bit | ||
203 | * @end: the last bit in the string | ||
204 | * @flags: memory allocation flags | ||
205 | * | ||
206 | * Description: | ||
207 | * Set a range of bits, starting at @start and ending with @end. Returns zero | ||
208 | * on success, negative values on failure. | ||
209 | * | ||
210 | */ | ||
211 | int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, | ||
212 | u32 start, | ||
213 | u32 end, | ||
214 | gfp_t flags) | ||
215 | { | ||
216 | int ret_val = 0; | ||
217 | struct netlbl_lsm_secattr_catmap *iter = catmap; | ||
218 | u32 iter_max_spot; | ||
219 | u32 spot; | ||
220 | |||
221 | /* XXX - This could probably be made a bit faster by combining writes | ||
222 | * to the catmap instead of setting a single bit each time, but for | ||
223 | * right now skipping to the start of the range in the catmap should | ||
224 | * be a nice improvement over calling the individual setbit function | ||
225 | * repeatedly from a loop. */ | ||
226 | |||
227 | while (iter->next != NULL && | ||
228 | start >= (iter->startbit + NETLBL_CATMAP_SIZE)) | ||
229 | iter = iter->next; | ||
230 | iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE; | ||
231 | |||
232 | for (spot = start; spot <= end && ret_val == 0; spot++) { | ||
233 | if (spot >= iter_max_spot && iter->next != NULL) { | ||
234 | iter = iter->next; | ||
235 | iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE; | ||
236 | } | ||
237 | ret_val = netlbl_secattr_catmap_setbit(iter, spot, GFP_ATOMIC); | ||
238 | } | ||
239 | |||
240 | return ret_val; | ||
241 | } | ||
242 | |||
243 | /* | ||
43 | * LSM Functions | 244 | * LSM Functions |
44 | */ | 245 | */ |
45 | 246 | ||