@@ -213,6 +213,144 @@ static const struct file_operations aa_fs_profile_remove = {
213213 .llseek = default_llseek ,
214214};
215215
216+ /**
217+ * query_data - queries a policy and writes its data to buf
218+ * @buf: the resulting data is stored here (NOT NULL)
219+ * @buf_len: size of buf
220+ * @query: query string used to retrieve data
221+ * @query_len: size of query including second NUL byte
222+ *
223+ * The buffers pointed to by buf and query may overlap. The query buffer is
224+ * parsed before buf is written to.
225+ *
226+ * The query should look like "<LABEL>\0<KEY>\0", where <LABEL> is the name of
227+ * the security confinement context and <KEY> is the name of the data to
228+ * retrieve. <LABEL> and <KEY> must not be NUL-terminated.
229+ *
230+ * Don't expect the contents of buf to be preserved on failure.
231+ *
232+ * Returns: number of characters written to buf or -errno on failure
233+ */
234+ static ssize_t query_data (char * buf , size_t buf_len ,
235+ char * query , size_t query_len )
236+ {
237+ char * out ;
238+ const char * key ;
239+ struct aa_profile * profile ;
240+ struct aa_data * data ;
241+ u32 bytes , blocks ;
242+ __le32 outle32 ;
243+
244+ if (!query_len )
245+ return - EINVAL ; /* need a query */
246+
247+ key = query + strnlen (query , query_len ) + 1 ;
248+ if (key + 1 >= query + query_len )
249+ return - EINVAL ; /* not enough space for a non-empty key */
250+ if (key + strnlen (key , query + query_len - key ) >= query + query_len )
251+ return - EINVAL ; /* must end with NUL */
252+
253+ if (buf_len < sizeof (bytes ) + sizeof (blocks ))
254+ return - EINVAL ; /* not enough space */
255+
256+ profile = aa_current_profile ();
257+
258+ /* We are going to leave space for two numbers. The first is the total
259+ * number of bytes we are writing after the first number. This is so
260+ * users can read the full output without reallocation.
261+ *
262+ * The second number is the number of data blocks we're writing. An
263+ * application might be confined by multiple policies having data in
264+ * the same key.
265+ */
266+ memset (buf , 0 , sizeof (bytes ) + sizeof (blocks ));
267+ out = buf + sizeof (bytes ) + sizeof (blocks );
268+
269+ blocks = 0 ;
270+ if (profile -> data ) {
271+ data = rhashtable_lookup_fast (profile -> data , & key ,
272+ profile -> data -> p );
273+
274+ if (data ) {
275+ if (out + sizeof (outle32 ) + data -> size > buf + buf_len )
276+ return - EINVAL ; /* not enough space */
277+ outle32 = __cpu_to_le32 (data -> size );
278+ memcpy (out , & outle32 , sizeof (outle32 ));
279+ out += sizeof (outle32 );
280+ memcpy (out , data -> data , data -> size );
281+ out += data -> size ;
282+ blocks ++ ;
283+ }
284+ }
285+
286+ outle32 = __cpu_to_le32 (out - buf - sizeof (bytes ));
287+ memcpy (buf , & outle32 , sizeof (outle32 ));
288+ outle32 = __cpu_to_le32 (blocks );
289+ memcpy (buf + sizeof (bytes ), & outle32 , sizeof (outle32 ));
290+
291+ return out - buf ;
292+ }
293+
294+ #define QUERY_CMD_DATA "data\0"
295+ #define QUERY_CMD_DATA_LEN 5
296+
297+ /**
298+ * aa_write_access - generic permissions and data query
299+ * @file: pointer to open apparmorfs/access file
300+ * @ubuf: user buffer containing the complete query string (NOT NULL)
301+ * @count: size of ubuf
302+ * @ppos: position in the file (MUST BE ZERO)
303+ *
304+ * Allows for one permissions or data query per open(), write(), and read()
305+ * sequence. The only queries currently supported are label-based queries for
306+ * permissions or data.
307+ *
308+ * For permissions queries, ubuf must begin with "label\0", followed by the
309+ * profile query specific format described in the query_label() function
310+ * documentation.
311+ *
312+ * For data queries, ubuf must have the form "data\0<LABEL>\0<KEY>\0", where
313+ * <LABEL> is the name of the security confinement context and <KEY> is the
314+ * name of the data to retrieve.
315+ *
316+ * Returns: number of bytes written or -errno on failure
317+ */
318+ static ssize_t aa_write_access (struct file * file , const char __user * ubuf ,
319+ size_t count , loff_t * ppos )
320+ {
321+ char * buf ;
322+ ssize_t len ;
323+
324+ if (* ppos )
325+ return - ESPIPE ;
326+
327+ buf = simple_transaction_get (file , ubuf , count );
328+ if (IS_ERR (buf ))
329+ return PTR_ERR (buf );
330+
331+ if (count > QUERY_CMD_DATA_LEN &&
332+ !memcmp (buf , QUERY_CMD_DATA , QUERY_CMD_DATA_LEN )) {
333+ len = query_data (buf , SIMPLE_TRANSACTION_LIMIT ,
334+ buf + QUERY_CMD_DATA_LEN ,
335+ count - QUERY_CMD_DATA_LEN );
336+ } else
337+ len = - EINVAL ;
338+
339+ if (len < 0 )
340+ return len ;
341+
342+ simple_transaction_set (file , len );
343+
344+ return count ;
345+ }
346+
347+ static const struct file_operations aa_fs_access = {
348+ .write = aa_write_access ,
349+ .read = simple_transaction_read ,
350+ .release = simple_transaction_release ,
351+ .llseek = generic_file_llseek ,
352+ };
353+
216354static int aa_fs_seq_show (struct seq_file * seq , void * v )
217355{
218356 struct aa_fs_entry * fs_file = seq -> private ;
@@ -1078,6 +1216,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
10781216};
10791217
10801218static struct aa_fs_entry aa_fs_entry_apparmor [] = {
1219+ AA_FS_FILE_FOPS (".access" , 0640 , & aa_fs_access ),
10811220 AA_FS_FILE_FOPS (".ns_level" , 0666 , & aa_fs_ns_level ),
10821221 AA_FS_FILE_FOPS (".ns_name" , 0640 , & aa_fs_ns_name ),
10831222 AA_FS_FILE_FOPS ("profiles" , 0440 , & aa_fs_profiles_fops ),
0 commit comments