~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/ccsecurity/permission.c

Version: ~ [ linux-5.14-rc3 ] ~ [ linux-5.13.5 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.53 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.135 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.198 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.240 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.276 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.276 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * security/ccsecurity/permission.c
  3  *
  4  * Copyright (C) 2005-2012  NTT DATA CORPORATION
  5  *
  6  * Version: 1.8.5   2015/11/11
  7  */
  8 
  9 #include "internal.h"
 10 
 11 /***** SECTION1: Constants definition *****/
 12 
 13 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
 14 
 15 /*
 16  * may_open() receives open flags modified by open_to_namei_flags() until
 17  * 2.6.32. We stop here in case some distributions backported ACC_MODE changes,
 18  * for we can't determine whether may_open() receives open flags modified by
 19  * open_to_namei_flags() or not.
 20  */
 21 #ifdef ACC_MODE
 22 #error ACC_MODE already defined.
 23 #endif
 24 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 25 
 26 #if defined(RHEL_MAJOR) && RHEL_MAJOR == 6
 27 /* RHEL6 passes unmodified flags since 2.6.32-71.14.1.el6 . */
 28 #undef ACC_MODE
 29 #define ACC_MODE(x) ("\004\002\006"[(x)&O_ACCMODE])
 30 #endif
 31 
 32 #endif
 33 
 34 /* String table for special mount operations. */
 35 static const char * const ccs_mounts[CCS_MAX_SPECIAL_MOUNT] = {
 36         [CCS_MOUNT_BIND]            = "--bind",
 37         [CCS_MOUNT_MOVE]            = "--move",
 38         [CCS_MOUNT_REMOUNT]         = "--remount",
 39         [CCS_MOUNT_MAKE_UNBINDABLE] = "--make-unbindable",
 40         [CCS_MOUNT_MAKE_PRIVATE]    = "--make-private",
 41         [CCS_MOUNT_MAKE_SLAVE]      = "--make-slave",
 42         [CCS_MOUNT_MAKE_SHARED]     = "--make-shared",
 43 };
 44 
 45 /* Mapping table from "enum ccs_path_acl_index" to "enum ccs_mac_index". */
 46 static const u8 ccs_p2mac[CCS_MAX_PATH_OPERATION] = {
 47         [CCS_TYPE_EXECUTE]    = CCS_MAC_FILE_EXECUTE,
 48         [CCS_TYPE_READ]       = CCS_MAC_FILE_OPEN,
 49         [CCS_TYPE_WRITE]      = CCS_MAC_FILE_OPEN,
 50         [CCS_TYPE_APPEND]     = CCS_MAC_FILE_OPEN,
 51         [CCS_TYPE_UNLINK]     = CCS_MAC_FILE_UNLINK,
 52 #ifdef CONFIG_CCSECURITY_FILE_GETATTR
 53         [CCS_TYPE_GETATTR]    = CCS_MAC_FILE_GETATTR,
 54 #endif
 55         [CCS_TYPE_RMDIR]      = CCS_MAC_FILE_RMDIR,
 56         [CCS_TYPE_TRUNCATE]   = CCS_MAC_FILE_TRUNCATE,
 57         [CCS_TYPE_SYMLINK]    = CCS_MAC_FILE_SYMLINK,
 58         [CCS_TYPE_CHROOT]     = CCS_MAC_FILE_CHROOT,
 59         [CCS_TYPE_UMOUNT]     = CCS_MAC_FILE_UMOUNT,
 60 };
 61 
 62 /* Mapping table from "enum ccs_mkdev_acl_index" to "enum ccs_mac_index". */
 63 const u8 ccs_pnnn2mac[CCS_MAX_MKDEV_OPERATION] = {
 64         [CCS_TYPE_MKBLOCK] = CCS_MAC_FILE_MKBLOCK,
 65         [CCS_TYPE_MKCHAR]  = CCS_MAC_FILE_MKCHAR,
 66 };
 67 
 68 /* Mapping table from "enum ccs_path2_acl_index" to "enum ccs_mac_index". */
 69 const u8 ccs_pp2mac[CCS_MAX_PATH2_OPERATION] = {
 70         [CCS_TYPE_LINK]       = CCS_MAC_FILE_LINK,
 71         [CCS_TYPE_RENAME]     = CCS_MAC_FILE_RENAME,
 72         [CCS_TYPE_PIVOT_ROOT] = CCS_MAC_FILE_PIVOT_ROOT,
 73 };
 74 
 75 /*
 76  * Mapping table from "enum ccs_path_number_acl_index" to "enum ccs_mac_index".
 77  */
 78 const u8 ccs_pn2mac[CCS_MAX_PATH_NUMBER_OPERATION] = {
 79         [CCS_TYPE_CREATE] = CCS_MAC_FILE_CREATE,
 80         [CCS_TYPE_MKDIR]  = CCS_MAC_FILE_MKDIR,
 81         [CCS_TYPE_MKFIFO] = CCS_MAC_FILE_MKFIFO,
 82         [CCS_TYPE_MKSOCK] = CCS_MAC_FILE_MKSOCK,
 83         [CCS_TYPE_IOCTL]  = CCS_MAC_FILE_IOCTL,
 84         [CCS_TYPE_CHMOD]  = CCS_MAC_FILE_CHMOD,
 85         [CCS_TYPE_CHOWN]  = CCS_MAC_FILE_CHOWN,
 86         [CCS_TYPE_CHGRP]  = CCS_MAC_FILE_CHGRP,
 87 };
 88 
 89 #ifdef CONFIG_CCSECURITY_NETWORK
 90 
 91 /*
 92  * Mapping table from "enum ccs_network_acl_index" to "enum ccs_mac_index" for
 93  * inet domain socket.
 94  */
 95 static const u8 ccs_inet2mac[CCS_SOCK_MAX][CCS_MAX_NETWORK_OPERATION] = {
 96         [SOCK_STREAM] = {
 97                 [CCS_NETWORK_BIND]    = CCS_MAC_NETWORK_INET_STREAM_BIND,
 98                 [CCS_NETWORK_LISTEN]  = CCS_MAC_NETWORK_INET_STREAM_LISTEN,
 99                 [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_INET_STREAM_CONNECT,
100                 [CCS_NETWORK_ACCEPT]  = CCS_MAC_NETWORK_INET_STREAM_ACCEPT,
101         },
102         [SOCK_DGRAM] = {
103                 [CCS_NETWORK_BIND]    = CCS_MAC_NETWORK_INET_DGRAM_BIND,
104                 [CCS_NETWORK_SEND]    = CCS_MAC_NETWORK_INET_DGRAM_SEND,
105 #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
106                 [CCS_NETWORK_RECV]    = CCS_MAC_NETWORK_INET_DGRAM_RECV,
107 #endif
108         },
109         [SOCK_RAW]    = {
110                 [CCS_NETWORK_BIND]    = CCS_MAC_NETWORK_INET_RAW_BIND,
111                 [CCS_NETWORK_SEND]    = CCS_MAC_NETWORK_INET_RAW_SEND,
112 #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
113                 [CCS_NETWORK_RECV]    = CCS_MAC_NETWORK_INET_RAW_RECV,
114 #endif
115         },
116 };
117 
118 /*
119  * Mapping table from "enum ccs_network_acl_index" to "enum ccs_mac_index" for
120  * unix domain socket.
121  */
122 static const u8 ccs_unix2mac[CCS_SOCK_MAX][CCS_MAX_NETWORK_OPERATION] = {
123         [SOCK_STREAM] = {
124                 [CCS_NETWORK_BIND]    = CCS_MAC_NETWORK_UNIX_STREAM_BIND,
125                 [CCS_NETWORK_LISTEN]  = CCS_MAC_NETWORK_UNIX_STREAM_LISTEN,
126                 [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_UNIX_STREAM_CONNECT,
127                 [CCS_NETWORK_ACCEPT]  = CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT,
128         },
129         [SOCK_DGRAM] = {
130                 [CCS_NETWORK_BIND]    = CCS_MAC_NETWORK_UNIX_DGRAM_BIND,
131                 [CCS_NETWORK_SEND]    = CCS_MAC_NETWORK_UNIX_DGRAM_SEND,
132 #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
133                 [CCS_NETWORK_RECV]    = CCS_MAC_NETWORK_UNIX_DGRAM_RECV,
134 #endif
135         },
136         [SOCK_SEQPACKET] = {
137                 [CCS_NETWORK_BIND]    = CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND,
138                 [CCS_NETWORK_LISTEN]  = CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
139                 [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
140                 [CCS_NETWORK_ACCEPT]  = CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT,
141         },
142 };
143 
144 #endif
145 
146 #ifdef CONFIG_CCSECURITY_CAPABILITY
147 
148 /*
149  * Mapping table from "enum ccs_capability_acl_index" to "enum ccs_mac_index".
150  */
151 const u8 ccs_c2mac[CCS_MAX_CAPABILITY_INDEX] = {
152         [CCS_USE_ROUTE_SOCKET]  = CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET,
153         [CCS_USE_PACKET_SOCKET] = CCS_MAC_CAPABILITY_USE_PACKET_SOCKET,
154         [CCS_SYS_REBOOT]        = CCS_MAC_CAPABILITY_SYS_REBOOT,
155         [CCS_SYS_VHANGUP]       = CCS_MAC_CAPABILITY_SYS_VHANGUP,
156         [CCS_SYS_SETTIME]       = CCS_MAC_CAPABILITY_SYS_SETTIME,
157         [CCS_SYS_NICE]          = CCS_MAC_CAPABILITY_SYS_NICE,
158         [CCS_SYS_SETHOSTNAME]   = CCS_MAC_CAPABILITY_SYS_SETHOSTNAME,
159         [CCS_USE_KERNEL_MODULE] = CCS_MAC_CAPABILITY_USE_KERNEL_MODULE,
160         [CCS_SYS_KEXEC_LOAD]    = CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD,
161         [CCS_SYS_PTRACE]        = CCS_MAC_CAPABILITY_SYS_PTRACE,
162 };
163 
164 #endif
165 
166 /***** SECTION2: Structure definition *****/
167 
168 /* Structure for holding inet domain socket's address. */
169 struct ccs_inet_addr_info {
170         u16 port;           /* In network byte order. */
171         const u32 *address; /* In network byte order. */
172         bool is_ipv6;
173 };
174 
175 /* Structure for holding unix domain socket's address. */
176 struct ccs_unix_addr_info {
177         u8 *addr; /* This may not be '\0' terminated string. */
178         unsigned int addr_len;
179 };
180 
181 /* Structure for holding socket address. */
182 struct ccs_addr_info {
183         u8 protocol;
184         u8 operation;
185         struct ccs_inet_addr_info inet;
186         struct ccs_unix_addr_info unix0;
187 };
188 
189 /***** SECTION3: Prototype definition section *****/
190 
191 bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
192                    struct ccs_page_dump *dump);
193 void ccs_get_attributes(struct ccs_obj_info *obj);
194 
195 static bool ccs_alphabet_char(const char c);
196 static bool ccs_argv(const unsigned int index, const char *arg_ptr,
197                      const int argc, const struct ccs_argv *argv, u8 *checked);
198 static bool ccs_byte_range(const char *str);
199 static bool ccs_check_entry(struct ccs_request_info *r,
200                             struct ccs_acl_info *ptr);
201 static bool ccs_check_mkdev_acl(struct ccs_request_info *r,
202                                 const struct ccs_acl_info *ptr);
203 static bool ccs_check_mount_acl(struct ccs_request_info *r,
204                                 const struct ccs_acl_info *ptr);
205 static bool ccs_check_path2_acl(struct ccs_request_info *r,
206                                 const struct ccs_acl_info *ptr);
207 static bool ccs_check_path_acl(struct ccs_request_info *r,
208                                const struct ccs_acl_info *ptr);
209 static bool ccs_check_path_number_acl(struct ccs_request_info *r,
210                                       const struct ccs_acl_info *ptr);
211 static bool ccs_compare_number_union(const unsigned long value,
212                                      const struct ccs_number_union *ptr);
213 static bool ccs_condition(struct ccs_request_info *r,
214                           const struct ccs_condition *cond);
215 static bool ccs_decimal(const char c);
216 static bool ccs_envp(const char *env_name, const char *env_value,
217                      const int envc, const struct ccs_envp *envp, u8 *checked);
218 static bool ccs_file_matches_pattern(const char *filename,
219                                      const char *filename_end,
220                                      const char *pattern,
221                                      const char *pattern_end);
222 static bool ccs_file_matches_pattern2(const char *filename,
223                                       const char *filename_end,
224                                       const char *pattern,
225                                       const char *pattern_end);
226 static bool ccs_get_realpath(struct ccs_path_info *buf, struct path *path);
227 static bool ccs_hexadecimal(const char c);
228 static bool ccs_number_matches_group(const unsigned long min,
229                                      const unsigned long max,
230                                      const struct ccs_group *group);
231 static bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
232                                      const struct ccs_path_info *pattern);
233 static bool ccs_path_matches_pattern2(const char *f, const char *p);
234 static bool ccs_scan_bprm(struct ccs_execve *ee, const u16 argc,
235                           const struct ccs_argv *argv, const u16 envc,
236                           const struct ccs_envp *envp);
237 static bool ccs_scan_exec_realpath(struct file *file,
238                                    const struct ccs_name_union *ptr,
239                                    const bool match);
240 static bool ccs_scan_transition(const struct list_head *list,
241                                 const struct ccs_path_info *domainname,
242                                 const struct ccs_path_info *program,
243                                 const char *last_name,
244                                 const enum ccs_transition_type type);
245 static const char *ccs_last_word(const char *name);
246 static const struct ccs_path_info *ccs_compare_name_union
247 (const struct ccs_path_info *name, const struct ccs_name_union *ptr);
248 static const struct ccs_path_info *ccs_path_matches_group
249 (const struct ccs_path_info *pathname, const struct ccs_group *group);
250 static enum ccs_transition_type ccs_transition_type
251 (const struct ccs_policy_namespace *ns, const struct ccs_path_info *domainname,
252  const struct ccs_path_info *program);
253 static int __ccs_chmod_permission(struct dentry *dentry,
254                                   struct vfsmount *vfsmnt, mode_t mode);
255 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
256 static int __ccs_chown_permission(struct dentry *dentry,
257                                   struct vfsmount *vfsmnt, kuid_t user,
258                                   kgid_t group);
259 #else
260 static int __ccs_chown_permission(struct dentry *dentry,
261                                   struct vfsmount *vfsmnt, uid_t user,
262                                   gid_t group);
263 #endif
264 static int __ccs_chroot_permission(const struct path *path);
265 static int __ccs_fcntl_permission(struct file *file, unsigned int cmd,
266                                   unsigned long arg);
267 static int __ccs_ioctl_permission(struct file *filp, unsigned int cmd,
268                                   unsigned long arg);
269 static int __ccs_link_permission(struct dentry *old_dentry,
270                                  struct dentry *new_dentry,
271                                  struct vfsmount *mnt);
272 static int __ccs_mkdir_permission(struct dentry *dentry, struct vfsmount *mnt,
273                                   unsigned int mode);
274 static int __ccs_mknod_permission(struct dentry *dentry, struct vfsmount *mnt,
275                                   const unsigned int mode, unsigned int dev);
276 static int __ccs_mount_permission(const char *dev_name,
277                                   const struct path *path, const char *type,
278                                   unsigned long flags, void *data_page);
279 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
280 static int __ccs_open_exec_permission(struct dentry *dentry,
281                                       struct vfsmount *mnt);
282 #endif
283 static int __ccs_open_permission(struct dentry *dentry, struct vfsmount *mnt,
284                                  const int flag);
285 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL))
286 static int __ccs_parse_table(int __user *name, int nlen, void __user *oldval,
287                              void __user *newval, struct ctl_table *table);
288 #endif
289 static int __ccs_pivot_root_permission(const struct path *old_path,
290                                        const struct path *new_path);
291 static int __ccs_rename_permission(struct dentry *old_dentry,
292                                    struct dentry *new_dentry,
293                                    struct vfsmount *mnt);
294 static int __ccs_rmdir_permission(struct dentry *dentry, struct vfsmount *mnt);
295 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
296 static int __ccs_search_binary_handler(struct linux_binprm *bprm);
297 #else
298 static int __ccs_search_binary_handler(struct linux_binprm *bprm,
299                                        struct pt_regs *regs);
300 #endif
301 static int __ccs_symlink_permission(struct dentry *dentry,
302                                     struct vfsmount *mnt, const char *from);
303 static int __ccs_truncate_permission(struct dentry *dentry,
304                                      struct vfsmount *mnt);
305 static int __ccs_umount_permission(struct vfsmount *mnt, int flags);
306 static int __ccs_unlink_permission(struct dentry *dentry,
307                                    struct vfsmount *mnt);
308 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
309 static int __ccs_uselib_permission(struct dentry *dentry,
310                                    struct vfsmount *mnt);
311 #endif
312 static int ccs_execute_permission(struct ccs_request_info *r,
313                                   const struct ccs_path_info *filename);
314 static int ccs_find_next_domain(struct ccs_execve *ee);
315 static int ccs_get_path(const char *pathname, struct path *path);
316 static int ccs_kern_path(const char *pathname, int flags, struct path *path);
317 static int ccs_mkdev_perm(const u8 operation, struct dentry *dentry,
318                           struct vfsmount *mnt, const unsigned int mode,
319                           unsigned int dev);
320 static int ccs_mount_acl(struct ccs_request_info *r, const char *dev_name,
321                          const struct path *dir, const char *type,
322                          unsigned long flags);
323 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
324 static int ccs_new_open_permission(struct file *filp);
325 #endif
326 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
327 static int ccs_old_chroot_permission(struct nameidata *nd);
328 static int ccs_old_mount_permission(const char *dev_name, struct nameidata *nd,
329                                     const char *type, unsigned long flags,
330                                     void *data_page);
331 static int ccs_old_pivot_root_permission(struct nameidata *old_nd,
332                                          struct nameidata *new_nd);
333 #endif
334 static int ccs_path2_perm(const u8 operation, struct dentry *dentry1,
335                           struct vfsmount *mnt1, struct dentry *dentry2,
336                           struct vfsmount *mnt2);
337 static int ccs_path_number_perm(const u8 type, struct dentry *dentry,
338                                 struct vfsmount *vfsmnt, unsigned long number);
339 static int ccs_path_perm(const u8 operation, struct dentry *dentry,
340                          struct vfsmount *mnt, const char *target);
341 static int ccs_path_permission(struct ccs_request_info *r, u8 operation,
342                                const struct ccs_path_info *filename);
343 static int ccs_start_execve(struct linux_binprm *bprm,
344                             struct ccs_execve **eep);
345 static int ccs_symlink_path(const char *pathname, struct ccs_path_info *name);
346 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
347 static void __ccs_clear_open_mode(void);
348 static void __ccs_save_open_mode(int mode);
349 #endif
350 static void ccs_add_slash(struct ccs_path_info *buf);
351 static void ccs_finish_execve(int retval, struct ccs_execve *ee);
352 
353 #ifdef CONFIG_CCSECURITY_MISC
354 static bool ccs_check_env_acl(struct ccs_request_info *r,
355                               const struct ccs_acl_info *ptr);
356 static int ccs_env_perm(struct ccs_request_info *r, const char *env);
357 static int ccs_environ(struct ccs_execve *ee);
358 #endif
359 
360 #ifdef CONFIG_CCSECURITY_CAPABILITY
361 static bool __ccs_capable(const u8 operation);
362 static bool ccs_check_capability_acl(struct ccs_request_info *r,
363                                      const struct ccs_acl_info *ptr);
364 static bool ccs_kernel_service(void);
365 static int __ccs_ptrace_permission(long request, long pid);
366 static int __ccs_socket_create_permission(int family, int type, int protocol);
367 #endif
368 
369 #ifdef CONFIG_CCSECURITY_NETWORK
370 static bool ccs_address_matches_group(const bool is_ipv6, const u32 *address,
371                                       const struct ccs_group *group);
372 static bool ccs_check_inet_acl(struct ccs_request_info *r,
373                                const struct ccs_acl_info *ptr);
374 static bool ccs_check_unix_acl(struct ccs_request_info *r,
375                                const struct ccs_acl_info *ptr);
376 static bool ccs_kernel_service(void);
377 static int __ccs_socket_bind_permission(struct socket *sock,
378                                         struct sockaddr *addr, int addr_len);
379 static int __ccs_socket_connect_permission(struct socket *sock,
380                                            struct sockaddr *addr,
381                                            int addr_len);
382 static int __ccs_socket_listen_permission(struct socket *sock);
383 static int __ccs_socket_post_accept_permission(struct socket *sock,
384                                                struct socket *newsock);
385 static int __ccs_socket_sendmsg_permission(struct socket *sock,
386                                            struct msghdr *msg, int size);
387 static int ccs_check_inet_address(const struct sockaddr *addr,
388                                   const unsigned int addr_len, const u16 port,
389                                   struct ccs_addr_info *address);
390 static int ccs_check_unix_address(struct sockaddr *addr,
391                                   const unsigned int addr_len,
392                                   struct ccs_addr_info *address);
393 static int ccs_inet_entry(const struct ccs_addr_info *address);
394 static int ccs_unix_entry(const struct ccs_addr_info *address);
395 static u8 ccs_sock_family(struct sock *sk);
396 #endif
397 
398 #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
399 static int __ccs_socket_post_recvmsg_permission(struct sock *sk,
400                                                 struct sk_buff *skb,
401                                                 int flags);
402 #endif
403 
404 #ifdef CONFIG_CCSECURITY_IPC
405 static bool ccs_check_signal_acl(struct ccs_request_info *r,
406                                  const struct ccs_acl_info *ptr);
407 static int ccs_signal_acl(const int pid, const int sig);
408 static int ccs_signal_acl0(pid_t tgid, pid_t pid, int sig);
409 static int ccs_signal_acl2(const int sig, const int pid);
410 #endif
411 
412 #ifdef CONFIG_CCSECURITY_FILE_GETATTR
413 static int __ccs_getattr_permission(struct vfsmount *mnt,
414                                     struct dentry *dentry);
415 #endif
416 
417 #ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
418 static bool ccs_find_execute_handler(struct ccs_execve *ee, const u8 type);
419 static int ccs_try_alt_exec(struct ccs_execve *ee);
420 static void ccs_unescape(unsigned char *dest);
421 #endif
422 
423 #ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
424 static bool ccs_check_task_acl(struct ccs_request_info *r,
425                                const struct ccs_acl_info *ptr);
426 #endif
427 
428 /***** SECTION4: Standalone functions section *****/
429 
430 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
431 
432 /**
433  * ccs_copy_argv - Wrapper for copy_strings_kernel().
434  *
435  * @arg:  String to copy.
436  * @bprm: Pointer to "struct linux_binprm".
437  *
438  * Returns return value of copy_strings_kernel().
439  */
440 static inline int ccs_copy_argv(const char *arg, struct linux_binprm *bprm)
441 {
442         const int ret = copy_strings_kernel(1, &arg, bprm);
443         if (ret >= 0)
444                 bprm->argc++;
445         return ret;
446 }
447 
448 #else
449 
450 /**
451  * ccs_copy_argv - Wrapper for copy_strings_kernel().
452  *
453  * @arg:  String to copy.
454  * @bprm: Pointer to "struct linux_binprm".
455  *
456  * Returns return value of copy_strings_kernel().
457  */
458 static inline int ccs_copy_argv(char *arg, struct linux_binprm *bprm)
459 {
460         const int ret = copy_strings_kernel(1, &arg, bprm);
461         if (ret >= 0)
462                 bprm->argc++;
463         return ret;
464 }
465 
466 #endif
467 
468 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)
469 
470 /**
471  * get_fs_root - Get reference on root directory.
472  *
473  * @fs:   Pointer to "struct fs_struct".
474  * @root: Pointer to "struct path".
475  *
476  * Returns nothing.
477  *
478  * This is for compatibility with older kernels.
479  */
480 static inline void get_fs_root(struct fs_struct *fs, struct path *root)
481 {
482         read_lock(&fs->lock);
483 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
484         *root = fs->root;
485         path_get(root);
486 #else
487         root->dentry = dget(fs->root);
488         root->mnt = mntget(fs->rootmnt);
489 #endif
490         read_unlock(&fs->lock);
491 }
492 
493 #endif
494 
495 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
496 
497 /**
498  * module_put - Put a reference on module.
499  *
500  * @module: Pointer to "struct module". Maybe NULL.
501  *
502  * Returns nothing.
503  *
504  * This is for compatibility with older kernels.
505  */
506 static inline void module_put(struct module *module)
507 {
508         if (module)
509                 __MOD_DEC_USE_COUNT(module);
510 }
511 
512 #endif
513 
514 /**
515  * ccs_put_filesystem - Wrapper for put_filesystem().
516  *
517  * @fstype: Pointer to "struct file_system_type".
518  *
519  * Returns nothing.
520  *
521  * Since put_filesystem() is not exported, I embed put_filesystem() here.
522  */
523 static inline void ccs_put_filesystem(struct file_system_type *fstype)
524 {
525         module_put(fstype->owner);
526 }
527 
528 #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
529 
530 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
531 #if !defined(RHEL_MAJOR) || RHEL_MAJOR != 5
532 #if !defined(AX_MAJOR) || AX_MAJOR != 3
533 
534 /**
535  * ip_hdr - Get "struct iphdr".
536  *
537  * @skb: Pointer to "struct sk_buff".
538  *
539  * Returns pointer to "struct iphdr".
540  *
541  * This is for compatibility with older kernels.
542  */
543 static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
544 {
545         return skb->nh.iph;
546 }
547 
548 /**
549  * udp_hdr - Get "struct udphdr".
550  *
551  * @skb: Pointer to "struct sk_buff".
552  *
553  * Returns pointer to "struct udphdr".
554  *
555  * This is for compatibility with older kernels.
556  */
557 static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
558 {
559         return skb->h.uh;
560 }
561 
562 /**
563  * ipv6_hdr - Get "struct ipv6hdr".
564  *
565  * @skb: Pointer to "struct sk_buff".
566  *
567  * Returns pointer to "struct ipv6hdr".
568  *
569  * This is for compatibility with older kernels.
570  */
571 static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
572 {
573         return skb->nh.ipv6h;
574 }
575 
576 #endif
577 #endif
578 #endif
579 
580 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
581 
582 /**
583  * skb_kill_datagram - Kill a datagram forcibly.
584  *
585  * @sk:    Pointer to "struct sock".
586  * @skb:   Pointer to "struct sk_buff".
587  * @flags: Flags passed to skb_recv_datagram().
588  *
589  * Returns nothing.
590  */
591 static inline void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
592                                      int flags)
593 {
594         /* Clear queue. */
595         if (flags & MSG_PEEK) {
596                 int clear = 0;
597                 spin_lock_irq(&sk->receive_queue.lock);
598                 if (skb == skb_peek(&sk->receive_queue)) {
599                         __skb_unlink(skb, &sk->receive_queue);
600                         clear = 1;
601                 }
602                 spin_unlock_irq(&sk->receive_queue.lock);
603                 if (clear)
604                         kfree_skb(skb);
605         }
606         skb_free_datagram(sk, skb);
607 }
608 
609 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
610 
611 /**
612  * skb_kill_datagram - Kill a datagram forcibly.
613  *
614  * @sk:    Pointer to "struct sock".
615  * @skb:   Pointer to "struct sk_buff".
616  * @flags: Flags passed to skb_recv_datagram().
617  *
618  * Returns nothing.
619  */
620 static inline void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
621                                      int flags)
622 {
623         /* Clear queue. */
624         if (flags & MSG_PEEK) {
625                 int clear = 0;
626                 spin_lock_bh(&sk->sk_receive_queue.lock);
627                 if (skb == skb_peek(&sk->sk_receive_queue)) {
628                         __skb_unlink(skb, &sk->sk_receive_queue);
629                         clear = 1;
630                 }
631                 spin_unlock_bh(&sk->sk_receive_queue.lock);
632                 if (clear)
633                         kfree_skb(skb);
634         }
635         skb_free_datagram(sk, skb);
636 }
637 
638 #endif
639 
640 #endif
641 
642 /***** SECTION5: Variables definition section *****/
643 
644 /* The initial domain. */
645 struct ccs_domain_info ccs_kernel_domain;
646 
647 /* The list for "struct ccs_domain_info". */
648 LIST_HEAD(ccs_domain_list);
649 
650 /***** SECTION6: Dependent functions section *****/
651 
652 /**
653  * ccs_path_matches_group - Check whether the given pathname matches members of the given pathname group.
654  *
655  * @pathname: The name of pathname.
656  * @group:    Pointer to "struct ccs_path_group".
657  *
658  * Returns matched member's pathname if @pathname matches pathnames in @group,
659  * NULL otherwise.
660  *
661  * Caller holds ccs_read_lock().
662  */
663 static const struct ccs_path_info *ccs_path_matches_group
664 (const struct ccs_path_info *pathname, const struct ccs_group *group)
665 {
666         struct ccs_path_group *member;
667         list_for_each_entry_srcu(member, &group->member_list, head.list,
668                                  &ccs_ss) {
669                 if (member->head.is_deleted)
670                         continue;
671                 if (!ccs_path_matches_pattern(pathname, member->member_name))
672                         continue;
673                 return member->member_name;
674         }
675         return NULL;
676 }
677 
678 /**
679  * ccs_number_matches_group - Check whether the given number matches members of the given number group.
680  *
681  * @min:   Min number.
682  * @max:   Max number.
683  * @group: Pointer to "struct ccs_number_group".
684  *
685  * Returns true if @min and @max partially overlaps @group, false otherwise.
686  *
687  * Caller holds ccs_read_lock().
688  */
689 static bool ccs_number_matches_group(const unsigned long min,
690                                      const unsigned long max,
691                                      const struct ccs_group *group)
692 {
693         struct ccs_number_group *member;
694         bool matched = false;
695         list_for_each_entry_srcu(member, &group->member_list, head.list,
696                                  &ccs_ss) {
697                 if (member->head.is_deleted)
698                         continue;
699                 if (min > member->number.values[1] ||
700                     max < member->number.values[0])
701                         continue;
702                 matched = true;
703                 break;
704         }
705         return matched;
706 }
707 
708 /**
709  * ccs_check_entry - Do permission check.
710  *
711  * @r:   Pointer to "struct ccs_request_info".
712  * @ptr: Pointer to "struct ccs_acl_info".
713  *
714  * Returns true on match, false otherwise.
715  *
716  * Caller holds ccs_read_lock().
717  */
718 static bool ccs_check_entry(struct ccs_request_info *r,
719                             struct ccs_acl_info *ptr)
720 {
721         if (ptr->is_deleted || ptr->type != r->param_type)
722                 return false;
723         switch (r->param_type) {
724         case CCS_TYPE_PATH_ACL:
725                 return ccs_check_path_acl(r, ptr);
726         case CCS_TYPE_PATH2_ACL:
727                 return ccs_check_path2_acl(r, ptr);
728         case CCS_TYPE_PATH_NUMBER_ACL:
729                 return ccs_check_path_number_acl(r, ptr);
730         case CCS_TYPE_MKDEV_ACL:
731                 return ccs_check_mkdev_acl(r, ptr);
732         case CCS_TYPE_MOUNT_ACL:
733                 return ccs_check_mount_acl(r, ptr);
734 #ifdef CONFIG_CCSECURITY_MISC
735         case CCS_TYPE_ENV_ACL:
736                 return ccs_check_env_acl(r, ptr);
737 #endif
738 #ifdef CONFIG_CCSECURITY_CAPABILITY
739         case CCS_TYPE_CAPABILITY_ACL:
740                 return ccs_check_capability_acl(r, ptr);
741 #endif
742 #ifdef CONFIG_CCSECURITY_NETWORK
743         case CCS_TYPE_INET_ACL:
744                 return ccs_check_inet_acl(r, ptr);
745         case CCS_TYPE_UNIX_ACL:
746                 return ccs_check_unix_acl(r, ptr);
747 #endif
748 #ifdef CONFIG_CCSECURITY_IPC
749         case CCS_TYPE_SIGNAL_ACL:
750                 return ccs_check_signal_acl(r, ptr);
751 #endif
752 #ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
753         case CCS_TYPE_MANUAL_TASK_ACL:
754                 return ccs_check_task_acl(r, ptr);
755 #endif
756         }
757         return true;
758 }
759 
760 /**
761  * ccs_check_acl - Do permission check.
762  *
763  * @r: Pointer to "struct ccs_request_info".
764  *
765  * Returns 0 on success, negative value otherwise.
766  *
767  * Caller holds ccs_read_lock().
768  */
769 int ccs_check_acl(struct ccs_request_info *r)
770 {
771         const struct ccs_domain_info *domain = ccs_current_domain();
772         int error;
773         do {
774                 struct ccs_acl_info *ptr;
775                 const struct list_head *list = &domain->acl_info_list;
776                 u16 i = 0;
777 retry:
778                 list_for_each_entry_srcu(ptr, list, list, &ccs_ss) {
779                         if (!ccs_check_entry(r, ptr))
780                                 continue;
781                         if (!ccs_condition(r, ptr->cond))
782                                 continue;
783                         r->matched_acl = ptr;
784                         r->granted = true;
785                         ccs_audit_log(r);
786                         return 0;
787                 }
788                 for (; i < CCS_MAX_ACL_GROUPS; i++) {
789                         if (!test_bit(i, domain->group))
790                                 continue;
791                         list = &domain->ns->acl_group[i++];
792                         goto retry;
793                 }
794                 r->granted = false;
795                 error = ccs_audit_log(r);
796         } while (error == CCS_RETRY_REQUEST &&
797                  r->type != CCS_MAC_FILE_EXECUTE);
798         return error;
799 }
800 
801 /**
802  * ccs_last_word - Get last component of a domainname.
803  *
804  * @name: Domainname to check.
805  *
806  * Returns the last word of @name.
807  */
808 static const char *ccs_last_word(const char *name)
809 {
810         const char *cp = strrchr(name, ' ');
811         if (cp)
812                 return cp + 1;
813         return name;
814 }
815 
816 /**
817  * ccs_scan_transition - Try to find specific domain transition type.
818  *
819  * @list:       Pointer to "struct list_head".
820  * @domainname: The name of current domain.
821  * @program:    The name of requested program.
822  * @last_name:  The last component of @domainname.
823  * @type:       One of values in "enum ccs_transition_type".
824  *
825  * Returns true if found one, false otherwise.
826  *
827  * Caller holds ccs_read_lock().
828  */
829 static bool ccs_scan_transition(const struct list_head *list,
830                                 const struct ccs_path_info *domainname,
831                                 const struct ccs_path_info *program,
832                                 const char *last_name,
833                                 const enum ccs_transition_type type)
834 {
835         const struct ccs_transition_control *ptr;
836         list_for_each_entry_srcu(ptr, list, head.list, &ccs_ss) {
837                 if (ptr->head.is_deleted || ptr->type != type)
838                         continue;
839                 if (ptr->domainname) {
840                         if (!ptr->is_last_name) {
841                                 if (ptr->domainname != domainname)
842                                         continue;
843                         } else {
844                                 /*
845                                  * Use direct strcmp() since this is
846                                  * unlikely used.
847                                  */
848                                 if (strcmp(ptr->domainname->name, last_name))
849                                         continue;
850                         }
851                 }
852                 if (ptr->program && ccs_pathcmp(ptr->program, program))
853                         continue;
854                 return true;
855         }
856         return false;
857 }
858 
859 /**
860  * ccs_transition_type - Get domain transition type.
861  *
862  * @ns:         Pointer to "struct ccs_policy_namespace".
863  * @domainname: The name of current domain.
864  * @program:    The name of requested program.
865  *
866  * Returns CCS_TRANSITION_CONTROL_TRANSIT if executing @program causes domain
867  * transition across namespaces, CCS_TRANSITION_CONTROL_INITIALIZE if executing
868  * @program reinitializes domain transition within that namespace,
869  * CCS_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname ,
870  * others otherwise.
871  *
872  * Caller holds ccs_read_lock().
873  */
874 static enum ccs_transition_type ccs_transition_type
875 (const struct ccs_policy_namespace *ns, const struct ccs_path_info *domainname,
876  const struct ccs_path_info *program)
877 {
878         const char *last_name = ccs_last_word(domainname->name);
879         enum ccs_transition_type type = CCS_TRANSITION_CONTROL_NO_RESET;
880         while (type < CCS_MAX_TRANSITION_TYPE) {
881                 const struct list_head * const list =
882                         &ns->policy_list[CCS_ID_TRANSITION_CONTROL];
883                 if (!ccs_scan_transition(list, domainname, program, last_name,
884                                          type)) {
885                         type++;
886                         continue;
887                 }
888                 if (type != CCS_TRANSITION_CONTROL_NO_RESET &&
889                     type != CCS_TRANSITION_CONTROL_NO_INITIALIZE)
890                         break;
891                 /*
892                  * Do not check for reset_domain if no_reset_domain matched.
893                  * Do not check for initialize_domain if no_initialize_domain
894                  * matched.
895                  */
896                 type++;
897                 type++;
898         }
899         return type;
900 }
901 
902 /**
903  * ccs_find_next_domain - Find a domain.
904  *
905  * @ee: Pointer to "struct ccs_execve".
906  *
907  * Returns 0 on success, negative value otherwise.
908  *
909  * Caller holds ccs_read_lock().
910  */
911 static int ccs_find_next_domain(struct ccs_execve *ee)
912 {
913         struct ccs_request_info *r = &ee->r;
914 #ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
915         const struct ccs_path_info *handler = ee->handler;
916 #endif
917         struct ccs_domain_info *domain = NULL;
918         struct ccs_domain_info * const old_domain = ccs_current_domain();
919         struct linux_binprm *bprm = ee->bprm;
920         struct ccs_security *task = ccs_current_security();
921         const struct ccs_path_info *candidate;
922         struct ccs_path_info exename;
923         int retval;
924         bool reject_on_transition_failure = false;
925 
926         /* Get symlink's pathname of program. */
927         retval = ccs_symlink_path(bprm->filename, &exename);
928         if (retval < 0)
929                 return retval;
930 
931 #ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
932         if (handler) {
933                 /* No permission check for execute handler. */
934                 candidate = &exename;
935                 if (ccs_pathcmp(candidate, handler)) {
936                         /* Failed to verify execute handler. */
937                         static u8 counter = 20;
938                         if (counter) {
939                                 counter--;
940                                 printk(KERN_WARNING "Failed to verify: %s\n",
941                                        handler->name);
942                         }
943                         goto out;
944                 }
945         } else
946 #endif
947         {
948                 struct ccs_aggregator *ptr;
949                 struct list_head *list;
950 retry:
951                 /* Check 'aggregator' directive. */
952                 candidate = &exename;
953                 list = &old_domain->ns->policy_list[CCS_ID_AGGREGATOR];
954                 list_for_each_entry_srcu(ptr, list, head.list, &ccs_ss) {
955                         if (ptr->head.is_deleted ||
956                             !ccs_path_matches_pattern(candidate,
957                                                       ptr->original_name))
958                                 continue;
959                         candidate = ptr->aggregated_name;
960                         break;
961                 }
962 
963                 /* Check execute permission. */
964                 retval = ccs_execute_permission(r, candidate);
965                 if (retval == CCS_RETRY_REQUEST)
966                         goto retry;
967                 if (retval < 0)
968                         goto out;
969                 /*
970                  * To be able to specify domainnames with wildcards, use the
971                  * pathname specified in the policy (which may contain
972                  * wildcard) rather than the pathname passed to execve()
973                  * (which never contains wildcard).
974                  */
975                 if (r->param.path.matched_path)
976                         candidate = r->param.path.matched_path;
977         }
978         /*
979          * Check for domain transition preference if "file execute" matched.
980          * If preference is given, make do_execve() fail if domain transition
981          * has failed, for domain transition preference should be used with
982          * destination domain defined.
983          */
984         if (r->ee->transition) {
985                 const char *domainname = r->ee->transition->name;
986                 reject_on_transition_failure = true;
987                 if (!strcmp(domainname, "keep"))
988                         goto force_keep_domain;
989                 if (!strcmp(domainname, "child"))
990                         goto force_child_domain;
991                 if (!strcmp(domainname, "reset"))
992                         goto force_reset_domain;
993                 if (!strcmp(domainname, "initialize"))
994                         goto force_initialize_domain;
995                 if (!strcmp(domainname, "parent")) {
996                         char *cp;
997                         strncpy(ee->tmp, old_domain->domainname->name,
998                                 CCS_EXEC_TMPSIZE - 1);
999                         cp = strrchr(ee->tmp, ' ');
1000                         if (cp)
1001                                 *cp = '\0';
1002                 } else if (*domainname == '<')
1003                         strncpy(ee->tmp, domainname, CCS_EXEC_TMPSIZE - 1);
1004                 else
1005                         snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
1006                                  old_domain->domainname->name, domainname);
1007                 goto force_jump_domain;
1008         }
1009         /*
1010          * No domain transition preference specified.
1011          * Calculate domain to transit to.
1012          */
1013         switch (ccs_transition_type(old_domain->ns, old_domain->domainname,
1014                                     candidate)) {
1015         case CCS_TRANSITION_CONTROL_RESET:
1016 force_reset_domain:
1017                 /* Transit to the root of specified namespace. */
1018                 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<%s>",
1019                          candidate->name);
1020                 /*
1021                  * Make do_execve() fail if domain transition across namespaces
1022                  * has failed.
1023                  */
1024                 reject_on_transition_failure = true;
1025                 break;
1026         case CCS_TRANSITION_CONTROL_INITIALIZE:
1027 force_initialize_domain:
1028                 /* Transit to the child of current namespace's root. */
1029                 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
1030                          old_domain->ns->name, candidate->name);
1031                 break;
1032         case CCS_TRANSITION_CONTROL_KEEP:
1033 force_keep_domain:
1034                 /* Keep current domain. */
1035                 domain = old_domain;
1036                 break;
1037         default:
1038                 if (old_domain == &ccs_kernel_domain && !ccs_policy_loaded) {
1039                         /*
1040                          * Needn't to transit from kernel domain before
1041                          * starting /sbin/init. But transit from kernel domain
1042                          * if executing initializers because they might start
1043                          * before /sbin/init.
1044                          */
1045                         domain = old_domain;
1046                         break;
1047                 }
1048 force_child_domain:
1049                 /* Normal domain transition. */
1050                 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
1051                          old_domain->domainname->name, candidate->name);
1052                 break;
1053         }
1054 force_jump_domain:
1055         /*
1056          * Tell GC that I started execve().
1057          * Also, tell open_exec() to check read permission.
1058          */
1059         task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
1060         /*
1061          * Make task->ccs_flags visible to GC before changing
1062          * task->ccs_domain_info.
1063          */
1064         smp_wmb();
1065         /*
1066          * Proceed to the next domain in order to allow reaching via PID.
1067          * It will be reverted if execve() failed. Reverting is not good.
1068          * But it is better than being unable to reach via PID in interactive
1069          * enforcing mode.
1070          */
1071         if (!domain)
1072                 domain = ccs_assign_domain(ee->tmp, true);
1073         if (domain)
1074                 retval = 0;
1075         else if (reject_on_transition_failure) {
1076                 printk(KERN_WARNING
1077                        "ERROR: Domain '%s' not ready.\n", ee->tmp);
1078                 retval = -ENOMEM;
1079         } else if (r->mode == CCS_CONFIG_ENFORCING)
1080                 retval = -ENOMEM;
1081         else {
1082                 retval = 0;
1083                 if (!old_domain->flags[CCS_DIF_TRANSITION_FAILED]) {
1084                         old_domain->flags[CCS_DIF_TRANSITION_FAILED] = true;
1085                         r->granted = false;
1086                         ccs_write_log(r, "%s",
1087                                       ccs_dif[CCS_DIF_TRANSITION_FAILED]);
1088                         printk(KERN_WARNING
1089                                "ERROR: Domain '%s' not defined.\n", ee->tmp);
1090                 }
1091         }
1092 out:
1093         kfree(exename.name);
1094         return retval;
1095 }
1096 
1097 #ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
1098 
1099 /**
1100  * ccs_unescape - Unescape escaped string.
1101  *
1102  * @dest: String to unescape.
1103  *
1104  * Returns nothing.
1105  */
1106 static void ccs_unescape(unsigned char *dest)
1107 {
1108         unsigned char *src = dest;
1109         unsigned char c;
1110         unsigned char d;
1111         unsigned char e;
1112         while (1) {
1113                 c = *src++;
1114                 if (!c)
1115                         break;
1116                 if (c != '\\') {
1117                         *dest++ = c;
1118                         continue;
1119                 }
1120                 c = *src++;
1121                 if (c == '\\') {
1122                         *dest++ = c;
1123                         continue;
1124                 }
1125                 if (c < '' || c > '3')
1126                         break;
1127                 d = *src++;
1128                 if (d < '' || d > '7')
1129                         break;
1130                 e = *src++;
1131                 if (e < '' || e > '7')
1132                         break;
1133                 *dest++ = ((c - '') << 6) + ((d - '') << 3) + (e - '');
1134         }
1135         *dest = '\0';
1136 }
1137 
1138 /**
1139  * ccs_try_alt_exec - Try to start execute handler.
1140  *
1141  * @ee: Pointer to "struct ccs_execve".
1142  *
1143  * Returns 0 on success, negative value otherwise.
1144  */
1145 static int ccs_try_alt_exec(struct ccs_execve *ee)
1146 {
1147         /*
1148          * Contents of modified bprm.
1149          * The envp[] in original bprm is moved to argv[] so that
1150          * the alternatively executed program won't be affected by
1151          * some dangerous environment variables like LD_PRELOAD.
1152          *
1153          * modified bprm->argc
1154          *    = original bprm->argc + original bprm->envc + 7
1155          * modified bprm->envc
1156          *    = 0
1157          *
1158          * modified bprm->argv[0]
1159          *    = the program's name specified by *_execute_handler
1160          * modified bprm->argv[1]
1161          *    = ccs_current_domain()->domainname->name
1162          * modified bprm->argv[2]
1163          *    = the current process's name
1164          * modified bprm->argv[3]
1165          *    = the current process's information (e.g. uid/gid).
1166          * modified bprm->argv[4]
1167          *    = original bprm->filename
1168          * modified bprm->argv[5]
1169          *    = original bprm->argc in string expression
1170          * modified bprm->argv[6]
1171          *    = original bprm->envc in string expression
1172          * modified bprm->argv[7]
1173          *    = original bprm->argv[0]
1174          *  ...
1175          * modified bprm->argv[bprm->argc + 6]
1176          *     = original bprm->argv[bprm->argc - 1]
1177          * modified bprm->argv[bprm->argc + 7]
1178          *     = original bprm->envp[0]
1179          *  ...
1180          * modified bprm->argv[bprm->envc + bprm->argc + 6]
1181          *     = original bprm->envp[bprm->envc - 1]
1182          */
1183         struct linux_binprm *bprm = ee->bprm;
1184         struct file *filp;
1185         int retval;
1186         const int original_argc = bprm->argc;
1187         const int original_envc = bprm->envc;
1188 
1189         /* Close the requested program's dentry. */
1190         ee->obj.path1.dentry = NULL;
1191         ee->obj.path1.mnt = NULL;
1192         ee->obj.stat_valid[CCS_PATH1] = false;
1193         ee->obj.stat_valid[CCS_PATH1_PARENT] = false;
1194         ee->obj.validate_done = false;
1195         allow_write_access(bprm->file);
1196         fput(bprm->file);
1197         bprm->file = NULL;
1198 
1199         /* Invalidate page dump cache. */
1200         ee->dump.page = NULL;
1201 
1202         /* Move envp[] to argv[] */
1203         bprm->argc += bprm->envc;
1204         bprm->envc = 0;
1205 
1206         /* Set argv[6] */
1207         {
1208                 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
1209                 retval = ccs_copy_argv(ee->tmp, bprm);
1210                 if (retval < 0)
1211                         goto out;
1212         }
1213 
1214         /* Set argv[5] */
1215         {
1216                 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
1217                 retval = ccs_copy_argv(ee->tmp, bprm);
1218                 if (retval < 0)
1219                         goto out;
1220         }
1221 
1222         /* Set argv[4] */
1223         {
1224                 retval = ccs_copy_argv(bprm->filename, bprm);
1225                 if (retval < 0)
1226                         goto out;
1227         }
1228 
1229         /* Set argv[3] */
1230         {
1231 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
1232                 /*
1233                  * Pass uid/gid seen from current user namespace, for these
1234                  * values are used by programs in current user namespace in
1235                  * order to decide whether to execve() or not (rather than by
1236                  * auditing daemon in init's user namespace).
1237                  */
1238                 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1239                          "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1240                          "sgid=%d fsuid=%d fsgid=%d", ccs_sys_getpid(),
1241                          __kuid_val(current_uid()), __kgid_val(current_gid()),
1242                          __kuid_val(current_euid()),
1243                          __kgid_val(current_egid()),
1244                          __kuid_val(current_suid()),
1245                          __kgid_val(current_sgid()),
1246                          __kuid_val(current_fsuid()),
1247                          __kgid_val(current_fsgid()));
1248 #else
1249                 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1250                          "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1251                          "sgid=%d fsuid=%d fsgid=%d", ccs_sys_getpid(),
1252                          current_uid(), current_gid(), current_euid(),
1253                          current_egid(), current_suid(), current_sgid(),
1254                          current_fsuid(), current_fsgid());
1255 #endif
1256                 retval = ccs_copy_argv(ee->tmp, bprm);
1257                 if (retval < 0)
1258                         goto out;
1259         }
1260 
1261         /* Set argv[2] */
1262         {
1263                 char *exe = (char *) ccs_get_exe();
1264                 if (exe) {
1265                         retval = ccs_copy_argv(exe, bprm);
1266                         kfree(exe);
1267                 } else {
1268 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
1269                         retval = ccs_copy_argv("<unknown>", bprm);
1270 #else
1271                         snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");
1272                         retval = ccs_copy_argv(ee->tmp, bprm);
1273 #endif
1274                 }
1275                 if (retval < 0)
1276                         goto out;
1277         }
1278 
1279         /* Set argv[1] */
1280         {
1281 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
1282                 retval = ccs_copy_argv(ccs_current_domain()->domainname->name,
1283                                        bprm);
1284 #else
1285                 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
1286                          ccs_current_domain()->domainname->name);
1287                 retval = ccs_copy_argv(ee->tmp, bprm);
1288 #endif
1289                 if (retval < 0)
1290                         goto out;
1291         }
1292 
1293         /* Set argv[0] */
1294         {
1295                 struct path root;
1296                 char *cp;
1297                 int root_len;
1298                 int handler_len;
1299                 get_fs_root(current->fs, &root);
1300                 cp = ccs_realpath(&root);
1301                 path_put(&root);
1302                 if (!cp) {
1303                         retval = -ENOMEM;
1304                         goto out;
1305                 }
1306                 root_len = strlen(cp);
1307                 retval = strncmp(ee->handler->name, cp, root_len);
1308                 root_len--;
1309                 kfree(cp);
1310                 if (retval) {
1311                         retval = -ENOENT;
1312                         goto out;
1313                 }
1314                 handler_len = ee->handler->total_len + 1;
1315                 cp = kmalloc(handler_len, CCS_GFP_FLAGS);
1316                 if (!cp) {
1317                         retval = -ENOMEM;
1318                         goto out;
1319                 }
1320                 /* ee->handler_path is released by ccs_finish_execve(). */
1321                 ee->handler_path = cp;
1322                 /* Adjust root directory for open_exec(). */
1323                 memmove(cp, ee->handler->name + root_len,
1324                         handler_len - root_len);
1325                 ccs_unescape(cp);
1326                 retval = -ENOENT;
1327                 if (*cp != '/')
1328                         goto out;
1329                 retval = ccs_copy_argv(cp, bprm);
1330                 if (retval < 0)
1331                         goto out;
1332         }
1333 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1334 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1335         bprm->argv_len = bprm->exec - bprm->p;
1336 #endif
1337 #endif
1338 
1339         /*
1340          * OK, now restart the process with execute handler program's dentry.
1341          */
1342         filp = open_exec(ee->handler_path);
1343         if (IS_ERR(filp)) {
1344                 retval = PTR_ERR(filp);
1345                 goto out;
1346         }
1347 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
1348         ee->obj.path1 = filp->f_path;
1349 #else
1350         ee->obj.path1.dentry = filp->f_dentry;
1351         ee->obj.path1.mnt = filp->f_vfsmnt;
1352 #endif
1353         bprm->file = filp;
1354         bprm->filename = ee->handler_path;
1355 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1356         bprm->interp = bprm->filename;
1357 #endif
1358         retval = prepare_binprm(bprm);
1359         if (retval < 0)
1360                 goto out;
1361         ee->r.dont_sleep_on_enforce_error = true;
1362         retval = ccs_find_next_domain(ee);
1363         ee->r.dont_sleep_on_enforce_error = false;
1364 out:
1365         return retval;
1366 }
1367 
1368 /**
1369  * ccs_find_execute_handler - Find an execute handler.
1370  *
1371  * @ee:   Pointer to "struct ccs_execve".
1372  * @type: Type of execute handler.
1373  *
1374  * Returns true if found, false otherwise.
1375  *
1376  * Caller holds ccs_read_lock().
1377  */
1378 static bool ccs_find_execute_handler(struct ccs_execve *ee, const u8 type)
1379 {
1380         struct ccs_request_info *r = &ee->r;
1381         /*
1382          * To avoid infinite execute handler loop, don't use execute handler
1383          * if the current process is marked as execute handler.
1384          */
1385         if (ccs_current_flags() & CCS_TASK_IS_EXECUTE_HANDLER)
1386                 return false;
1387         r->param_type = type;
1388         ccs_check_acl(r);
1389         if (!r->granted)
1390                 return false;
1391         ee->handler = container_of(r->matched_acl, struct ccs_handler_acl,
1392                                    head)->handler;
1393         ee->transition = r->matched_acl && r->matched_acl->cond &&
1394                 r->matched_acl->cond->exec_transit ?
1395                 r->matched_acl->cond->transit : NULL;
1396         return true;
1397 }
1398 
1399 #endif
1400 
1401 #ifdef CONFIG_MMU
1402 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1403 #define CCS_BPRM_MMU
1404 #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3
1405 #define CCS_BPRM_MMU
1406 #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2
1407 #define CCS_BPRM_MMU
1408 #endif
1409 #endif
1410 
1411 /**
1412  * ccs_dump_page - Dump a page to buffer.
1413  *
1414  * @bprm: Pointer to "struct linux_binprm".
1415  * @pos:  Location to dump.
1416  * @dump: Poiner to "struct ccs_page_dump".
1417  *
1418  * Returns true on success, false otherwise.
1419  */
1420 bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1421                    struct ccs_page_dump *dump)
1422 {
1423         struct page *page;
1424         /* dump->data is released by ccs_start_execve(). */
1425         if (!dump->data) {
1426                 dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1427                 if (!dump->data)
1428                         return false;
1429         }
1430         /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1431 #ifdef CCS_BPRM_MMU
1432 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)
1433         if (get_user_pages_remote(current, bprm->mm, pos, 1, 0, 1, &page,
1434                                   NULL) <= 0)
1435                 return false;
1436 #else
1437         if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1438                 return false;
1439 #endif
1440 #else
1441         page = bprm->page[pos / PAGE_SIZE];
1442 #endif
1443         if (page != dump->page) {
1444                 const unsigned int offset = pos % PAGE_SIZE;
1445                 /*
1446                  * Maybe kmap()/kunmap() should be used here.
1447                  * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1448                  * So do I.
1449                  */
1450 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
1451                 char *kaddr = kmap_atomic(page);
1452 #else
1453                 char *kaddr = kmap_atomic(page, KM_USER0);
1454 #endif
1455                 dump->page = page;
1456                 memcpy(dump->data + offset, kaddr + offset,
1457                        PAGE_SIZE - offset);
1458 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
1459                 kunmap_atomic(kaddr);
1460 #else
1461                 kunmap_atomic(kaddr, KM_USER0);
1462 #endif
1463         }
1464         /* Same with put_arg_page(page) in fs/exec.c */
1465 #ifdef CCS_BPRM_MMU
1466         put_page(page);
1467 #endif
1468         return true;
1469 }
1470 
1471 /**
1472  * ccs_start_execve - Prepare for execve() operation.
1473  *
1474  * @bprm: Pointer to "struct linux_binprm".
1475  * @eep:  Pointer to "struct ccs_execve *".
1476  *
1477  * Returns 0 on success, negative value otherwise.
1478  */
1479 static int ccs_start_execve(struct linux_binprm *bprm,
1480                             struct ccs_execve **eep)
1481 {
1482         int retval;
1483         struct ccs_security *task = ccs_current_security();
1484         struct ccs_execve *ee;
1485         int idx;
1486         *eep = NULL;
1487         ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
1488         if (!ee)
1489                 return -ENOMEM;
1490         ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1491         if (!ee->tmp) {
1492                 kfree(ee);
1493                 return -ENOMEM;
1494         }
1495         idx = ccs_read_lock();
1496         /* ee->dump->data is allocated by ccs_dump_page(). */
1497         ee->previous_domain = task->ccs_domain_info;
1498         /* Clear manager flag. */
1499         task->ccs_flags &= ~CCS_TASK_IS_MANAGER;
1500         *eep = ee;
1501         ccs_init_request_info(&ee->r, CCS_MAC_FILE_EXECUTE);
1502         ee->r.ee = ee;
1503         ee->bprm = bprm;
1504         ee->r.obj = &ee->obj;
1505 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
1506         ee->obj.path1 = bprm->file->f_path;
1507 #else
1508         ee->obj.path1.dentry = bprm->file->f_dentry;
1509         ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1510 #endif
1511 #ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
1512         /*
1513          * No need to call ccs_environ() for execute handler because envp[] is
1514          * moved to argv[].
1515          */
1516         if (ccs_find_execute_handler(ee, CCS_TYPE_AUTO_EXECUTE_HANDLER)) {
1517                 retval = ccs_try_alt_exec(ee);
1518                 goto done;
1519         }
1520 #endif
1521         retval = ccs_find_next_domain(ee);
1522 #ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
1523         if (retval == -EPERM &&
1524             ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {
1525                 retval = ccs_try_alt_exec(ee);
1526                 goto done;
1527         }
1528 #endif
1529 #ifdef CONFIG_CCSECURITY_MISC
1530         if (!retval)
1531                 retval = ccs_environ(ee);
1532 #endif
1533 #ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
1534 done:
1535 #endif
1536         ccs_read_unlock(idx);
1537         kfree(ee->tmp);
1538         ee->tmp = NULL;
1539         kfree(ee->dump.data);
1540         ee->dump.data = NULL;
1541         return retval;
1542 }
1543 
1544 /**
1545  * ccs_finish_execve - Clean up execve() operation.
1546  *
1547  * @retval: Return code of an execve() operation.
1548  * @ee:     Pointer to "struct ccs_execve".
1549  *
1550  * Returns nothing.
1551  */
1552 static void ccs_finish_execve(int retval, struct ccs_execve *ee)
1553 {
1554         struct ccs_security *task = ccs_current_security();
1555         if (!ee)
1556                 return;
1557         if (retval < 0) {
1558                 task->ccs_domain_info = ee->previous_domain;
1559                 /*
1560                  * Make task->ccs_domain_info visible to GC before changing
1561                  * task->ccs_flags.
1562                  */
1563                 smp_wmb();
1564         } else {
1565                 /* Mark the current process as execute handler. */
1566                 if (ee->handler)
1567                         task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1568                 /* Mark the current process as normal process. */
1569                 else
1570                         task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1571         }
1572         /* Tell GC that I finished execve(). */
1573         task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
1574         kfree(ee->handler_path);
1575         kfree(ee);
1576 }
1577 
1578 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
1579 
1580 /**
1581  * __ccs_search_binary_handler - Main routine for do_execve().
1582  *
1583  * @bprm: Pointer to "struct linux_binprm".
1584  *
1585  * Returns 0 on success, negative value otherwise.
1586  *
1587  * Performs permission checks for do_execve() and domain transition.
1588  * Domain transition by "struct ccs_domain_transition_control" and
1589  * "auto_domain_transition=" parameter of "struct ccs_condition" are reverted
1590  * if do_execve() failed.
1591  * Garbage collector does not remove "struct ccs_domain_info" from
1592  * ccs_domain_list nor kfree("struct ccs_domain_info") if the current thread is
1593  * marked as CCS_TASK_IS_IN_EXECVE.
1594  */
1595 static int __ccs_search_binary_handler(struct linux_binprm *bprm)
1596 {
1597         struct ccs_execve *ee;
1598         int retval;
1599 #ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
1600         if (!ccs_policy_loaded)
1601                 ccsecurity_exports.load_policy(bprm->filename);
1602 #endif
1603         retval = ccs_start_execve(bprm, &ee);
1604         if (!retval)
1605                 retval = search_binary_handler(bprm);
1606         ccs_finish_execve(retval, ee);
1607         return retval;
1608 }
1609 
1610 #else
1611 
1612 /**
1613  * __ccs_search_binary_handler - Main routine for do_execve().
1614  *
1615  * @bprm: Pointer to "struct linux_binprm".
1616  * @regs: Pointer to "struct pt_regs".
1617  *
1618  * Returns 0 on success, negative value otherwise.
1619  *
1620  * Performs permission checks for do_execve() and domain transition.
1621  * Domain transition by "struct ccs_domain_transition_control" and
1622  * "auto_domain_transition=" parameter of "struct ccs_condition" are reverted
1623  * if do_execve() failed.
1624  * Garbage collector does not remove "struct ccs_domain_info" from
1625  * ccs_domain_list nor kfree("struct ccs_domain_info") if the current thread is
1626  * marked as CCS_TASK_IS_IN_EXECVE.
1627  */
1628 static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1629                                        struct pt_regs *regs)
1630 {
1631         struct ccs_execve *ee;
1632         int retval;
1633 #ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
1634         if (!ccs_policy_loaded)
1635                 ccsecurity_exports.load_policy(bprm->filename);
1636 #endif
1637         retval = ccs_start_execve(bprm, &ee);
1638         if (!retval)
1639                 retval = search_binary_handler(bprm, regs);
1640         ccs_finish_execve(retval, ee);
1641         return retval;
1642 }
1643 
1644 #endif
1645 
1646 /**
1647  * ccs_permission_init - Register permission check hooks.
1648  *
1649  * Returns nothing.
1650  */
1651 void __init ccs_permission_init(void)
1652 {
1653 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
1654         ccsecurity_ops.save_open_mode = __ccs_save_open_mode;
1655         ccsecurity_ops.clear_open_mode = __ccs_clear_open_mode;
1656         ccsecurity_ops.open_permission = __ccs_open_permission;
1657 #else
1658         ccsecurity_ops.open_permission = ccs_new_open_permission;
1659 #endif
1660         ccsecurity_ops.fcntl_permission = __ccs_fcntl_permission;
1661         ccsecurity_ops.ioctl_permission = __ccs_ioctl_permission;
1662         ccsecurity_ops.chmod_permission = __ccs_chmod_permission;
1663         ccsecurity_ops.chown_permission = __ccs_chown_permission;
1664 #ifdef CONFIG_CCSECURITY_FILE_GETATTR
1665         ccsecurity_ops.getattr_permission = __ccs_getattr_permission;
1666 #endif
1667 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1668         ccsecurity_ops.pivot_root_permission = __ccs_pivot_root_permission;
1669         ccsecurity_ops.chroot_permission = __ccs_chroot_permission;
1670 #else
1671         ccsecurity_ops.pivot_root_permission = ccs_old_pivot_root_permission;
1672         ccsecurity_ops.chroot_permission = ccs_old_chroot_permission;
1673 #endif
1674         ccsecurity_ops.umount_permission = __ccs_umount_permission;
1675         ccsecurity_ops.mknod_permission = __ccs_mknod_permission;
1676         ccsecurity_ops.mkdir_permission = __ccs_mkdir_permission;
1677         ccsecurity_ops.rmdir_permission = __ccs_rmdir_permission;
1678         ccsecurity_ops.unlink_permission = __ccs_unlink_permission;
1679         ccsecurity_ops.symlink_permission = __ccs_symlink_permission;
1680         ccsecurity_ops.truncate_permission = __ccs_truncate_permission;
1681         ccsecurity_ops.rename_permission = __ccs_rename_permission;
1682         ccsecurity_ops.link_permission = __ccs_link_permission;
1683 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
1684         ccsecurity_ops.open_exec_permission = __ccs_open_exec_permission;
1685         ccsecurity_ops.uselib_permission = __ccs_uselib_permission;
1686 #endif
1687 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL))
1688         ccsecurity_ops.parse_table = __ccs_parse_table;
1689 #endif
1690 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1691         ccsecurity_ops.mount_permission = __ccs_mount_permission;
1692 #else
1693         ccsecurity_ops.mount_permission = ccs_old_mount_permission;
1694 #endif
1695 #ifdef CONFIG_CCSECURITY_CAPABILITY
1696         ccsecurity_ops.socket_create_permission =
1697                 __ccs_socket_create_permission;
1698 #endif
1699 #ifdef CONFIG_CCSECURITY_NETWORK
1700         ccsecurity_ops.socket_listen_permission =
1701                 __ccs_socket_listen_permission;
1702         ccsecurity_ops.socket_connect_permission =
1703                 __ccs_socket_connect_permission;
1704         ccsecurity_ops.socket_bind_permission = __ccs_socket_bind_permission;
1705         ccsecurity_ops.socket_post_accept_permission =
1706                 __ccs_socket_post_accept_permission;
1707         ccsecurity_ops.socket_sendmsg_permission =
1708                 __ccs_socket_sendmsg_permission;
1709 #endif
1710 #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
1711         ccsecurity_ops.socket_post_recvmsg_permission =
1712                 __ccs_socket_post_recvmsg_permission;
1713 #endif
1714 #ifdef CONFIG_CCSECURITY_IPC
1715         ccsecurity_ops.kill_permission = ccs_signal_acl;
1716         ccsecurity_ops.tgkill_permission = ccs_signal_acl0;
1717         ccsecurity_ops.tkill_permission = ccs_signal_acl;
1718         ccsecurity_ops.sigqueue_permission = ccs_signal_acl;
1719         ccsecurity_ops.tgsigqueue_permission = ccs_signal_acl0;
1720 #endif
1721 #ifdef CONFIG_CCSECURITY_CAPABILITY
1722         ccsecurity_ops.capable = __ccs_capable;
1723         ccsecurity_ops.ptrace_permission = __ccs_ptrace_permission;
1724 #endif
1725         ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1726 }
1727 
1728 /**
1729  * ccs_kern_path - Wrapper for kern_path().
1730  *
1731  * @pathname: Pathname to resolve. Maybe NULL.
1732  * @flags:    Lookup flags.
1733  * @path:     Pointer to "struct path".
1734  *
1735  * Returns 0 on success, negative value otherwise.
1736  */
1737 static int ccs_kern_path(const char *pathname, int flags, struct path *path)
1738 {
1739 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
1740         if (!pathname || kern_path(pathname, flags, path))
1741                 return -ENOENT;
1742 #else
1743         struct nameidata nd;
1744         if (!pathname || path_lookup(pathname, flags, &nd))
1745                 return -ENOENT;
1746 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1747         *path = nd.path;
1748 #else
1749         path->dentry = nd.dentry;
1750         path->mnt = nd.mnt;
1751 #endif
1752 #endif
1753         return 0;
1754 }
1755 
1756 /**
1757  * ccs_get_path - Get dentry/vfsmmount of a pathname.
1758  *
1759  * @pathname: The pathname to solve. Maybe NULL.
1760  * @path:     Pointer to "struct path".
1761  *
1762  * Returns 0 on success, negative value otherwise.
1763  */
1764 static int ccs_get_path(const char *pathname, struct path *path)
1765 {
1766 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1767         return ccs_kern_path(pathname, LOOKUP_FOLLOW, path);
1768 #else
1769         return ccs_kern_path(pathname, LOOKUP_FOLLOW | LOOKUP_POSITIVE, path);
1770 #endif
1771 }
1772 
1773 /**
1774  * ccs_symlink_path - Get symlink's pathname.
1775  *
1776  * @pathname: The pathname to solve. Maybe NULL.
1777  * @name:     Pointer to "struct ccs_path_info".
1778  *
1779  * Returns 0 on success, negative value otherwise.
1780  *
1781  * This function uses kzalloc(), so caller must kfree() if this function
1782  * didn't return NULL.
1783  */
1784 static int ccs_symlink_path(const char *pathname, struct ccs_path_info *name)
1785 {
1786         char *buf;
1787         struct path path;
1788 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1789         if (ccs_kern_path(pathname, 0, &path))
1790                 return -ENOENT;
1791 #else
1792         if (ccs_kern_path(pathname, LOOKUP_POSITIVE, &path))
1793                 return -ENOENT;
1794 #endif
1795         buf = ccs_realpath(&path);
1796         path_put(&path);
1797         if (buf) {
1798                 name->name = buf;
1799                 ccs_fill_path_info(name);
1800                 return 0;
1801         }
1802         return -ENOMEM;
1803 }
1804 
1805 /**
1806  * ccs_check_mount_acl - Check permission for path path path number operation.
1807  *
1808  * @r:   Pointer to "struct ccs_request_info".
1809  * @ptr: Pointer to "struct ccs_acl_info".
1810  *
1811  * Returns true if granted, false otherwise.
1812  */
1813 static bool ccs_check_mount_acl(struct ccs_request_info *r,
1814                                 const struct ccs_acl_info *ptr)
1815 {
1816         const struct ccs_mount_acl *acl =
1817                 container_of(ptr, typeof(*acl), head);
1818         return ccs_compare_number_union(r->param.mount.flags, &acl->flags) &&
1819                 ccs_compare_name_union(r->param.mount.type, &acl->fs_type) &&
1820                 ccs_compare_name_union(r->param.mount.dir, &acl->dir_name) &&
1821                 (!r->param.mount.need_dev ||
1822                  ccs_compare_name_union(r->param.mount.dev, &acl->dev_name));
1823 }
1824 
1825 /**
1826  * ccs_mount_acl - Check permission for mount() operation.
1827  *
1828  * @r:        Pointer to "struct ccs_request_info".
1829  * @dev_name: Name of device file. Maybe NULL.
1830  * @dir:      Pointer to "struct path".
1831  * @type:     Name of filesystem type.
1832  * @flags:    Mount options.
1833  *
1834  * Returns 0 on success, negative value otherwise.
1835  *
1836  * Caller holds ccs_read_lock().
1837  */
1838 static int ccs_mount_acl(struct ccs_request_info *r, const char *dev_name,
1839                          const struct path *dir, const char *type,
1840                          unsigned long flags)
1841 {
1842         struct ccs_obj_info obj = { };
1843         struct file_system_type *fstype = NULL;
1844         const char *requested_type = NULL;
1845         const char *requested_dir_name = NULL;
1846         const char *requested_dev_name = NULL;
1847         struct ccs_path_info rtype;
1848         struct ccs_path_info rdev;
1849         struct ccs_path_info rdir;
1850         int need_dev = 0;
1851         int error = -ENOMEM;
1852         r->obj = &obj;
1853 
1854         /* Get fstype. */
1855         requested_type = ccs_encode(type);
1856         if (!requested_type)
1857                 goto out;
1858         rtype.name = requested_type;
1859         ccs_fill_path_info(&rtype);
1860 
1861         /* Get mount point. */
1862         obj.path2 = *dir;
1863         requested_dir_name = ccs_realpath(dir);
1864         if (!requested_dir_name) {
1865                 error = -ENOMEM;
1866                 goto out;
1867         }
1868         rdir.name = requested_dir_name;
1869         ccs_fill_path_info(&rdir);
1870 
1871         /* Compare fs name. */
1872         if (type == ccs_mounts[CCS_MOUNT_REMOUNT]) {
1873                 /* dev_name is ignored. */
1874         } else if (type == ccs_mounts[CCS_MOUNT_MAKE_UNBINDABLE] ||
1875                    type == ccs_mounts[CCS_MOUNT_MAKE_PRIVATE] ||
1876                    type == ccs_mounts[CCS_MOUNT_MAKE_SLAVE] ||
1877                    type == ccs_mounts[CCS_MOUNT_MAKE_SHARED]) {
1878                 /* dev_name is ignored. */
1879         } else if (type == ccs_mounts[CCS_MOUNT_BIND] ||
1880                    type == ccs_mounts[CCS_MOUNT_MOVE]) {
1881                 need_dev = -1; /* dev_name is a directory */
1882         } else {
1883                 fstype = get_fs_type(type);
1884                 if (!fstype) {
1885                         error = -ENODEV;
1886                         goto out;
1887                 }
1888                 if (fstype->fs_flags & FS_REQUIRES_DEV)
1889                         /* dev_name is a block device file. */
1890                         need_dev = 1;
1891         }
1892         if (need_dev) {
1893                 /* Get mount point or device file. */
1894                 if (ccs_get_path(dev_name, &obj.path1)) {
1895                         error = -ENOENT;
1896                         goto out;
1897                 }
1898                 requested_dev_name = ccs_realpath(&obj.path1);
1899                 if (!requested_dev_name) {
1900                         error = -ENOENT;
1901                         goto out;
1902                 }
1903         } else {
1904                 /* Map dev_name to "<NULL>" if no dev_name given. */
1905                 if (!dev_name)
1906                         dev_name = "<NULL>";
1907                 requested_dev_name = ccs_encode(dev_name);
1908                 if (!requested_dev_name) {
1909                         error = -ENOMEM;
1910                         goto out;
1911                 }
1912         }
1913         rdev.name = requested_dev_name;
1914         ccs_fill_path_info(&rdev);
1915         r->param_type = CCS_TYPE_MOUNT_ACL;
1916         r->param.mount.need_dev = need_dev;
1917         r->param.mount.dev = &rdev;
1918         r->param.mount.dir = &rdir;
1919         r->param.mount.type = &rtype;
1920         r->param.mount.flags = flags;
1921         error = ccs_check_acl(r);
1922 out:
1923         kfree(requested_dev_name);
1924         kfree(requested_dir_name);
1925         if (fstype)
1926                 ccs_put_filesystem(fstype);
1927         kfree(requested_type);
1928         /* Drop refcount obtained by ccs_get_path(). */
1929         if (obj.path1.dentry)
1930                 path_put(&obj.path1);
1931         return error;
1932 }
1933 
1934 /**
1935  * __ccs_mount_permission - Check permission for mount() operation.
1936  *
1937  * @dev_name:  Name of device file. Maybe NULL.
1938  * @path:      Pointer to "struct path".
1939  * @type:      Name of filesystem type. Maybe NULL.
1940  * @flags:     Mount options.
1941  * @data_page: Optional data. Maybe NULL.
1942  *
1943  * Returns 0 on success, negative value otherwise.
1944  */
1945 static int __ccs_mount_permission(const char *dev_name,
1946                                   const struct path *path, const char *type,
1947                                   unsigned long flags, void *data_page)
1948 {
1949         struct ccs_request_info r;
1950         int error = 0;
1951         int idx;
1952         if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
1953                 flags &= ~MS_MGC_MSK;
1954         if (flags & MS_REMOUNT) {
1955                 type = ccs_mounts[CCS_MOUNT_REMOUNT];
1956                 flags &= ~MS_REMOUNT;
1957         } else if (flags & MS_BIND) {
1958                 type = ccs_mounts[CCS_MOUNT_BIND];
1959                 flags &= ~MS_BIND;
1960         } else if (flags & MS_SHARED) {
1961                 if (flags & (MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1962                         return -EINVAL;
1963                 type = ccs_mounts[CCS_MOUNT_MAKE_SHARED];
1964                 flags &= ~MS_SHARED;
1965         } else if (flags & MS_PRIVATE) {
1966                 if (flags & (MS_SHARED | MS_SLAVE | MS_UNBINDABLE))
1967                         return -EINVAL;
1968                 type = ccs_mounts[CCS_MOUNT_MAKE_PRIVATE];
1969                 flags &= ~MS_PRIVATE;
1970         } else if (flags & MS_SLAVE) {
1971                 if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE))
1972                         return -EINVAL;
1973                 type = ccs_mounts[CCS_MOUNT_MAKE_SLAVE];
1974                 flags &= ~MS_SLAVE;
1975         } else if (flags & MS_UNBINDABLE) {
1976                 if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE))
1977                         return -EINVAL;
1978                 type = ccs_mounts[CCS_MOUNT_MAKE_UNBINDABLE];
1979                 flags &= ~MS_UNBINDABLE;
1980         } else if (flags & MS_MOVE) {
1981                 type = ccs_mounts[CCS_MOUNT_MOVE];
1982                 flags &= ~MS_MOVE;
1983         }
1984         if (!type)
1985                 type = "<NULL>";
1986         idx = ccs_read_lock();
1987         if (ccs_init_request_info(&r, CCS_MAC_FILE_MOUNT)
1988             != CCS_CONFIG_DISABLED)
1989                 error = ccs_mount_acl(&r, dev_name, path, type, flags);
1990         ccs_read_unlock(idx);
1991         return error;
1992 }
1993 
1994 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1995 
1996 /**
1997  * ccs_old_mount_permission - Check permission for mount() operation.
1998  *
1999  * @dev_name:  Name of device file.
2000  * @nd:        Pointer to "struct nameidata".
2001  * @type:      Name of filesystem type. Maybe NULL.
2002  * @flags:     Mount options.
2003  * @data_page: Optional data. Maybe NULL.
2004  *
2005  * Returns 0 on success, negative value otherwise.
2006  */
2007 static int ccs_old_mount_permission(const char *dev_name, struct nameidata *nd,
2008                                     const char *type, unsigned long flags,
2009                                     void *data_page)
2010 {
2011         struct path path = { nd->mnt, nd->dentry };
2012         return __ccs_mount_permission(dev_name, &path, type, flags, data_page);
2013 }
2014 
2015 #endif
2016 
2017 /**
2018  * ccs_compare_number_union - Check whether a value matches "struct ccs_number_union" or not.
2019  *
2020  * @value: Number to check.
2021  * @ptr:   Pointer to "struct ccs_number_union".
2022  *
2023  * Returns true if @value matches @ptr, false otherwise.
2024  */
2025 static bool ccs_compare_number_union(const unsigned long value,
2026                                      const struct ccs_number_union *ptr)
2027 {
2028         if (ptr->group)
2029                 return ccs_number_matches_group(value, value, ptr->group);
2030         return value >= ptr->values[0] && value <= ptr->values[1];
2031 }
2032 
2033 /**
2034  * ccs_compare_name_union - Check whether a name matches "struct ccs_name_union" or not.
2035  *
2036  * @name: Pointer to "struct ccs_path_info".
2037  * @ptr:  Pointer to "struct ccs_name_union".
2038  *
2039  * Returns "struct ccs_path_info" if @name matches @ptr, NULL otherwise.
2040  */
2041 static const struct ccs_path_info *ccs_compare_name_union
2042 (const struct ccs_path_info *name, const struct ccs_name_union *ptr)
2043 {
2044         if (ptr->group)
2045                 return ccs_path_matches_group(name, ptr->group);
2046         if (ccs_path_matches_pattern(name, ptr->filename))
2047                 return ptr->filename;
2048         return NULL;
2049 }
2050 
2051 /**
2052  * ccs_add_slash - Add trailing '/' if needed.
2053  *
2054  * @buf: Pointer to "struct ccs_path_info".
2055  *
2056  * Returns nothing.
2057  *
2058  * @buf must be generated by ccs_encode() because this function does not
2059  * allocate memory for adding '/'.
2060  */
2061 static void ccs_add_slash(struct ccs_path_info *buf)
2062 {
2063         if (buf->is_dir)
2064                 return;
2065         /* This is OK because ccs_encode() reserves space for appending "/". */
2066         strcat((char *) buf->name, "/");
2067         ccs_fill_path_info(buf);
2068 }
2069 
2070 /**
2071  * ccs_get_realpath - Get realpath.
2072  *
2073  * @buf:  Pointer to "struct ccs_path_info".
2074  * @path: Pointer to "struct path". @path->mnt may be NULL.
2075  *
2076  * Returns true on success, false otherwise.
2077  */
2078 static bool ccs_get_realpath(struct ccs_path_info *buf, struct path *path)
2079 {
2080         buf->name = ccs_realpath(path);
2081         if (buf->name) {
2082                 ccs_fill_path_info(buf);
2083                 return true;
2084         }
2085         return false;
2086 }
2087 
2088 /**
2089  * ccs_check_path_acl - Check permission for path operation.
2090  *
2091  * @r:   Pointer to "struct ccs_request_info".
2092  * @ptr: Pointer to "struct ccs_acl_info".
2093  *
2094  * Returns true if granted, false otherwise.
2095  *
2096  * To be able to use wildcard for domain transition, this function sets
2097  * matching entry on success. Since the caller holds ccs_read_lock(),
2098  * it is safe to set matching entry.
2099  */
2100 static bool ccs_check_path_acl(struct ccs_request_info *r,
2101                                const struct ccs_acl_info *ptr)
2102 {
2103         const struct ccs_path_acl *acl = container_of(ptr, typeof(*acl), head);
2104         if (ptr->perm & (1 << r->param.path.operation)) {
2105                 r->param.path.matched_path =
2106                         ccs_compare_name_union(r->param.path.filename,
2107                                                &acl->name);
2108                 return r->param.path.matched_path != NULL;
2109         }
2110         return false;
2111 }
2112 
2113 /**
2114  * ccs_check_path_number_acl - Check permission for path number operation.
2115  *
2116  * @r:   Pointer to "struct ccs_request_info".
2117  * @ptr: Pointer to "struct ccs_acl_info".
2118  *
2119  * Returns true if granted, false otherwise.
2120  */
2121 static bool ccs_check_path_number_acl(struct ccs_request_info *r,
2122                                       const struct ccs_acl_info *ptr)
2123 {
2124         const struct ccs_path_number_acl *acl =
2125                 container_of(ptr, typeof(*acl), head);
2126         return (ptr->perm & (1 << r->param.path_number.operation)) &&
2127                 ccs_compare_number_union(r->param.path_number.number,
2128                                          &acl->number) &&
2129                 ccs_compare_name_union(r->param.path_number.filename,
2130                                        &acl->name);
2131 }
2132 
2133 /**
2134  * ccs_check_path2_acl - Check permission for path path operation.
2135  *
2136  * @r:   Pointer to "struct ccs_request_info".
2137  * @ptr: Pointer to "struct ccs_acl_info".
2138  *
2139  * Returns true if granted, false otherwise.
2140  */
2141 static bool ccs_check_path2_acl(struct ccs_request_info *r,
2142                                 const struct ccs_acl_info *ptr)
2143 {
2144         const struct ccs_path2_acl *acl =
2145                 container_of(ptr, typeof(*acl), head);
2146         return (ptr->perm & (1 << r->param.path2.operation)) &&
2147                 ccs_compare_name_union(r->param.path2.filename1, &acl->name1)
2148                 && ccs_compare_name_union(r->param.path2.filename2,
2149                                           &acl->name2);
2150 }
2151 
2152 /**
2153  * ccs_check_mkdev_acl - Check permission for path number number number operation.
2154  *
2155  * @r:   Pointer to "struct ccs_request_info".
2156  * @ptr: Pointer to "struct ccs_acl_info".
2157  *
2158  * Returns true if granted, false otherwise.
2159  */
2160 static bool ccs_check_mkdev_acl(struct ccs_request_info *r,
2161                                 const struct ccs_acl_info *ptr)
2162 {
2163         const struct ccs_mkdev_acl *acl =
2164                 container_of(ptr, typeof(*acl), head);
2165         return (ptr->perm & (1 << r->param.mkdev.operation)) &&
2166                 ccs_compare_number_union(r->param.mkdev.mode, &acl->mode) &&
2167                 ccs_compare_number_union(r->param.mkdev.major, &acl->major) &&
2168                 ccs_compare_number_union(r->param.mkdev.minor, &acl->minor) &&
2169                 ccs_compare_name_union(r->param.mkdev.filename, &acl->name);
2170 }
2171 
2172 /**
2173  * ccs_path_permission - Check permission for path operation.
2174  *
2175  * @r:         Pointer to "struct ccs_request_info".
2176  * @operation: Type of operation.
2177  * @filename:  Filename to check.
2178  *
2179  * Returns 0 on success, negative value otherwise.
2180  *
2181  * Caller holds ccs_read_lock().
2182  */
2183 static int ccs_path_permission(struct ccs_request_info *r, u8 operation,
2184                                const struct ccs_path_info *filename)
2185 {
2186         r->type = ccs_p2mac[operation];
2187         r->mode = ccs_get_mode(r->profile, r->type);
2188         if (r->mode == CCS_CONFIG_DISABLED)
2189                 return 0;
2190         r->param_type = CCS_TYPE_PATH_ACL;
2191         r->param.path.filename = filename;
2192         r->param.path.operation = operation;
2193         return ccs_check_acl(r);
2194 }
2195 
2196 /**
2197  * ccs_execute_permission - Check permission for execute operation.
2198  *
2199  * @r:         Pointer to "struct ccs_request_info".
2200  * @filename:  Filename to check.
2201  *
2202  * Returns 0 on success, CCS_RETRY_REQUEST on retry, negative value otherwise.
2203  *
2204  * Caller holds ccs_read_lock().
2205  */
2206 static int ccs_execute_permission(struct ccs_request_info *r,
2207                                   const struct ccs_path_info *filename)
2208 {
2209         int error;
2210         /*
2211          * Unlike other permission checks, this check is done regardless of
2212          * profile mode settings in order to check for domain transition
2213          * preference.
2214          */
2215         r->type = CCS_MAC_FILE_EXECUTE;
2216         r->mode = ccs_get_mode(r->profile, r->type);
2217         r->param_type = CCS_TYPE_PATH_ACL;
2218         r->param.path.filename = filename;
2219         r->param.path.operation = CCS_TYPE_EXECUTE;
2220         error = ccs_check_acl(r);
2221         r->ee->transition = r->matched_acl && r->matched_acl->cond &&
2222                 r->matched_acl->cond->exec_transit ?
2223                 r->matched_acl->cond->transit : NULL;
2224         return error;
2225 }
2226 
2227 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
2228 
2229 /**
2230  * __ccs_save_open_mode - Remember original flags passed to sys_open().
2231  *
2232  * @mode: Flags passed to sys_open().
2233  *
2234  * Returns nothing.
2235  *
2236  * TOMOYO does not check "file write" if open(path, O_TRUNC | O_RDONLY) was
2237  * requested because write() is not permitted. Instead, TOMOYO checks
2238  * "file truncate" if O_TRUNC is passed.
2239  *
2240  * TOMOYO does not check "file read" and "file write" if open(path, 3) was
2241  * requested because read()/write() are not permitted. Instead, TOMOYO checks
2242  * "file ioctl" when ioctl() is requested.
2243  */
2244 static void __ccs_save_open_mode(int mode)
2245 {
2246         if ((mode & 3) == 3)
2247                 ccs_current_security()->ccs_flags |= CCS_OPEN_FOR_IOCTL_ONLY;
2248 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 14)
2249         /* O_TRUNC passes MAY_WRITE to ccs_open_permission(). */
2250         else if (!(mode & 3) && (mode & O_TRUNC))
2251                 ccs_current_security()->ccs_flags |=
2252                         CCS_OPEN_FOR_READ_TRUNCATE;
2253 #endif
2254 }
2255 
2256 /**
2257  * __ccs_clear_open_mode - Forget original flags passed to sys_open().
2258  *
2259  * Returns nothing.
2260  */
2261 static void __ccs_clear_open_mode(void)
2262 {
2263         ccs_current_security()->ccs_flags &= ~(CCS_OPEN_FOR_IOCTL_ONLY |
2264                                                CCS_OPEN_FOR_READ_TRUNCATE);
2265 }
2266 
2267 #endif
2268 
2269 /**
2270  * __ccs_open_permission - Check permission for "read" and "write".
2271  *
2272  * @dentry: Pointer to "struct dentry".
2273  * @mnt:    Pointer to "struct vfsmount". Maybe NULL.
2274  * @flag:   Flags for open().
2275  *
2276  * Returns 0 on success, negative value otherwise.
2277  */
2278 static int __ccs_open_permission(struct dentry *dentry, struct vfsmount *mnt,
2279                                  const int flag)
2280 {
2281         struct ccs_request_info r;
2282         struct ccs_obj_info obj = {
2283                 .path1.dentry = dentry,
2284                 .path1.mnt = mnt,
2285         };
2286         const u32 ccs_flags = ccs_current_flags();
2287 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2288         const u8 acc_mode = (flag & 3) == 3 ? 0 : ACC_MODE(flag);
2289 #else
2290         const u8 acc_mode = (ccs_flags & CCS_OPEN_FOR_IOCTL_ONLY) ? 0 :
2291 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 14)
2292                 (ccs_flags & CCS_OPEN_FOR_READ_TRUNCATE) ? 4 :
2293 #endif
2294                 ACC_MODE(flag);
2295 #endif
2296         int error = 0;
2297         struct ccs_path_info buf;
2298         int idx;
2299 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
2300         if (current->in_execve && !(ccs_flags & CCS_TASK_IS_IN_EXECVE))
2301                 return 0;
2302 #endif
2303 #ifndef CONFIG_CCSECURITY_FILE_READDIR
2304         if (d_is_dir(dentry))
2305                 return 0;
2306 #endif
2307         buf.name = NULL;
2308         r.mode = CCS_CONFIG_DISABLED;
2309         idx = ccs_read_lock();
2310         if (acc_mode && ccs_init_request_info(&r, CCS_MAC_FILE_OPEN)
2311             != CCS_CONFIG_DISABLED) {
2312                 if (!ccs_get_realpath(&buf, &obj.path1)) {
2313                         error = -ENOMEM;
2314                         goto out;
2315                 }
2316                 r.obj = &obj;
2317                 if (acc_mode & MAY_READ)
2318                         error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
2319                 if (!error && (acc_mode & MAY_WRITE))
2320                         error = ccs_path_permission(&r, (flag & O_APPEND) ?
2321                                                     CCS_TYPE_APPEND :
2322                                                     CCS_TYPE_WRITE, &buf);
2323         }
2324 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
2325         if (!error && (flag & O_TRUNC) &&
2326             ccs_init_request_info(&r, CCS_MAC_FILE_TRUNCATE)
2327             != CCS_CONFIG_DISABLED) {
2328                 if (!buf.name && !ccs_get_realpath(&buf, &obj.path1)) {
2329                         error = -ENOMEM;
2330                         goto out;
2331                 }
2332                 r.obj = &obj;
2333                 error = ccs_path_permission(&r, CCS_TYPE_TRUNCATE, &buf);
2334         }
2335 #endif
2336 out:
2337         kfree(buf.name);
2338         ccs_read_unlock(idx);
2339         if (r.mode != CCS_CONFIG_ENFORCING)
2340                 error = 0;
2341         return error;
2342 }
2343 
2344 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2345 
2346 /**
2347  * ccs_new_open_permission - Check permission for "read" and "write".
2348  *
2349  * @filp: Pointer to "struct file".
2350  *
2351  * Returns 0 on success, negative value otherwise.
2352  */
2353 static int ccs_new_open_permission(struct file *filp)
2354 {
2355         return __ccs_open_permission(filp->f_path.dentry, filp->f_path.mnt,
2356                                      filp->f_flags);
2357 }
2358 
2359 #endif
2360 
2361 /**
2362  * ccs_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "getattr", "chroot" and "unmount".
2363  *
2364  * @operation: Type of operation.
2365  * @dentry:    Pointer to "struct dentry".
2366  * @mnt:       Pointer to "struct vfsmount". Maybe NULL.
2367  * @target:    Symlink's target if @operation is CCS_TYPE_SYMLINK,
2368  *             NULL otherwise.
2369  *
2370  * Returns 0 on success, negative value otherwise.
2371  */
2372 static int ccs_path_perm(const u8 operation, struct dentry *dentry,
2373                          struct vfsmount *mnt, const char *target)
2374 {
2375         struct ccs_request_info r;
2376         struct ccs_obj_info obj = {
2377                 .path1.dentry = dentry,
2378                 .path1.mnt = mnt,
2379         };
2380         int error = 0;
2381         struct ccs_path_info buf;
2382         bool is_enforce = false;
2383         struct ccs_path_info symlink_target;
2384         int idx;
2385         buf.name = NULL;
2386         symlink_target.name = NULL;
2387         idx = ccs_read_lock();
2388         if (ccs_init_request_info(&r, ccs_p2mac[operation])
2389             == CCS_CONFIG_DISABLED)
2390                 goto out;
2391         is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
2392         error = -ENOMEM;
2393         if (!ccs_get_realpath(&buf, &obj.path1))
2394                 goto out;
2395         r.obj = &obj;
2396         switch (operation) {
2397         case CCS_TYPE_RMDIR:
2398         case CCS_TYPE_CHROOT:
2399                 ccs_add_slash(&buf);
2400                 break;
2401         case CCS_TYPE_SYMLINK:
2402                 symlink_target.name = ccs_encode(target);
2403                 if (!symlink_target.name)
2404                         goto out;
2405                 ccs_fill_path_info(&symlink_target);
2406                 obj.symlink_target = &symlink_target;
2407                 break;
2408         }
2409         error = ccs_path_permission(&r, operation, &buf);
2410         if (operation == CCS_TYPE_SYMLINK)
2411                 kfree(symlink_target.name);
2412 out:
2413         kfree(buf.name);
2414         ccs_read_unlock(idx);
2415         if (!is_enforce)
2416                 error = 0;
2417         return error;
2418 }
2419 
2420 /**
2421  * ccs_mkdev_perm - Check permission for "mkblock" and "mkchar".
2422  *
2423  * @operation: Type of operation. (CCS_TYPE_MKCHAR or CCS_TYPE_MKBLOCK)
2424  * @dentry:    Pointer to "struct dentry".
2425  * @mnt:       Pointer to "struct vfsmount". Maybe NULL.
2426  * @mode:      Create mode.
2427  * @dev:       Device number.
2428  *
2429  * Returns 0 on success, negative value otherwise.
2430  */
2431 static int ccs_mkdev_perm(const u8 operation, struct dentry *dentry,
2432                           struct vfsmount *mnt, const unsigned int mode,
2433                           unsigned int dev)
2434 {
2435         struct ccs_request_info r;
2436         struct ccs_obj_info obj = {
2437                 .path1.dentry = dentry,
2438                 .path1.mnt = mnt,
2439         };
2440         int error = 0;
2441         struct ccs_path_info buf;
2442         bool is_enforce = false;
2443         int idx;
2444         idx = ccs_read_lock();
2445         if (ccs_init_request_info(&r, ccs_pnnn2mac[operation])
2446             == CCS_CONFIG_DISABLED)
2447                 goto out;
2448         is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
2449         error = -EPERM;
2450         if (!capable(CAP_MKNOD))
2451                 goto out;
2452         error = -ENOMEM;
2453         if (!ccs_get_realpath(&buf, &obj.path1))
2454                 goto out;
2455         r.obj = &obj;
2456 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
2457         dev = new_decode_dev(dev);
2458 #endif
2459         r.param_type = CCS_TYPE_MKDEV_ACL;
2460         r.param.mkdev.filename = &buf;
2461         r.param.mkdev.operation = operation;
2462         r.param.mkdev.mode = mode;
2463         r.param.mkdev.major = MAJOR(dev);
2464         r.param.mkdev.minor = MINOR(dev);
2465         error = ccs_check_acl(&r);
2466         kfree(buf.name);
2467 out:
2468         ccs_read_unlock(idx);
2469         if (!is_enforce)
2470                 error = 0;
2471         return error;
2472 }
2473 
2474 /**
2475  * ccs_path2_perm - Check permission for "rename", "link" and "pivot_root".
2476  *
2477  * @operation: Type of operation.
2478  * @dentry1:   Pointer to "struct dentry".
2479  * @mnt1:      Pointer to "struct vfsmount". Maybe NULL.
2480  * @dentry2:   Pointer to "struct dentry".
2481  * @mnt2:      Pointer to "struct vfsmount". Maybe NULL.
2482  *
2483  * Returns 0 on success, negative value otherwise.
2484  */
2485 static int ccs_path2_perm(const u8 operation, struct dentry *dentry1,
2486                           struct vfsmount *mnt1, struct dentry *dentry2,
2487                           struct vfsmount *mnt2)
2488 {
2489         struct ccs_request_info r;
2490         int error = 0;
2491         struct ccs_path_info buf1;
2492         struct ccs_path_info buf2;
2493         bool is_enforce = false;
2494         struct ccs_obj_info obj = {
2495                 .path1.dentry = dentry1,
2496                 .path1.mnt = mnt1,
2497                 .path2.dentry = dentry2,
2498                 .path2.mnt = mnt2,
2499         };
2500         int idx;
2501         buf1.name = NULL;
2502         buf2.name = NULL;
2503         idx = ccs_read_lock();
2504         if (ccs_init_request_info(&r, ccs_pp2mac[operation])
2505             == CCS_CONFIG_DISABLED)
2506                 goto out;
2507         is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
2508         error = -ENOMEM;
2509         if (!ccs_get_realpath(&buf1, &obj.path1) ||
2510             !ccs_get_realpath(&buf2, &obj.path2))
2511                 goto out;
2512         switch (operation) {
2513         case CCS_TYPE_RENAME:
2514         case CCS_TYPE_LINK:
2515                 if (!d_is_dir(dentry1))
2516                         break;
2517                 /* fall through */
2518         case CCS_TYPE_PIVOT_ROOT:
2519                 ccs_add_slash(&buf1);
2520                 ccs_add_slash(&buf2);
2521                 break;
2522         }
2523         r.obj = &obj;
2524         r.param_type = CCS_TYPE_PATH2_ACL;
2525         r.param.path2.operation = operation;
2526         r.param.path2.filename1 = &buf1;
2527         r.param.path2.filename2 = &buf2;
2528         error = ccs_check_acl(&r);
2529 out:
2530         kfree(buf1.name);
2531         kfree(buf2.name);
2532         ccs_read_unlock(idx);
2533         if (!is_enforce)
2534                 error = 0;
2535         return error;
2536 }
2537 
2538 /**
2539  * ccs_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
2540  *
2541  * @type:   Type of operation.
2542  * @dentry: Pointer to "struct dentry".
2543  * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
2544  * @number: Number.
2545  *
2546  * Returns 0 on success, negative value otherwise.
2547  */
2548 static int ccs_path_number_perm(const u8 type, struct dentry *dentry,
2549                                 struct vfsmount *vfsmnt, unsigned long number)
2550 {
2551         struct ccs_request_info r;
2552         struct ccs_obj_info obj = {
2553                 .path1.dentry = dentry,
2554                 .path1.mnt = vfsmnt,
2555         };
2556         int error = 0;
2557         struct ccs_path_info buf;
2558         int idx;
2559         if (!dentry)
2560                 return 0;
2561         idx = ccs_read_lock();
2562         if (ccs_init_request_info(&r, ccs_pn2mac[type]) == CCS_CONFIG_DISABLED)
2563                 goto out;
2564         error = -ENOMEM;
2565         if (!ccs_get_realpath(&buf, &obj.path1))
2566                 goto out;
2567         r.obj = &obj;
2568         if (type == CCS_TYPE_MKDIR)
2569                 ccs_add_slash(&buf);
2570         r.param_type = CCS_TYPE_PATH_NUMBER_ACL;
2571         r.param.path_number.operation = type;
2572         r.param.path_number.filename = &buf;
2573         r.param.path_number.number = number;
2574         error = ccs_check_acl(&r);
2575         kfree(buf.name);
2576 out:
2577         ccs_read_unlock(idx);
2578         if (r.mode != CCS_CONFIG_ENFORCING)
2579                 error = 0;
2580         return error;
2581 }
2582 
2583 /**
2584  * __ccs_ioctl_permission - Check permission for "ioctl".
2585  *
2586  * @filp: Pointer to "struct file".
2587  * @cmd:  Ioctl command number.
2588  * @arg:  Param for @cmd.
2589  *
2590  * Returns 0 on success, negative value otherwise.
2591  */
2592 static int __ccs_ioctl_permission(struct file *filp, unsigned int cmd,
2593                                   unsigned long arg)
2594 {
2595 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
2596         return ccs_path_number_perm(CCS_TYPE_IOCTL, filp->f_path.dentry,
2597                                     filp->f_path.mnt, cmd);
2598 #else
2599         return ccs_path_number_perm(CCS_TYPE_IOCTL, filp->f_dentry,
2600                                     filp->f_vfsmnt, cmd);
2601 #endif
2602 }
2603 
2604 /**
2605  * __ccs_chmod_permission - Check permission for "chmod".
2606  *
2607  * @dentry: Pointer to "struct dentry".
2608  * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
2609  * @mode:   Mode.
2610  *
2611  * Returns 0 on success, negative value otherwise.
2612  */
2613 static int __ccs_chmod_permission(struct dentry *dentry,
2614                                   struct vfsmount *vfsmnt, mode_t mode)
2615 {
2616         return ccs_path_number_perm(CCS_TYPE_CHMOD, dentry, vfsmnt,
2617                                     mode & S_IALLUGO);
2618 }
2619 
2620 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
2621 
2622 /**
2623  * __ccs_chown_permission - Check permission for "chown/chgrp".
2624  *
2625  * @dentry: Pointer to "struct dentry".
2626  * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
2627  * @user:   User ID.
2628  * @group:  Group ID.
2629  *
2630  * Returns 0 on success, negative value otherwise.
2631  */
2632 static int __ccs_chown_permission(struct dentry *dentry,
2633                                   struct vfsmount *vfsmnt, kuid_t user,
2634                                   kgid_t group)
2635 {
2636         int error = 0;
2637         if (uid_valid(user))
2638                 error = ccs_path_number_perm(CCS_TYPE_CHOWN, dentry, vfsmnt,
2639                                              from_kuid(&init_user_ns, user));
2640         if (!error && gid_valid(group))
2641                 error = ccs_path_number_perm(CCS_TYPE_CHGRP, dentry, vfsmnt,
2642                                              from_kgid(&init_user_ns, group));
2643         return error;
2644 }
2645 
2646 #else
2647 
2648 /**
2649  * __ccs_chown_permission - Check permission for "chown/chgrp".
2650  *
2651  * @dentry: Pointer to "struct dentry".
2652  * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
2653  * @user:   User ID.
2654  * @group:  Group ID.
2655  *
2656  * Returns 0 on success, negative value otherwise.
2657  */
2658 static int __ccs_chown_permission(struct dentry *dentry,
2659                                   struct vfsmount *vfsmnt, uid_t user,
2660                                   gid_t group)
2661 {
2662         int error = 0;
2663         if (user == (uid_t) -1 && group == (gid_t) -1)
2664                 return 0;
2665         if (user != (uid_t) -1)
2666                 error = ccs_path_number_perm(CCS_TYPE_CHOWN, dentry, vfsmnt,
2667                                              user);
2668         if (!error && group != (gid_t) -1)
2669                 error = ccs_path_number_perm(CCS_TYPE_CHGRP, dentry, vfsmnt,
2670                                              group);
2671         return error;
2672 }
2673 
2674 #endif
2675 
2676 /**
2677  * __ccs_fcntl_permission - Check permission for changing O_APPEND flag.
2678  *
2679  * @file: Pointer to "struct file".
2680  * @cmd:  Command number.
2681  * @arg:  Value for @cmd.
2682  *
2683  * Returns 0 on success, negative value otherwise.
2684  */
2685 static int __ccs_fcntl_permission(struct file *file, unsigned int cmd,
2686                                   unsigned long arg)
2687 {
2688         if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)))
2689                 return 0;
2690 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2691         return __ccs_open_permission(file->f_path.dentry, file->f_path.mnt,
2692                                      O_WRONLY | (arg & O_APPEND));
2693 #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 6
2694         return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
2695                                      O_WRONLY | (arg & O_APPEND));
2696 #else
2697         return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
2698                                      (O_WRONLY + 1) | (arg & O_APPEND));
2699 #endif
2700 }
2701 
2702 /**
2703  * __ccs_pivot_root_permission - Check permission for pivot_root().
2704  *
2705  * @old_path: Pointer to "struct path".
2706  * @new_path: Pointer to "struct path".
2707  *
2708  * Returns 0 on success, negative value otherwise.
2709  */
2710 static int __ccs_pivot_root_permission(const struct path *old_path,
2711                                        const struct path *new_path)
2712 {
2713         return ccs_path2_perm(CCS_TYPE_PIVOT_ROOT, new_path->dentry,
2714                               new_path->mnt, old_path->dentry, old_path->mnt);
2715 }
2716 
2717 /**
2718  * __ccs_chroot_permission - Check permission for chroot().
2719  *
2720  * @path: Pointer to "struct path".
2721  *
2722  * Returns 0 on success, negative value otherwise.
2723  */
2724 static int __ccs_chroot_permission(const struct path *path)
2725 {
2726         return ccs_path_perm(CCS_TYPE_CHROOT, path->dentry, path->mnt, NULL);
2727 }
2728 
2729 /**
2730  * __ccs_umount_permission - Check permission for unmount.
2731  *
2732  * @mnt:   Pointer to "struct vfsmount".
2733  * @flags: Unused.
2734  *
2735  * Returns 0 on success, negative value otherwise.
2736  */
2737 static int __ccs_umount_permission(struct vfsmount *mnt, int flags)
2738 {
2739         return ccs_path_perm(CCS_TYPE_UMOUNT, mnt->mnt_root, mnt, NULL);
2740 }
2741 
2742 /**
2743  * __ccs_mknod_permission - Check permission for vfs_mknod().
2744  *
2745  * @dentry: Pointer to "struct dentry".
2746  * @mnt:    Pointer to "struct vfsmount". Maybe NULL.
2747  * @mode:   Device type and permission.
2748  * @dev:    Device number for block or character device.
2749  *
2750  * Returns 0 on success, negative value otherwise.
2751  */
2752 static int __ccs_mknod_permission(struct dentry *dentry, struct vfsmount *mnt,
2753                                   const unsigned int mode, unsigned int dev)
2754 {
2755         int error = 0;
2756         const unsigned int perm = mode & S_IALLUGO;
2757         switch (mode & S_IFMT) {
2758         case S_IFCHR:
2759                 error = ccs_mkdev_perm(CCS_TYPE_MKCHAR, dentry, mnt, perm,
2760                                        dev);
2761                 break;
2762         case S_IFBLK:
2763                 error = ccs_mkdev_perm(CCS_TYPE_MKBLOCK, dentry, mnt, perm,
2764                                        dev);
2765                 break;
2766         case S_IFIFO:
2767                 error = ccs_path_number_perm(CCS_TYPE_MKFIFO, dentry, mnt,
2768                                              perm);
2769                 break;
2770         case S_IFSOCK:
2771                 error = ccs_path_number_perm(CCS_TYPE_MKSOCK, dentry, mnt,
2772                                              perm);
2773                 break;
2774         case 0:
2775         case S_IFREG:
2776                 error = ccs_path_number_perm(CCS_TYPE_CREATE, dentry, mnt,
2777                                              perm);
2778                 break;
2779         }
2780         return error;
2781 }
2782 
2783 /**
2784  * __ccs_mkdir_permission - Check permission for vfs_mkdir().
2785  *
2786  * @dentry: Pointer to "struct dentry".
2787  * @mnt:    Pointer to "struct vfsmount". Maybe NULL.
2788  * @mode:   Create mode.
2789  *
2790  * Returns 0 on success, negative value otherwise.
2791  */
2792 static int __ccs_mkdir_permission(struct dentry *dentry, struct vfsmount *mnt,
2793                                   unsigned int mode)
2794 {
2795         return ccs_path_number_perm(CCS_TYPE_MKDIR, dentry, mnt, mode);
2796 }
2797 
2798 /**
2799  * __ccs_rmdir_permission - Check permission for vfs_rmdir().
2800  *
2801  * @dentry: Pointer to "struct dentry".
2802  * @mnt:    Pointer to "struct vfsmount". Maybe NULL.
2803  *
2804  * Returns 0 on success, negative value otherwise.
2805  */
2806 static int __ccs_rmdir_permission(struct dentry *dentry, struct vfsmount *mnt)
2807 {
2808         return ccs_path_perm(CCS_TYPE_RMDIR, dentry, mnt, NULL);
2809 }
2810 
2811 /**
2812  * __ccs_unlink_permission - Check permission for vfs_unlink().
2813  *
2814  * @dentry: Pointer to "struct dentry".
2815  * @mnt:    Pointer to "struct vfsmount". Maybe NULL.
2816  *
2817  * Returns 0 on success, negative value otherwise.
2818  */
2819 static int __ccs_unlink_permission(struct dentry *dentry, struct vfsmount *mnt)
2820 {
2821         return ccs_path_perm(CCS_TYPE_UNLINK, dentry, mnt, NULL);
2822 }
2823 
2824 #ifdef CONFIG_CCSECURITY_FILE_GETATTR
2825 
2826 /**
2827  * __ccs_getattr_permission - Check permission for vfs_getattr().
2828  *
2829  * @mnt:    Pointer to "struct vfsmount". Maybe NULL.
2830  * @dentry: Pointer to "struct dentry".
2831  *
2832  * Returns 0 on success, negative value otherwise.
2833  */
2834 static int __ccs_getattr_permission(struct vfsmount *mnt,
2835                                     struct dentry *dentry)
2836 {
2837         return ccs_path_perm(CCS_TYPE_GETATTR, dentry, mnt, NULL);
2838 }
2839 
2840 #endif
2841 
2842 /**
2843  * __ccs_symlink_permission - Check permission for vfs_symlink().
2844  *
2845  * @dentry: Pointer to "struct dentry".
2846  * @mnt:    Pointer to "struct vfsmount". Maybe NULL.
2847  * @from:   Content of symlink.
2848  *
2849  * Returns 0 on success, negative value otherwise.
2850  */
2851 static int __ccs_symlink_permission(struct dentry *dentry,
2852                                     struct vfsmount *mnt, const char *from)
2853 {
2854         return ccs_path_perm(CCS_TYPE_SYMLINK, dentry, mnt, from);
2855 }
2856 
2857 /**
2858  * __ccs_truncate_permission - Check permission for notify_change().
2859  *
2860  * @dentry: Pointer to "struct dentry".
2861  * @mnt:    Pointer to "struct vfsmount". Maybe NULL.
2862  *
2863  * Returns 0 on success, negative value otherwise.
2864  */
2865 static int __ccs_truncate_permission(struct dentry *dentry,
2866                                      struct vfsmount *mnt)
2867 {
2868         return ccs_path_perm(CCS_TYPE_TRUNCATE, dentry, mnt, NULL);
2869 }
2870 
2871 /**
2872  * __ccs_rename_permission - Check permission for vfs_rename().
2873  *
2874  * @old_dentry: Pointer to "struct dentry".
2875  * @new_dentry: Pointer to "struct dentry".
2876  * @mnt:        Pointer to "struct vfsmount". Maybe NULL.
2877  *
2878  * Returns 0 on success, negative value otherwise.
2879  */
2880 static int __ccs_rename_permission(struct dentry *old_dentry,
2881                                    struct dentry *new_dentry,
2882                                    struct vfsmount *mnt)
2883 {
2884         return ccs_path2_perm(CCS_TYPE_RENAME, old_dentry, mnt, new_dentry,
2885                               mnt);
2886 }
2887 
2888 /**
2889  * __ccs_link_permission - Check permission for vfs_link().
2890  *
2891  * @old_dentry: Pointer to "struct dentry".
2892  * @new_dentry: Pointer to "struct dentry".
2893  * @mnt:        Pointer to "struct vfsmount". Maybe NULL.
2894  *
2895  * Returns 0 on success, negative value otherwise.
2896  */
2897 static int __ccs_link_permission(struct dentry *old_dentry,
2898                                  struct dentry *new_dentry,
2899                                  struct vfsmount *mnt)
2900 {
2901         return ccs_path2_perm(CCS_TYPE_LINK, old_dentry, mnt, new_dentry, mnt);
2902 }
2903 
2904 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
2905 
2906 /**
2907  * __ccs_open_exec_permission - Check permission for open_exec().
2908  *
2909  * @dentry: Pointer to "struct dentry".
2910  * @mnt:    Pointer to "struct vfsmount".
2911  *
2912  * Returns 0 on success, negative value otherwise.
2913  */
2914 static int __ccs_open_exec_permission(struct dentry *dentry,
2915                                       struct vfsmount *mnt)
2916 {
2917         return (ccs_current_flags() & CCS_TASK_IS_IN_EXECVE) ?
2918                 __ccs_open_permission(dentry, mnt, O_RDONLY + 1) : 0;
2919 }
2920 
2921 /**
2922  * __ccs_uselib_permission - Check permission for sys_uselib().
2923  *
2924  * @dentry: Pointer to "struct dentry".
2925  * @mnt:    Pointer to "struct vfsmount".
2926  *
2927  * Returns 0 on success, negative value otherwise.
2928  */
2929 static int __ccs_uselib_permission(struct dentry *dentry, struct vfsmount *mnt)
2930 {
2931         return __ccs_open_permission(dentry, mnt, O_RDONLY + 1);
2932 }
2933 
2934 #endif
2935 
2936 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL))
2937 
2938 /**
2939  * __ccs_parse_table - Check permission for parse_table().
2940  *
2941  * @name:   Pointer to "int __user".
2942  * @nlen:   Number of elements in @name.
2943  * @oldval: Pointer to "void __user".
2944  * @newval: Pointer to "void __user".
2945  * @table:  Pointer to "struct ctl_table".
2946  *
2947  * Returns 0 on success, negative value otherwise.
2948  *
2949  * Note that this function is racy because this function checks values in
2950  * userspace memory which could be changed after permission check.
2951  */
2952 static int __ccs_parse_table(int __user *name, int nlen, void __user *oldval,
2953                              void __user *newval, struct ctl_table *table)
2954 {
2955         int n;
2956         int error = -ENOMEM;
2957         int op = 0;
2958         struct ccs_path_info buf;
2959         char *buffer = NULL;
2960         struct ccs_request_info r;
2961         int idx;
2962         if (oldval)
2963                 op |= 004;
2964         if (newval)
2965                 op |= 002;
2966         if (!op) /* Neither read nor write */
2967                 return 0;
2968         idx = ccs_read_lock();
2969         if (ccs_init_request_info(&r, CCS_MAC_FILE_OPEN)
2970             == CCS_CONFIG_DISABLED) {
2971                 error = 0;
2972                 goto out;
2973         }
2974         buffer = kmalloc(PAGE_SIZE, CCS_GFP_FLAGS);
2975         if (!buffer)
2976                 goto out;
2977         snprintf(buffer, PAGE_SIZE - 1, "proc:/sys");
2978 repeat:
2979         if (!nlen) {
2980                 error = -ENOTDIR;
2981                 goto out;
2982         }
2983         if (get_user(n, name)) {
2984                 error = -EFAULT;
2985                 goto out;
2986         }
2987         for ( ; table->ctl_name
2988 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
2989                       || table->procname
2990 #endif
2991                       ; table++) {
2992                 int pos;
2993                 const char *cp;
2994 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
2995                 if (n != table->ctl_name && table->ctl_name != CTL_ANY)
2996                         continue;
2997 #else
2998                 if (!n || n != table->ctl_name)
2999                         continue;
3000 #endif
3001                 pos = strlen(buffer);
3002                 cp = table->procname;
3003                 error = -ENOMEM;
3004                 if (cp) {
3005                         int len = strlen(cp);
3006                         if (len + 2 > PAGE_SIZE - 1)
3007                                 goto out;
3008                         buffer[pos++] = '/';
3009                         memmove(buffer + pos, cp, len + 1);
3010                 } else {
3011                         /* Assume nobody assigns "=\$=" for procname. */
3012                         snprintf(buffer + pos, PAGE_SIZE - pos - 1,
3013                                  "/=%d=", table->ctl_name);
3014                         if (!memchr(buffer, '\0', PAGE_SIZE - 2))
3015                                 goto out;
3016                 }
3017                 if (!table->child)
3018                         goto no_child;
3019 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
3020                 if (!table->strategy)
3021                         goto no_strategy;
3022                 /* printk("sysctl='%s'\n", buffer); */
3023                 buf.name = ccs_encode(buffer);
3024                 if (!buf.name)
3025                         goto out;
3026                 ccs_fill_path_info(&buf);
3027                 if (op & MAY_READ)
3028                         error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
3029                 else
3030                         error = 0;
3031                 if (!error && (op & MAY_WRITE))
3032                         error = ccs_path_permission(&r, CCS_TYPE_WRITE, &buf);
3033                 kfree(buf.name);
3034                 if (error)
3035                         goto out;
3036 no_strategy:
3037 #endif
3038                 name++;
3039                 nlen--;
3040                 table = table->child;
3041                 goto repeat;
3042 no_child:
3043                 /* printk("sysctl='%s'\n", buffer); */
3044                 buf.name = ccs_encode(buffer);
3045                 if (!buf.name)
3046                         goto out;
3047                 ccs_fill_path_info(&buf);
3048                 if (op & MAY_READ)
3049                         error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
3050                 else
3051                         error = 0;
3052                 if (!error && (op & MAY_WRITE))
3053                         error = ccs_path_permission(&r, CCS_TYPE_WRITE, &buf);
3054                 kfree(buf.name);
3055                 goto out;
3056         }
3057         error = -ENOTDIR;
3058 out:
3059         ccs_read_unlock(idx);
3060         kfree(buffer);
3061         return error;
3062 }
3063 
3064 #endif
3065 
3066 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
3067 
3068 /**
3069  * ccs_old_pivot_root_permission - Check permission for pivot_root().
3070  *
3071  * @old_nd: Pointer to "struct nameidata".
3072  * @new_nd: Pointer to "struct nameidata".
3073  *
3074  * Returns 0 on success, negative value otherwise.
3075  */
3076 static int ccs_old_pivot_root_permission(struct nameidata *old_nd,
3077                                          struct nameidata *new_nd)
3078 {
3079         struct path old_path = { old_nd->mnt, old_nd->dentry };
3080         struct path new_path = { new_nd->mnt, new_nd->dentry };
3081         return __ccs_pivot_root_permission(&old_path, &new_path);
3082 }
3083 
3084 /**
3085  * ccs_old_chroot_permission - Check permission for chroot().
3086  *
3087  * @nd: Pointer to "struct nameidata".
3088  *
3089  * Returns 0 on success, negative value otherwise.
3090  */
3091 static int ccs_old_chroot_permission(struct nameidata *nd)
3092 {
3093         struct path path = { nd->mnt, nd->dentry };
3094         return __ccs_chroot_permission(&path);
3095 }
3096 
3097 #endif
3098 
3099 #ifdef CONFIG_CCSECURITY_NETWORK
3100 
3101 /**
3102  * ccs_address_matches_group - Check whether the given address matches members of the given address group.
3103  *
3104  * @is_ipv6: True if @address is an IPv6 address.
3105  * @address: An IPv4 or IPv6 address.
3106  * @group:   Pointer to "struct ccs_address_group".
3107  *
3108  * Returns true if @address matches addresses in @group group, false otherwise.
3109  *
3110  * Caller holds ccs_read_lock().
3111  */
3112 static bool ccs_address_matches_group(const bool is_ipv6, const u32 *address,
3113                                       const struct ccs_group *group)
3114 {
3115         struct ccs_address_group *member;
3116         bool matched = false;
3117         const u8 size = is_ipv6 ? 16 : 4;
3118         list_for_each_entry_srcu(member, &group->member_list, head.list,
3119                                  &ccs_ss) {
3120                 if (member->head.is_deleted)
3121                         continue;
3122                 if (member->address.is_ipv6 != is_ipv6)
3123                         continue;
3124                 if (memcmp(&member->address.ip[0], address, size) > 0 ||
3125                     memcmp(address, &member->address.ip[1], size) > 0)
3126                         continue;
3127                 matched = true;
3128                 break;
3129         }
3130         return matched;
3131 }
3132 
3133 /**
3134  * ccs_check_inet_acl - Check permission for inet domain socket operation.
3135  *
3136  * @r:   Pointer to "struct ccs_request_info".
3137  * @ptr: Pointer to "struct ccs_acl_info".
3138  *
3139  * Returns true if granted, false otherwise.
3140  */
3141 static bool ccs_check_inet_acl(struct ccs_request_info *r,
3142                                const struct ccs_acl_info *ptr)
3143 {
3144         const struct ccs_inet_acl *acl = container_of(ptr, typeof(*acl), head);
3145         const u8 size = r->param.inet_network.is_ipv6 ? 16 : 4;
3146         if (!(ptr->perm & (1 << r->param.inet_network.operation)) ||
3147             !ccs_compare_number_union(r->param.inet_network.port, &acl->port))
3148                 return false;
3149         if (acl->address.group)
3150                 return ccs_address_matches_group(r->param.inet_network.is_ipv6,
3151                                                  r->param.inet_network.address,
3152                                                  acl->address.group);
3153         return acl->address.is_ipv6 == r->param.inet_network.is_ipv6 &&
3154                 memcmp(&acl->address.ip[0],
3155                        r->param.inet_network.address, size) <= 0 &&
3156                 memcmp(r->param.inet_network.address,
3157                        &acl->address.ip[1], size) <= 0;
3158 }
3159 
3160 /**
3161  * ccs_check_unix_acl - Check permission for unix domain socket operation.
3162  *
3163  * @r:   Pointer to "struct ccs_request_info".
3164  * @ptr: Pointer to "struct ccs_acl_info".
3165  *
3166  * Returns true if granted, false otherwise.
3167  */
3168 static bool ccs_check_unix_acl(struct ccs_request_info *r,
3169                                const struct ccs_acl_info *ptr)
3170 {
3171         const struct ccs_unix_acl *acl = container_of(ptr, typeof(*acl), head);
3172         return (ptr->perm & (1 << r->param.unix_network.operation)) &&
3173                 ccs_compare_name_union(r->param.unix_network.address,
3174                                        &acl->name);
3175 }
3176 
3177 /**
3178  * ccs_inet_entry - Check permission for INET network operation.
3179  *
3180  * @address: Pointer to "struct ccs_addr_info".
3181  *
3182  * Returns 0 on success, negative value otherwise.
3183  */
3184 static int ccs_inet_entry(const struct ccs_addr_info *address)
3185 {
3186         const int idx = ccs_read_lock();
3187         struct ccs_request_info r;
3188         int error = 0;
3189         const u8 type = ccs_inet2mac[address->protocol][address->operation];
3190         if (type && ccs_init_request_info(&r, type) != CCS_CONFIG_DISABLED) {
3191                 r.param_type = CCS_TYPE_INET_ACL;
3192                 r.param.inet_network.protocol = address->protocol;
3193                 r.param.inet_network.operation = address->operation;
3194                 r.param.inet_network.is_ipv6 = address->inet.is_ipv6;
3195                 r.param.inet_network.address = address->inet.address;
3196                 r.param.inet_network.port = ntohs(address->inet.port);
3197                 r.dont_sleep_on_enforce_error =
3198                         address->operation == CCS_NETWORK_ACCEPT
3199 #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3200                         || address->operation == CCS_NETWORK_RECV
3201 #endif
3202                         ;
3203                 error = ccs_check_acl(&r);
3204         }
3205         ccs_read_unlock(idx);
3206         return error;
3207 }
3208 
3209 /**
3210  * ccs_check_inet_address - Check permission for inet domain socket's operation.
3211  *
3212  * @addr:     Pointer to "struct sockaddr".
3213  * @addr_len: Size of @addr.
3214  * @port:     Port number.
3215  * @address:  Pointer to "struct ccs_addr_info".
3216  *
3217  * Returns 0 on success, negative value otherwise.
3218  */
3219 static int ccs_check_inet_address(const struct sockaddr *addr,
3220                                   const unsigned int addr_len, const u16 port,
3221                                   struct ccs_addr_info *address)
3222 {
3223         struct ccs_inet_addr_info *i = &address->inet;
3224         switch (addr->sa_family) {
3225         case AF_INET6:
3226                 if (addr_len < SIN6_LEN_RFC2133)
3227                         goto skip;
3228                 i->is_ipv6 = true;
3229                 i->address = (u32 *)
3230                         ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr;
3231                 i->port = ((struct sockaddr_in6 *) addr)->sin6_port;
3232                 break;
3233         case AF_INET:
3234                 if (addr_len < sizeof(struct sockaddr_in))
3235                         goto skip;
3236                 i->is_ipv6 = false;
3237                 i->address = (u32 *) &((struct sockaddr_in *) addr)->sin_addr;
3238                 i->port = ((struct sockaddr_in *) addr)->sin_port;
3239                 break;
3240         default:
3241                 goto skip;
3242         }
3243         if (address->protocol == SOCK_RAW)
3244                 i->port = htons(port);
3245         return ccs_inet_entry(address);
3246 skip:
3247         return 0;
3248 }
3249 
3250 /**
3251  * ccs_unix_entry - Check permission for UNIX network operation.
3252  *
3253  * @address: Pointer to "struct ccs_addr_info".
3254  *
3255  * Returns 0 on success, negative value otherwise.
3256  */
3257 static int ccs_unix_entry(const struct ccs_addr_info *address)
3258 {
3259         const int idx = ccs_read_lock();
3260         struct ccs_request_info r;
3261         int error = 0;
3262         const u8 type = ccs_unix2mac[address->protocol][address->operation];
3263         if (type && ccs_init_request_info(&r, type) != CCS_CONFIG_DISABLED) {
3264                 char *buf = address->unix0.addr;
3265                 int len = address->unix0.addr_len - sizeof(sa_family_t);
3266                 if (len <= 0) {
3267                         buf = "anonymous";
3268                         len = 9;
3269                 } else if (buf[0]) {
3270                         len = strnlen(buf, len);
3271                 }
3272                 buf = ccs_encode2(buf, len);
3273                 if (buf) {
3274                         struct ccs_path_info addr;
3275                         addr.name = buf;
3276                         ccs_fill_path_info(&addr);
3277                         r.param_type = CCS_TYPE_UNIX_ACL;
3278                         r.param.unix_network.protocol = address->protocol;
3279                         r.param.unix_network.operation = address->operation;
3280                         r.param.unix_network.address = &addr;
3281                         r.dont_sleep_on_enforce_error =
3282                                 address->operation == CCS_NETWORK_ACCEPT
3283 #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3284                                 || address->operation == CCS_NETWORK_RECV
3285 #endif
3286                                 ;
3287                         error = ccs_check_acl(&r);
3288                         kfree(buf);
3289                 } else
3290                         error = -ENOMEM;
3291         }
3292         ccs_read_unlock(idx);
3293         return error;
3294 }
3295 
3296 /**
3297  * ccs_check_unix_address - Check permission for unix domain socket's operation.
3298  *
3299  * @addr:     Pointer to "struct sockaddr".
3300  * @addr_len: Size of @addr.
3301  * @address:  Pointer to "struct ccs_addr_info".
3302  *
3303  * Returns 0 on success, negative value otherwise.
3304  */
3305 static int ccs_check_unix_address(struct sockaddr *addr,
3306                                   const unsigned int addr_len,
3307                                   struct ccs_addr_info *address)
3308 {
3309         struct ccs_unix_addr_info *u = &address->unix0;
3310         if (addr->sa_family != AF_UNIX)
3311                 return 0;
3312         u->addr = ((struct sockaddr_un *) addr)->sun_path;
3313         u->addr_len = addr_len;
3314         return ccs_unix_entry(address);
3315 }
3316 
3317 /**
3318  * ccs_sock_family - Get socket's family.
3319  *
3320  * @sk: Pointer to "struct sock".
3321  *
3322  * Returns one of PF_INET, PF_INET6, PF_UNIX or 0.
3323  */
3324 static u8 ccs_sock_family(struct sock *sk)
3325 {
3326         u8 family;
3327         if (ccs_kernel_service())
3328                 return 0;
3329         family = sk->sk_family;
3330         switch (family) {
3331         case PF_INET:
3332         case PF_INET6:
3333         case PF_UNIX:
3334                 return family;
3335         default:
3336                 return 0;
3337         }
3338 }
3339 
3340 /**
3341  * __ccs_socket_listen_permission - Check permission for listening a socket.
3342  *
3343  * @sock: Pointer to "struct socket".
3344  *
3345  * Returns 0 on success, negative value otherwise.
3346  */
3347 static int __ccs_socket_listen_permission(struct socket *sock)
3348 {
3349         struct ccs_addr_info address;
3350         const u8 family = ccs_sock_family(sock->sk);
3351         const unsigned int type = sock->type;
3352         struct sockaddr_storage addr;
3353         int addr_len;
3354         if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET))
3355                 return 0;
3356         {
3357                 const int error = sock->ops->getname(sock, (struct sockaddr *)
3358                                                      &addr, &addr_len, 0);
3359                 if (error)
3360                         return error;
3361         }
3362         address.protocol = type;
3363         address.operation = CCS_NETWORK_LISTEN;
3364         if (family == PF_UNIX)
3365                 return ccs_check_unix_address((struct sockaddr *) &addr,
3366                                               addr_len, &address);
3367         return ccs_check_inet_address((struct sockaddr *) &addr, addr_len, 0,
3368                                       &address);
3369 }
3370 
3371 /**
3372  * __ccs_socket_connect_permission - Check permission for setting the remote address of a socket.
3373  *
3374  * @sock:     Pointer to "struct socket".
3375  * @addr:     Pointer to "struct sockaddr".
3376  * @addr_len: Size of @addr.
3377  *
3378  * Returns 0 on success, negative value otherwise.
3379  */
3380 static int __ccs_socket_connect_permission(struct socket *sock,
3381                                            struct sockaddr *addr, int addr_len)
3382 {
3383         struct ccs_addr_info address;
3384         const u8 family = ccs_sock_family(sock->sk);
3385         const unsigned int type = sock->type;
3386         if (!family)
3387                 return 0;
3388         address.protocol = type;
3389         switch (type) {
3390         case SOCK_DGRAM:
3391         case SOCK_RAW:
3392                 address.operation = CCS_NETWORK_SEND;
3393                 break;
3394         case SOCK_STREAM:
3395         case SOCK_SEQPACKET:
3396                 address.operation = CCS_NETWORK_CONNECT;
3397                 break;
3398         default:
3399                 return 0;
3400         }
3401         if (family == PF_UNIX)
3402                 return ccs_check_unix_address(addr, addr_len, &address);
3403         return ccs_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
3404                                       &address);
3405 }
3406 
3407 /**
3408  * __ccs_socket_bind_permission - Check permission for setting the local address of a socket.
3409  *
3410  * @sock:     Pointer to "struct socket".
3411  * @addr:     Pointer to "struct sockaddr".
3412  * @addr_len: Size of @addr.
3413  *
3414  * Returns 0 on success, negative value otherwise.
3415  */
3416 static int __ccs_socket_bind_permission(struct socket *sock,
3417                                         struct sockaddr *addr, int addr_len)
3418 {
3419         struct ccs_addr_info address;
3420         const u8 family = ccs_sock_family(sock->sk);
3421         const unsigned int type = sock->type;
3422         if (!family)
3423                 return 0;
3424         switch (type) {
3425         case SOCK_STREAM:
3426         case SOCK_DGRAM:
3427         case SOCK_RAW:
3428         case SOCK_SEQPACKET:
3429                 address.protocol = type;
3430                 address.operation = CCS_NETWORK_BIND;
3431                 break;
3432         default:
3433                 return 0;
3434         }
3435         if (family == PF_UNIX)
3436                 return ccs_check_unix_address(addr, addr_len, &address);
3437         return ccs_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
3438                                       &address);
3439 }
3440 
3441 /**
3442  * __ccs_socket_sendmsg_permission - Check permission for sending a datagram.
3443  *
3444  * @sock: Pointer to "struct socket".
3445  * @msg:  Pointer to "struct msghdr".
3446  * @size: Unused.
3447  *
3448  * Returns 0 on success, negative value otherwise.
3449  */
3450 static int __ccs_socket_sendmsg_permission(struct socket *sock,
3451                                            struct msghdr *msg, int size)
3452 {
3453         struct ccs_addr_info address;
3454         const u8 family = ccs_sock_family(sock->sk);
3455         const unsigned int type = sock->type;
3456         if (!msg->msg_name || !family ||
3457             (type != SOCK_DGRAM && type != SOCK_RAW))
3458                 return 0;
3459         address.protocol = type;
3460         address.operation = CCS_NETWORK_SEND;
3461         if (family == PF_UNIX)
3462                 return ccs_check_unix_address((struct sockaddr *)
3463                                               msg->msg_name, msg->msg_namelen,
3464                                               &address);
3465         return ccs_check_inet_address((struct sockaddr *) msg->msg_name,
3466                                       msg->msg_namelen, sock->sk->sk_protocol,
3467                                       &address);
3468 }
3469 
3470 /**
3471  * __ccs_socket_post_accept_permission - Check permission for accepting a socket.
3472  *
3473  * @sock:    Pointer to "struct socket".
3474  * @newsock: Pointer to "struct socket".
3475  *
3476  * Returns 0 on success, negative value otherwise.
3477  */
3478 static int __ccs_socket_post_accept_permission(struct socket *sock,
3479                                                struct socket *newsock)
3480 {
3481         struct ccs_addr_info address;
3482         const u8 family = ccs_sock_family(sock->sk);
3483         const unsigned int type = sock->type;
3484         struct sockaddr_storage addr;
3485         int addr_len;
3486         if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET))
3487                 return 0;
3488         {
3489                 const int error = newsock->ops->getname(newsock,
3490                                                         (struct sockaddr *)
3491                                                         &addr, &addr_len, 2);
3492                 if (error)
3493                         return error;
3494         }
3495         address.protocol = type;
3496         address.operation = CCS_NETWORK_ACCEPT;
3497         if (family == PF_UNIX)
3498                 return ccs_check_unix_address((struct sockaddr *) &addr,
3499                                               addr_len, &address);
3500         return ccs_check_inet_address((struct sockaddr *) &addr, addr_len, 0,
3501                                       &address);
3502 }
3503 
3504 #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3505 
3506 /**
3507  * __ccs_socket_post_recvmsg_permission - Check permission for receiving a datagram.
3508  *
3509  * @sk:    Pointer to "struct sock".
3510  * @skb:   Pointer to "struct sk_buff".
3511  * @flags: Flags passed to skb_recv_datagram().
3512  *
3513  * Returns 0 on success, negative value otherwise.
3514  */
3515 static int __ccs_socket_post_recvmsg_permission(struct sock *sk,
3516                                                 struct sk_buff *skb, int flags)
3517 {
3518         struct ccs_addr_info address;
3519         const u8 family = ccs_sock_family(sk);
3520         const unsigned int type = sk->sk_type;
3521         struct sockaddr_storage addr;
3522         if (!family)
3523                 return 0;
3524         switch (type) {
3525         case SOCK_DGRAM:
3526         case SOCK_RAW:
3527                 address.protocol = type;
3528                 break;
3529         default:
3530                 return 0;
3531         }
3532         address.operation = CCS_NETWORK_RECV;
3533         switch (family) {
3534         case PF_INET6:
3535                 {
3536                         struct in6_addr *sin6 = (struct in6_addr *) &addr;
3537                         address.inet.is_ipv6 = true;
3538                         if (type == SOCK_DGRAM &&
3539                             skb->protocol == htons(ETH_P_IP))
3540                                 ipv6_addr_set(sin6, 0, 0, htonl(0xffff),
3541                                               ip_hdr(skb)->saddr);
3542                         else
3543                                 *sin6 = ipv6_hdr(skb)->saddr;
3544                         break;
3545                 }
3546         case PF_INET:
3547                 {
3548                         struct in_addr *sin4 = (struct in_addr *) &addr;
3549                         address.inet.is_ipv6 = false;
3550                         sin4->s_addr = ip_hdr(skb)->saddr;
3551                         break;
3552                 }
3553         default: /* == PF_UNIX */
3554                 {
3555 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
3556                         struct unix_address *u = unix_sk(skb->sk)->addr;
3557 #else
3558                         struct unix_address *u =
3559                                 skb->sk->protinfo.af_unix.addr;
3560 #endif
3561                         unsigned int addr_len;
3562                         if (u && u->len <= sizeof(addr)) {
3563                                 addr_len = u->len;
3564                                 memcpy(&addr, u->name, addr_len);
3565                         } else {
3566                                 addr_len = 0;
3567                                 addr.ss_family = AF_UNIX;
3568                         }
3569                         if (ccs_check_unix_address((struct sockaddr *) &addr,
3570                                                    addr_len, &address))
3571                                 goto out;
3572                         return 0;
3573                 }
3574         }
3575         address.inet.address = (u32 *) &addr;
3576         if (type == SOCK_DGRAM)
3577                 address.inet.port = udp_hdr(skb)->source;
3578         else
3579                 address.inet.port = htons(sk->sk_protocol);
3580         if (ccs_inet_entry(&address))
3581                 goto out;
3582         return 0;
3583 out:
3584         /*
3585          * Remove from queue if MSG_PEEK is used so that
3586          * the head message from unwanted source in receive queue will not
3587          * prevent the caller from picking up next message from wanted source
3588          * when the caller is using MSG_PEEK flag for picking up.
3589          */
3590         {
3591 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
3592                 bool slow = false;
3593                 if (type == SOCK_DGRAM && family != PF_UNIX)
3594                         slow = lock_sock_fast(sk);
3595 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
3596                 if (type == SOCK_DGRAM && family != PF_UNIX)
3597                         lock_sock(sk);
3598 #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 2
3599                 if (type == SOCK_DGRAM && family != PF_UNIX)
3600                         lock_sock(sk);
3601 #endif
3602                 skb_kill_datagram(sk, skb, flags);
3603 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
3604                 if (type == SOCK_DGRAM && family != PF_UNIX)
3605                         unlock_sock_fast(sk, slow);
3606 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
3607                 if (type == SOCK_DGRAM && family != PF_UNIX)
3608                         release_sock(sk);
3609 #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 2
3610                 if (type == SOCK_DGRAM && family != PF_UNIX)
3611                         release_sock(sk);
3612 #endif
3613         }
3614         return -EPERM;
3615 }
3616 
3617 #endif
3618 
3619 #endif
3620 
3621 #if defined(CONFIG_CCSECURITY_CAPABILITY) || defined(CONFIG_CCSECURITY_NETWORK)
3622 
3623 /**
3624  * ccs_kernel_service - Check whether I'm kernel service or not.
3625  *
3626  * Returns true if I'm kernel service, false otherwise.
3627  */
3628 static bool ccs_kernel_service(void)
3629 {
3630         /* Nothing to do if I am a kernel service. */
3631         return segment_eq(get_fs(), KERNEL_DS);
3632 }
3633 
3634 #endif
3635 
3636 #ifdef CONFIG_CCSECURITY_CAPABILITY
3637 
3638 /**
3639  * ccs_check_capability_acl - Check permission for capability operation.
3640  *
3641  * @r:   Pointer to "struct ccs_request_info".
3642  * @ptr: Pointer to "struct ccs_acl_info".
3643  *
3644  * Returns true if granted, false otherwise.
3645  */
3646 static bool ccs_check_capability_acl(struct ccs_request_info *r,
3647                                      const struct ccs_acl_info *ptr)
3648 {
3649         const struct ccs_capability_acl *acl =
3650                 container_of(ptr, typeof(*acl), head);
3651         return acl->operation == r->param.capability.operation;
3652 }
3653 
3654 /**
3655  * ccs_capable - Check permission for capability.
3656  *
3657  * @operation: Type of operation.
3658  *
3659  * Returns true on success, false otherwise.
3660  */
3661 static bool __ccs_capable(const u8 operation)
3662 {
3663         struct ccs_request_info r;
3664         int error = 0;
3665         const int idx = ccs_read_lock();
3666         if (ccs_init_request_info(&r, ccs_c2mac[operation])
3667             != CCS_CONFIG_DISABLED) {
3668                 r.param_type = CCS_TYPE_CAPABILITY_ACL;
3669                 r.param.capability.operation = operation;
3670                 error = ccs_check_acl(&r);
3671         }
3672         ccs_read_unlock(idx);
3673         return !error;
3674 }
3675 
3676 /**
3677  * __ccs_socket_create_permission - Check permission for creating a socket.
3678  *
3679  * @family:   Protocol family.
3680  * @type:     Unused.
3681  * @protocol: Unused.
3682  *
3683  * Returns 0 on success, negative value otherwise.
3684  */
3685 static int __ccs_socket_create_permission(int family, int type, int protocol)
3686 {
3687         if (ccs_kernel_service())
3688                 return 0;
3689         if (family == PF_PACKET && !ccs_capable(CCS_USE_PACKET_SOCKET))
3690                 return -EPERM;
3691         if (family == PF_ROUTE && !ccs_capable(CCS_USE_ROUTE_SOCKET))
3692                 return -EPERM;
3693         return 0;
3694 }
3695 
3696 /**
3697  * __ccs_ptrace_permission - Check permission for ptrace().
3698  *
3699  * @request: Unused.
3700  * @pid:     Unused.
3701  *
3702  * Returns 0 on success, negative value otherwise.
3703  *
3704  * Since this function is called from location where it is permitted to sleep,
3705  * it is racy to check target process's domainname anyway. Therefore, we don't
3706  * use target process's domainname.
3707  */
3708 static int __ccs_ptrace_permission(long request, long pid)
3709 {
3710         return __ccs_capable(CCS_SYS_PTRACE) ? 0 : -EPERM;
3711 }
3712 
3713 #endif
3714 
3715 #ifdef CONFIG_CCSECURITY_IPC
3716 
3717 /**
3718  * ccs_check_signal_acl - Check permission for signal operation.
3719  *
3720  * @r:   Pointer to "struct ccs_request_info".
3721  * @ptr: Pointer to "struct ccs_acl_info".
3722  *
3723  * Returns true if granted, false otherwise.
3724  */
3725 static bool ccs_check_signal_acl(struct ccs_request_info *r,
3726                                  const struct ccs_acl_info *ptr)
3727 {
3728         const struct ccs_signal_acl *acl =
3729                 container_of(ptr, typeof(*acl), head);
3730         if (ccs_compare_number_union(r->param.signal.sig, &acl->sig)) {
3731                 const int len = acl->domainname->total_len;
3732                 if (!strncmp(acl->domainname->name,
3733                              r->param.signal.dest_pattern, len)) {
3734                         switch (r->param.signal.dest_pattern[len]) {
3735                         case ' ':
3736                         case '\0':
3737                                 return true;
3738                         }
3739                 }
3740         }
3741         return false;
3742 }
3743 
3744 /**
3745  * ccs_signal_acl2 - Check permission for signal.
3746  *
3747  * @sig: Signal number.
3748  * @pid: Target's PID.
3749  *
3750  * Returns 0 on success, negative value otherwise.
3751  *
3752  * Caller holds ccs_read_lock().
3753  */
3754 static int ccs_signal_acl2(const int sig, const int pid)
3755 {
3756         struct ccs_request_info r;
3757         struct ccs_domain_info *dest = NULL;
3758         const struct ccs_domain_info * const domain = ccs_current_domain();
3759         if (ccs_init_request_info(&r, CCS_MAC_SIGNAL) == CCS_CONFIG_DISABLED)
3760                 return 0;
3761         if (!sig)
3762                 return 0;                /* No check for NULL signal. */
3763         r.param_type = CCS_TYPE_SIGNAL_ACL;
3764         r.param.signal.sig = sig;
3765         r.param.signal.dest_pattern = domain->domainname->name;
3766         r.granted = true;
3767         if (ccs_sys_getpid() == pid) {
3768                 ccs_audit_log(&r);
3769                 return 0;                /* No check for self process. */
3770         }
3771         { /* Simplified checking. */
3772                 struct task_struct *p = NULL;
3773                 ccs_tasklist_lock();
3774 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
3775                 if (pid > 0)
3776                         p = ccsecurity_exports.find_task_by_vpid((pid_t) pid);
3777                 else if (pid == 0)
3778                         p = current;
3779                 else if (pid == -1)
3780                         dest = &ccs_kernel_domain;
3781                 else
3782                         p = ccsecurity_exports.find_task_by_vpid((pid_t) -pid);
3783 #else
3784                 if (pid > 0)
3785                         p = find_task_by_pid((pid_t) pid);
3786                 else if (pid == 0)
3787                         p = current;
3788                 else if (pid == -1)
3789                         dest = &ccs_kernel_domain;
3790                 else
3791                         p = find_task_by_pid((pid_t) -pid);
3792 #endif
3793                 if (p)
3794                         dest = ccs_task_domain(p);
3795                 ccs_tasklist_unlock();
3796         }
3797         if (!dest)
3798                 return 0; /* I can't find destinatioin. */
3799         if (domain == dest) {
3800                 ccs_audit_log(&r);
3801                 return 0;                /* No check for self domain. */
3802         }
3803         r.param.signal.dest_pattern = dest->domainname->name;
3804         return ccs_check_acl(&r);
3805 }
3806 
3807 /**
3808  * ccs_signal_acl - Check permission for signal.
3809  *
3810  * @pid: Target's PID.
3811  * @sig: Signal number.
3812  *
3813  * Returns 0 on success, negative value otherwise.
3814  */
3815 static int ccs_signal_acl(const int pid, const int sig)
3816 {
3817         int error;
3818         if (!sig)
3819                 error = 0;
3820         else {
3821                 const int idx = ccs_read_lock();
3822                 error = ccs_signal_acl2(sig, pid);
3823                 ccs_read_unlock(idx);
3824         }
3825         return error;
3826 }
3827 
3828 /**
3829  * ccs_signal_acl0 - Permission check for signal().
3830  *
3831  * @tgid: Unused.
3832  * @pid:  Target's PID.
3833  * @sig:  Signal number.
3834  *
3835  * Returns 0 on success, negative value otherwise.
3836  */
3837 static int ccs_signal_acl0(pid_t tgid, pid_t pid, int sig)
3838 {
3839         return ccs_signal_acl(pid, sig);
3840 }
3841 
3842 #endif
3843 
3844 #ifdef CONFIG_CCSECURITY_MISC
3845 
3846 /**
3847  * ccs_check_env_acl - Check permission for environment variable's name.
3848  *
3849  * @r:   Pointer to "struct ccs_request_info".
3850  * @ptr: Pointer to "struct ccs_acl_info".
3851  *
3852  * Returns true if granted, false otherwise.
3853  */
3854 static bool ccs_check_env_acl(struct ccs_request_info *r,
3855                               const struct ccs_acl_info *ptr)
3856 {
3857         const struct ccs_env_acl *acl = container_of(ptr, typeof(*acl), head);
3858         return ccs_path_matches_pattern(r->param.environ.name, acl->env);
3859 }
3860 
3861 /**
3862  * ccs_env_perm - Check permission for environment variable's name.
3863  *
3864  * @r:   Pointer to "struct ccs_request_info".
3865  * @env: The name of environment variable.
3866  *
3867  * Returns 0 on success, negative value otherwise.
3868  *
3869  * Caller holds ccs_read_lock().
3870  */
3871 static int ccs_env_perm(struct ccs_request_info *r, const char *env)
3872 {
3873         struct ccs_path_info environ;
3874         if (!env || !*env)
3875                 return 0;
3876         environ.name = env;
3877         ccs_fill_path_info(&environ);
3878         r->param_type = CCS_TYPE_ENV_ACL;
3879         r->param.environ.name = &environ;
3880         return ccs_check_acl(r);
3881 }
3882 
3883 /**
3884  * ccs_environ - Check permission for environment variable names.
3885  *
3886  * @ee: Pointer to "struct ccs_execve".
3887  *
3888  * Returns 0 on success, negative value otherwise.
3889  */
3890 static int ccs_environ(struct ccs_execve *ee)
3891 {
3892         struct ccs_request_info *r = &ee->r;
3893         struct linux_binprm *bprm = ee->bprm;
3894         /* env_page.data is allocated by ccs_dump_page(). */
3895         struct ccs_page_dump env_page = { };
3896         char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
3897         int arg_len = 0;
3898         unsigned long pos = bprm->p;
3899         int offset = pos % PAGE_SIZE;
3900         int argv_count = bprm->argc;
3901         int envp_count = bprm->envc;
3902         /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
3903         int error = -ENOMEM;
3904         ee->r.type = CCS_MAC_ENVIRON;
3905         ee->r.profile = ccs_current_domain()->profile;
3906         ee->r.mode = ccs_get_mode(ee->r.profile, CCS_MAC_ENVIRON);
3907         if (!r->mode || !envp_count)
3908                 return 0;
3909         arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
3910         if (!arg_ptr)
3911                 goto out;
3912         while (error == -ENOMEM) {
3913                 if (!ccs_dump_page(bprm, pos, &env_page))
3914                         goto out;
3915                 pos += PAGE_SIZE - offset;
3916                 /* Read. */
3917                 while (argv_count && offset < PAGE_SIZE) {
3918                         if (!env_page.data[offset++])
3919                                 argv_count--;
3920                 }
3921                 if (argv_count) {
3922                         offset = 0;
3923                         continue;
3924                 }
3925                 while (offset < PAGE_SIZE) {
3926                         const unsigned char c = env_page.data[offset++];
3927                         if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
3928                                 if (c == '=') {
3929                                         arg_ptr[arg_len++] = '\0';
3930                                 } else if (c == '\\') {
3931                                         arg_ptr[arg_len++] = '\\';
3932                                         arg_ptr[arg_len++] = '\\';
3933                                 } else if (c > ' ' && c < 127) {
3934                                         arg_ptr[arg_len++] = c;
3935                                 } else {
3936                                         arg_ptr[arg_len++] = '\\';
3937                                         arg_ptr[arg_len++] = (c >> 6) + '';
3938                                         arg_ptr[arg_len++]
3939                                                 = ((c >> 3) & 7) + '';
3940                                         arg_ptr[arg_len++] = (c & 7) + '';
3941                                 }
3942                         } else {
3943                                 arg_ptr[arg_len] = '\0';
3944                         }
3945                         if (c)
3946                                 continue;
3947                         if (ccs_env_perm(r, arg_ptr)) {
3948                                 error = -EPERM;
3949                                 break;
3950                         }
3951                         if (!--envp_count) {
3952                                 error = 0;
3953                                 break;
3954                         }
3955                         arg_len = 0;
3956                 }
3957                 offset = 0;
3958         }
3959 out:
3960         if (r->mode != CCS_CONFIG_ENFORCING)
3961                 error = 0;
3962         kfree(env_page.data);
3963         kfree(arg_ptr);
3964         return error;
3965 }
3966 
3967 #endif
3968 
3969 /**
3970  * ccs_argv - Check argv[] in "struct linux_binbrm".
3971  *
3972  * @index:   Index number of @arg_ptr.
3973  * @arg_ptr: Contents of argv[@index].
3974  * @argc:    Length of @argv.
3975  * @argv:    Pointer to "struct ccs_argv".
3976  * @checked: Set to true if @argv[@index] was found.
3977  *
3978  * Returns true on success, false otherwise.
3979  */
3980 static bool ccs_argv(const unsigned int index, const char *arg_ptr,
3981                      const int argc, const struct ccs_argv *argv,
3982                      u8 *checked)
3983 {
3984         int i;
3985         struct ccs_path_info arg;
3986         arg.name = arg_ptr;
3987         for (i = 0; i < argc; argv++, checked++, i++) {
3988                 bool result;
3989                 if (index != argv->index)
3990                         continue;
3991                 *checked = 1;
3992                 ccs_fill_path_info(&arg);
3993                 result = ccs_path_matches_pattern(&arg, argv->value);
3994                 if (argv->is_not)
3995                         result = !result;
3996                 if (!result)
3997                         return false;
3998         }
3999         return true;
4000 }
4001 
4002 /**
4003  * ccs_envp - Check envp[] in "struct linux_binbrm".
4004  *
4005  * @env_name:  The name of environment variable.
4006  * @env_value: The value of environment variable.
4007  * @envc:      Length of @envp.
4008  * @envp:      Pointer to "struct ccs_envp".
4009  * @checked:   Set to true if @envp[@env_name] was found.
4010  *
4011  * Returns true on success, false otherwise.
4012  */
4013 static bool ccs_envp(const char *env_name, const char *env_value,
4014                      const int envc, const struct ccs_envp *envp,
4015                      u8 *checked)
4016 {
4017         int i;
4018         struct ccs_path_info name;
4019         struct ccs_path_info value;
4020         name.name = env_name;
4021         ccs_fill_path_info(&name);
4022         value.name = env_value;
4023         ccs_fill_path_info(&value);
4024         for (i = 0; i < envc; envp++, checked++, i++) {
4025                 bool result;
4026                 if (!ccs_path_matches_pattern(&name, envp->name))
4027                         continue;
4028                 *checked = 1;
4029                 if (envp->value) {
4030                         result = ccs_path_matches_pattern(&value, envp->value);
4031                         if (envp->is_not)
4032                                 result = !result;
4033                 } else {
4034                         result = true;
4035                         if (!envp->is_not)
4036                                 result = !result;
4037                 }
4038                 if (!result)
4039                         return false;
4040         }
4041         return true;
4042 }
4043 
4044 /**
4045  * ccs_scan_bprm - Scan "struct linux_binprm".
4046  *
4047  * @ee:   Pointer to "struct ccs_execve".
4048  * @argc: Length of @argc.
4049  * @argv: Pointer to "struct ccs_argv".
4050  * @envc: Length of @envp.
4051  * @envp: Poiner to "struct ccs_envp".
4052  *
4053  * Returns true on success, false otherwise.
4054  */
4055 static bool ccs_scan_bprm(struct ccs_execve *ee,
4056                           const u16 argc, const struct ccs_argv *argv,
4057                           const u16 envc, const struct ccs_envp *envp)
4058 {
4059         struct linux_binprm *bprm = ee->bprm;
4060         struct ccs_page_dump *dump = &ee->dump;
4061         char *arg_ptr = ee->tmp;
4062         int arg_len = 0;
4063         unsigned long pos = bprm->p;
4064         int offset = pos % PAGE_SIZE;
4065         int argv_count = bprm->argc;
4066         int envp_count = bprm->envc;
4067         bool result = true;
4068         u8 local_checked[32];
4069         u8 *checked;
4070         if (argc + envc <= sizeof(local_checked)) {
4071                 checked = local_checked;
4072                 memset(local_checked, 0, sizeof(local_checked));
4073         } else {
4074                 checked = kzalloc(argc + envc, CCS_GFP_FLAGS);
4075                 if (!checked)
4076                         return false;
4077         }
4078         while (argv_count || envp_count) {
4079                 if (!ccs_dump_page(bprm, pos, dump)) {
4080                         result = false;
4081                         goto out;
4082                 }
4083                 pos += PAGE_SIZE - offset;
4084                 while (offset < PAGE_SIZE) {
4085                         /* Read. */
4086                         const char *kaddr = dump->data;
4087                         const unsigned char c = kaddr[offset++];
4088                         if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
4089                                 if (c == '\\') {
4090                                         arg_ptr[arg_len++] = '\\';
4091                                         arg_ptr[arg_len++] = '\\';
4092                                 } else if (c > ' ' && c < 127) {
4093                                         arg_ptr[arg_len++] = c;
4094                                 } else {
4095                                         arg_ptr[arg_len++] = '\\';
4096                                         arg_ptr[arg_len++] = (c >> 6) + '';
4097                                         arg_ptr[arg_len++] =
4098                                                 ((c >> 3) & 7) + '';
4099                                         arg_ptr[arg_len++] = (c & 7) + '';
4100                                 }
4101                         } else {
4102                                 arg_ptr[arg_len] = '\0';
4103                         }
4104                         if (c)
4105                                 continue;
4106                         /* Check. */
4107                         if (argv_count) {
4108                                 if (!ccs_argv(bprm->argc - argv_count,
4109                                               arg_ptr, argc, argv,
4110                                               checked)) {
4111                                         result = false;
4112                                         break;
4113                                 }
4114                                 argv_count--;
4115                         } else if (envp_count) {
4116                                 char *cp = strchr(arg_ptr, '=');
4117                                 if (cp) {
4118                                         *cp = '\0';
4119                                         if (!ccs_envp(arg_ptr, cp + 1,
4120                                                       envc, envp,
4121                                                       checked + argc)) {
4122                                                 result = false;
4123                                                 break;
4124                                         }
4125                                 }
4126                                 envp_count--;
4127                         } else {
4128                                 break;
4129                         }
4130                         arg_len = 0;
4131                 }
4132                 offset = 0;
4133                 if (!result)
4134                         break;
4135         }
4136 out:
4137         if (result) {
4138                 int i;
4139                 /* Check not-yet-checked entries. */
4140                 for (i = 0; i < argc; i++) {
4141                         if (checked[i])
4142                                 continue;
4143                         /*
4144                          * Return true only if all unchecked indexes in
4145                          * bprm->argv[] are not matched.
4146                          */
4147                         if (argv[i].is_not)
4148                                 continue;
4149                         result = false;
4150                         break;
4151                 }
4152                 for (i = 0; i < envc; envp++, i++) {
4153                         if (checked[argc + i])
4154                                 continue;
4155                         /*
4156                          * Return true only if all unchecked environ variables
4157                          * in bprm->envp[] are either undefined or not matched.
4158                          */
4159                         if ((!envp->value && !envp->is_not) ||
4160                             (envp->value && envp->is_not))
4161                                 continue;
4162                         result = false;
4163                         break;
4164                 }
4165         }
4166         if (checked != local_checked)
4167                 kfree(checked);
4168         return result;
4169 }
4170 
4171 /**
4172  * ccs_scan_exec_realpath - Check "exec.realpath" parameter of "struct ccs_condition".
4173  *
4174  * @file:  Pointer to "struct file".
4175  * @ptr:   Pointer to "struct ccs_name_union".
4176  * @match: True if "exec.realpath=", false if "exec.realpath!=".
4177  *
4178  * Returns true on success, false otherwise.
4179  */
4180 static bool ccs_scan_exec_realpath(struct file *file,
4181                                    const struct ccs_name_union *ptr,
4182                                    const bool match)
4183 {
4184         bool result;
4185         struct ccs_path_info exe;
4186 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
4187         struct path path;
4188 #endif
4189         if (!file)
4190                 return false;
4191 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
4192         exe.name = ccs_realpath(&file->f_path);
4193 #else
4194         path.mnt = file->f_vfsmnt;
4195         path.dentry = file->f_dentry;
4196         exe.name = ccs_realpath(&path);
4197 #endif
4198         if (!exe.name)
4199                 return false;
4200         ccs_fill_path_info(&exe);
4201         result = ccs_compare_name_union(&exe, ptr);
4202         kfree(exe.name);
4203         return result == match;
4204 }
4205 
4206 /**
4207  * ccs_get_attributes - Revalidate "struct inode".
4208  *
4209  * @obj: Pointer to "struct ccs_obj_info".
4210  *
4211  * Returns nothing.
4212  */
4213 void ccs_get_attributes(struct ccs_obj_info *obj)
4214 {
4215         u8 i;
4216         struct dentry *dentry = NULL;
4217 
4218         for (i = 0; i < CCS_MAX_PATH_STAT; i++) {
4219                 struct inode *inode;
4220                 switch (i) {
4221                 case CCS_PATH1:
4222                         dentry = obj->path1.dentry;
4223                         if (!dentry)
4224                                 continue;
4225                         break;
4226                 case CCS_PATH2:
4227                         dentry = obj->path2.dentry;
4228                         if (!dentry)
4229                                 continue;
4230                         break;
4231                 default:
4232                         if (!dentry)
4233                                 continue;
4234 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
4235                         spin_lock(&dcache_lock);
4236                         dentry = dget(dentry->d_parent);
4237                         spin_unlock(&dcache_lock);
4238 #else
4239                         dentry = dget_parent(dentry);
4240 #endif
4241                         break;
4242                 }
4243                 inode = d_backing_inode(dentry);
4244                 if (inode) {
4245                         struct ccs_mini_stat *stat = &obj->stat[i];
4246                         stat->uid  = inode->i_uid;
4247                         stat->gid  = inode->i_gid;
4248                         stat->ino  = inode->i_ino;
4249                         stat->mode = inode->i_mode;
4250 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
4251                         stat->dev  = inode->i_dev;
4252 #else
4253                         stat->dev  = inode->i_sb->s_dev;
4254 #endif
4255                         stat->rdev = inode->i_rdev;
4256                         obj->stat_valid[i] = true;
4257                 }
4258                 if (i & 1) /* i == CCS_PATH1_PARENT || i == CCS_PATH2_PARENT */
4259                         dput(dentry);
4260         }
4261 }
4262 
4263 /**
4264  * ccs_condition - Check condition part.
4265  *
4266  * @r:    Pointer to "struct ccs_request_info".
4267  * @cond: Pointer to "struct ccs_condition". Maybe NULL.
4268  *
4269  * Returns true on success, false otherwise.
4270  *
4271  * Caller holds ccs_read_lock().
4272  */
4273 static bool ccs_condition(struct ccs_request_info *r,
4274                           const struct ccs_condition *cond)
4275 {
4276         const u32 ccs_flags = ccs_current_flags();
4277         u32 i;
4278         unsigned long min_v[2] = { 0, 0 };
4279         unsigned long max_v[2] = { 0, 0 };
4280         const struct ccs_condition_element *condp;
4281         const struct ccs_number_union *numbers_p;
4282         const struct ccs_name_union *names_p;
4283         const struct ccs_argv *argv;
4284         const struct ccs_envp *envp;
4285         struct ccs_obj_info *obj;
4286         u16 condc;
4287         u16 argc;
4288         u16 envc;
4289         struct linux_binprm *bprm = NULL;
4290         if (!cond)
4291                 return true;
4292         condc = cond->condc;
4293         argc = cond->argc;
4294         envc = cond->envc;
4295         obj = r->obj;
4296         if (r->ee)
4297                 bprm = r->ee->bprm;
4298         if (!bprm && (argc || envc))
4299                 return false;
4300         condp = (struct ccs_condition_element *) (cond + 1);
4301         numbers_p = (const struct ccs_number_union *) (condp + condc);
4302         names_p = (const struct ccs_name_union *)
4303                 (numbers_p + cond->numbers_count);
4304         argv = (const struct ccs_argv *) (names_p + cond->names_count);
4305         envp = (const struct ccs_envp *) (argv + argc);
4306         for (i = 0; i < condc; i++) {
4307                 const bool match = condp->equals;
4308                 const u8 left = condp->left;
4309                 const u8 right = condp->right;
4310                 bool is_bitop[2] = { false, false };
4311                 u8 j;
4312                 condp++;
4313                 /* Check argv[] and envp[] later. */
4314                 if (left == CCS_ARGV_ENTRY || left == CCS_ENVP_ENTRY)
4315                         continue;
4316                 /* Check string expressions. */
4317                 if (right == CCS_NAME_UNION) {
4318                         const struct ccs_name_union *ptr = names_p++;
4319                         switch (left) {
4320                                 struct ccs_path_info *symlink;
4321                                 struct ccs_execve *ee;
4322                                 struct file *file;
4323                         case CCS_SYMLINK_TARGET:
4324                                 symlink = obj ? obj->symlink_target : NULL;
4325                                 if (!symlink ||
4326                                     !ccs_compare_name_union(symlink, ptr)
4327                                     == match)
4328                                         goto out;
4329                                 break;
4330                         case CCS_EXEC_REALPATH:
4331                                 ee = r->ee;
4332                                 file = ee ? ee->bprm->file : NULL;
4333                                 if (!ccs_scan_exec_realpath(file, ptr, match))
4334                                         goto out;
4335                                 break;
4336                         }
4337                         continue;
4338                 }
4339                 /* Check numeric or bit-op expressions. */
4340                 for (j = 0; j < 2; j++) {
4341                         const u8 index = j ? right : left;
4342                         unsigned long value = 0;
4343                         switch (index) {
4344                         case CCS_TASK_UID:
4345                                 value = from_kuid(&init_user_ns,
4346                                                   current_uid());
4347                                 break;
4348                         case CCS_TASK_EUID:
4349                                 value = from_kuid(&init_user_ns,
4350                                                   current_euid());
4351                                 break;
4352                         case CCS_TASK_SUID:
4353                                 value = from_kuid(&init_user_ns,
4354                                                   current_suid());
4355                                 break;
4356                         case CCS_TASK_FSUID:
4357                                 value = from_kuid(&init_user_ns,
4358                                                   current_fsuid());
4359                                 break;
4360                         case CCS_TASK_GID:
4361                                 value = from_kgid(&init_user_ns,
4362                                                   current_gid());
4363                                 break;
4364                         case CCS_TASK_EGID:
4365                                 value = from_kgid(&init_user_ns,
4366                                                   current_egid());
4367                                 break;
4368                         case CCS_TASK_SGID:
4369                                 value = from_kgid(&init_user_ns,
4370                                                   current_sgid());
4371                                 break;
4372                         case CCS_TASK_FSGID:
4373                                 value = from_kgid(&init_user_ns,
4374                                                   current_fsgid());
4375                                 break;
4376                         case CCS_TASK_PID:
4377                                 value = ccs_sys_getpid();
4378                                 break;
4379                         case CCS_TASK_PPID:
4380                                 value = ccs_sys_getppid();
4381                                 break;
4382                         case CCS_TYPE_IS_SOCKET:
4383                                 value = S_IFSOCK;
4384                                 break;
4385                         case CCS_TYPE_IS_SYMLINK:
4386                                 value = S_IFLNK;
4387                                 break;
4388                         case CCS_TYPE_IS_FILE:
4389                                 value = S_IFREG;
4390                                 break;
4391                         case CCS_TYPE_IS_BLOCK_DEV:
4392                                 value = S_IFBLK;
4393                                 break;
4394                         case CCS_TYPE_IS_DIRECTORY:
4395                                 value = S_IFDIR;
4396                                 break;
4397                         case CCS_TYPE_IS_CHAR_DEV:
4398                                 value = S_IFCHR;
4399                                 break;
4400                         case CCS_TYPE_IS_FIFO:
4401                                 value = S_IFIFO;
4402                                 break;
4403                         case CCS_MODE_SETUID:
4404                                 value = S_ISUID;
4405                                 break;
4406                         case CCS_MODE_SETGID:
4407                                 value = S_ISGID;
4408                                 break;
4409                         case CCS_MODE_STICKY:
4410                                 value = S_ISVTX;
4411                                 break;
4412                         case CCS_MODE_OWNER_READ:
4413                                 value = S_IRUSR;
4414                                 break;
4415                         case CCS_MODE_OWNER_WRITE:
4416                                 value = S_IWUSR;
4417                                 break;
4418                         case CCS_MODE_OWNER_EXECUTE:
4419                                 value = S_IXUSR;
4420                                 break;
4421                         case CCS_MODE_GROUP_READ:
4422                                 value = S_IRGRP;
4423                                 break;
4424                         case CCS_MODE_GROUP_WRITE:
4425                                 value = S_IWGRP;
4426                                 break;
4427                         case CCS_MODE_GROUP_EXECUTE:
4428                                 value = S_IXGRP;
4429                                 break;
4430                         case CCS_MODE_OTHERS_READ:
4431                                 value = S_IROTH;
4432                                 break;
4433                         case CCS_MODE_OTHERS_WRITE:
4434                                 value = S_IWOTH;
4435                                 break;
4436                         case CCS_MODE_OTHERS_EXECUTE:
4437                                 value = S_IXOTH;
4438                                 break;
4439                         case CCS_EXEC_ARGC:
4440                                 if (!bprm)
4441                                         goto out;
4442                                 value = bprm->argc;
4443                                 break;
4444                         case CCS_EXEC_ENVC:
4445                                 if (!bprm)
4446                                         goto out;
4447                                 value = bprm->envc;
4448                                 break;
4449                         case CCS_TASK_TYPE:
4450                                 value = ((u8) ccs_flags)
4451                                         & CCS_TASK_IS_EXECUTE_HANDLER;
4452                                 break;
4453                         case CCS_TASK_EXECUTE_HANDLER:
4454                                 value = CCS_TASK_IS_EXECUTE_HANDLER;
4455                                 break;
4456                         case CCS_NUMBER_UNION:
4457                                 /* Fetch values later. */
4458                                 break;
4459                         default:
4460                                 if (!obj)
4461                                         goto out;
4462                                 if (!obj->validate_done) {
4463                                         ccs_get_attributes(obj);
4464                                         obj->validate_done = true;
4465                                 }
4466                                 {
4467                                         u8 stat_index;
4468                                         struct ccs_mini_stat *stat;
4469                                         switch (index) {
4470                                         case CCS_PATH1_UID:
4471                                         case CCS_PATH1_GID:
4472                                         case CCS_PATH1_INO:
4473                                         case CCS_PATH1_MAJOR:
4474                                         case CCS_PATH1_MINOR:
4475                                         case CCS_PATH1_TYPE:
4476                                         case CCS_PATH1_DEV_MAJOR:
4477                                         case CCS_PATH1_DEV_MINOR:
4478                                         case CCS_PATH1_PERM:
4479                                                 stat_index = CCS_PATH1;
4480                                                 break;
4481                                         case CCS_PATH2_UID:
4482                                         case CCS_PATH2_GID:
4483                                         case CCS_PATH2_INO:
4484                                         case CCS_PATH2_MAJOR:
4485                                         case CCS_PATH2_MINOR:
4486                                         case CCS_PATH2_TYPE:
4487                                         case CCS_PATH2_DEV_MAJOR:
4488                                         case CCS_PATH2_DEV_MINOR:
4489                                         case CCS_PATH2_PERM:
4490                                                 stat_index = CCS_PATH2;
4491                                                 break;
4492                                         case CCS_PATH1_PARENT_UID:
4493                                         case CCS_PATH1_PARENT_GID:
4494                                         case CCS_PATH1_PARENT_INO:
4495                                         case CCS_PATH1_PARENT_PERM:
4496                                                 stat_index = CCS_PATH1_PARENT;
4497                                                 break;
4498                                         case CCS_PATH2_PARENT_UID:
4499                                         case CCS_PATH2_PARENT_GID:
4500                                         case CCS_PATH2_PARENT_INO:
4501                                         case CCS_PATH2_PARENT_PERM:
4502                                                 stat_index = CCS_PATH2_PARENT;
4503                                                 break;
4504                                         default:
4505                                                 goto out;
4506                                         }
4507                                         if (!obj->stat_valid[stat_index])
4508                                                 goto out;
4509                                         stat = &obj->stat[stat_index];
4510                                         switch (index) {
4511                                         case CCS_PATH1_UID:
4512                                         case CCS_PATH2_UID:
4513                                         case CCS_PATH1_PARENT_UID:
4514                                         case CCS_PATH2_PARENT_UID:
4515                                                 value = from_kuid
4516                                                         (&init_user_ns,
4517                                                          stat->uid);
4518                                                 break;
4519                                         case CCS_PATH1_GID:
4520                                         case CCS_PATH2_GID:
4521                                         case CCS_PATH1_PARENT_GID:
4522                                         case CCS_PATH2_PARENT_GID:
4523                                                 value = from_kgid
4524                                                         (&init_user_ns,
4525                                                          stat->gid);
4526                                                 break;
4527                                         case CCS_PATH1_INO:
4528                                         case CCS_PATH2_INO:
4529                                         case CCS_PATH1_PARENT_INO:
4530                                         case CCS_PATH2_PARENT_INO:
4531                                                 value = stat->ino;
4532                                                 break;
4533                                         case CCS_PATH1_MAJOR:
4534                                         case CCS_PATH2_MAJOR:
4535                                                 value = MAJOR(stat->dev);
4536                                                 break;
4537                                         case CCS_PATH1_MINOR:
4538                                         case CCS_PATH2_MINOR:
4539                                                 value = MINOR(stat->dev);
4540                                                 break;
4541                                         case CCS_PATH1_TYPE:
4542                                         case CCS_PATH2_TYPE:
4543                                                 value = stat->mode & S_IFMT;
4544                                                 break;
4545                                         case CCS_PATH1_DEV_MAJOR:
4546                                         case CCS_PATH2_DEV_MAJOR:
4547                                                 value = MAJOR(stat->rdev);
4548                                                 break;
4549                                         case CCS_PATH1_DEV_MINOR:
4550                                         case CCS_PATH2_DEV_MINOR:
4551                                                 value = MINOR(stat->rdev);
4552                                                 break;
4553                                         case CCS_PATH1_PERM:
4554                                         case CCS_PATH2_PERM:
4555                                         case CCS_PATH1_PARENT_PERM:
4556                                         case CCS_PATH2_PARENT_PERM:
4557                                                 value = stat->mode & S_IALLUGO;
4558                                                 break;
4559                                         }
4560                                 }
4561                                 break;
4562                         }
4563                         max_v[j] = value;
4564                         min_v[j] = value;
4565                         switch (index) {
4566                         case CCS_MODE_SETUID:
4567                         case CCS_MODE_SETGID:
4568                         case CCS_MODE_STICKY:
4569                         case CCS_MODE_OWNER_READ:
4570                         case CCS_MODE_OWNER_WRITE:
4571                         case CCS_MODE_OWNER_EXECUTE:
4572                         case CCS_MODE_GROUP_READ:
4573                         case CCS_MODE_GROUP_WRITE:
4574                         case CCS_MODE_GROUP_EXECUTE:
4575                         case CCS_MODE_OTHERS_READ:
4576                         case CCS_MODE_OTHERS_WRITE:
4577                         case CCS_MODE_OTHERS_EXECUTE:
4578                                 is_bitop[j] = true;
4579                         }
4580                 }
4581                 if (left == CCS_NUMBER_UNION) {
4582                         /* Fetch values now. */
4583                         const struct ccs_number_union *ptr = numbers_p++;
4584                         min_v[0] = ptr->values[0];
4585                         max_v[0] = ptr->values[1];
4586                 }
4587                 if (right == CCS_NUMBER_UNION) {
4588                         /* Fetch values now. */
4589                         const struct ccs_number_union *ptr = numbers_p++;
4590                         if (ptr->group) {
4591                                 if (ccs_number_matches_group(min_v[0],
4592                                                              max_v[0],
4593                                                              ptr->group)
4594                                     == match)
4595                                         continue;
4596                         } else {
4597                                 if ((min_v[0] <= ptr->values[1] &&
4598                                      max_v[0] >= ptr->values[0]) == match)
4599                                         continue;
4600                         }
4601                         goto out;
4602                 }
4603                 /*
4604                  * Bit operation is valid only when counterpart value
4605                  * represents permission.
4606                  */
4607                 if (is_bitop[0] && is_bitop[1]) {
4608                         goto out;
4609                 } else if (is_bitop[0]) {
4610                         switch (right) {
4611                         case CCS_PATH1_PERM:
4612                         case CCS_PATH1_PARENT_PERM:
4613                         case CCS_PATH2_PERM:
4614                         case CCS_PATH2_PARENT_PERM:
4615                                 if (!(max_v[0] & max_v[1]) == !match)
4616                                         continue;
4617                         }
4618                         goto out;
4619                 } else if (is_bitop[1]) {
4620                         switch (left) {
4621                         case CCS_PATH1_PERM:
4622                         case CCS_PATH1_PARENT_PERM:
4623                         case CCS_PATH2_PERM:
4624                         case CCS_PATH2_PARENT_PERM:
4625                                 if (!(max_v[0] & max_v[1]) == !match)
4626                                         continue;
4627                         }
4628                         goto out;
4629                 }
4630                 /* Normal value range comparison. */
4631                 if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
4632                         continue;
4633 out:
4634                 return false;
4635         }
4636         /* Check argv[] and envp[] now. */
4637         if (r->ee && (argc || envc))
4638                 return ccs_scan_bprm(r->ee, argc, argv, envc, envp);
4639         return true;
4640 }
4641 
4642 #ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
4643 
4644 /**
4645  * ccs_check_task_acl - Check permission for task operation.
4646  *
4647  * @r:   Pointer to "struct ccs_request_info".
4648  * @ptr: Pointer to "struct ccs_acl_info".
4649  *
4650  * Returns true if granted, false otherwise.
4651  */
4652 static bool ccs_check_task_acl(struct ccs_request_info *r,
4653                                const struct ccs_acl_info *ptr)
4654 {
4655         const struct ccs_task_acl *acl = container_of(ptr, typeof(*acl), head);
4656         return !ccs_pathcmp(r->param.task.domainname, acl->domainname);
4657 }
4658 
4659 #endif
4660 
4661 /**
4662  * ccs_init_request_info - Initialize "struct ccs_request_info" members.
4663  *
4664  * @r:     Pointer to "struct ccs_request_info" to initialize.
4665  * @index: Index number of functionality.
4666  *
4667  * Returns mode.
4668  *
4669  * "task auto_domain_transition" keyword is evaluated before returning mode for
4670  * @index. If "task auto_domain_transition" keyword was specified and
4671  * transition to that domain failed, the current thread will be killed by
4672  * SIGKILL. Note that if current->pid == 1, sending SIGKILL won't work.
4673  */
4674 int ccs_init_request_info(struct ccs_request_info *r, const u8 index)
4675 {
4676 #ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
4677         u8 i;
4678         const char *buf;
4679         for (i = 0; i < 255; i++) {
4680                 const u8 profile = ccs_current_domain()->profile;
4681                 memset(r, 0, sizeof(*r));
4682                 r->profile = profile;
4683                 r->type = index;
4684                 r->mode = ccs_get_mode(profile, index);
4685                 r->param_type = CCS_TYPE_AUTO_TASK_ACL;
4686                 ccs_check_acl(r);
4687                 if (!r->granted)
4688                         return r->mode;
4689                 buf = container_of(r->matched_acl, typeof(struct ccs_task_acl),
4690                                    head)->domainname->name;
4691                 if (!ccs_assign_domain(buf, true))
4692                         break;
4693         }
4694         ccs_transition_failed(buf);
4695         return CCS_CONFIG_DISABLED;
4696 #else
4697         const u8 profile = ccs_current_domain()->profile;
4698         memset(r, 0, sizeof(*r));
4699         r->profile = profile;
4700         r->type = index;
4701         r->mode = ccs_get_mode(profile, index);
4702         return r->mode;
4703 #endif
4704 }
4705 
4706 /**
4707  * ccs_byte_range - Check whether the string is a \ooo style octal value.
4708  *
4709  * @str: Pointer to the string.
4710  *
4711  * Returns true if @str is a \ooo style octal value, false otherwise.
4712  */
4713 static bool ccs_byte_range(const char *str)
4714 {
4715         return *str >= '' && *str++ <= '3' &&
4716                 *str >= '' && *str++ <= '7' &&
4717                 *str >= '' && *str <= '7';
4718 }
4719 
4720 /**
4721  * ccs_decimal - Check whether the character is a decimal character.
4722  *
4723  * @c: The character to check.
4724  *
4725  * Returns true if @c is a decimal character, false otherwise.
4726  */
4727 static bool ccs_decimal(const char c)
4728 {
4729         return c >= '' && c <= '9';
4730 }
4731 
4732 /**
4733  * ccs_hexadecimal - Check whether the character is a hexadecimal character.
4734  *
4735  * @c: The character to check.
4736  *
4737  * Returns true if @c is a hexadecimal character, false otherwise.
4738  */
4739 static bool ccs_hexadecimal(const char c)
4740 {
4741         return (c >= '' && c <= '9') ||
4742                 (c >= 'A' && c <= 'F') ||
4743                 (c >= 'a' && c <= 'f');
4744 }
4745 
4746 /**
4747  * ccs_alphabet_char - Check whether the character is an alphabet.
4748  *
4749  * @c: The character to check.
4750  *
4751  * Returns true if @c is an alphabet character, false otherwise.
4752  */
4753 static bool ccs_alphabet_char(const char c)
4754 {
4755         return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
4756 }
4757 
4758 /**
4759  * ccs_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
4760  *
4761  * @filename:     The start of string to check.
4762  * @filename_end: The end of string to check.
4763  * @pattern:      The start of pattern to compare.
4764  * @pattern_end:  The end of pattern to compare.
4765  *
4766  * Returns true if @filename matches @pattern, false otherwise.
4767  */
4768 static bool ccs_file_matches_pattern2(const char *filename,
4769                                       const char *filename_end,
4770                                       const char *pattern,
4771                                       const char *pattern_end)
4772 {
4773         while (filename < filename_end && pattern < pattern_end) {
4774                 char c;
4775                 if (*pattern != '\\') {
4776                         if (*filename++ != *pattern++)
4777                                 return false;
4778                         continue;
4779                 }
4780                 c = *filename;
4781                 pattern++;
4782                 switch (*pattern) {
4783                         int i;
4784                         int j;
4785                 case '?':
4786                         if (c == '/') {
4787                                 return false;
4788                         } else if (c == '\\') {
4789                                 if (filename[1] == '\\')
4790                                         filename++;
4791                                 else if (ccs_byte_range(filename + 1))
4792                                         filename += 3;
4793                                 else
4794                                         return false;
4795                         }
4796                         break;
4797                 case '\\':
4798                         if (c != '\\')
4799                                 return false;
4800                         if (*++filename != '\\')
4801                                 return false;
4802                         break;
4803                 case '+':
4804                         if (!ccs_decimal(c))
4805                                 return false;
4806                         break;
4807                 case 'x':
4808                         if (!ccs_hexadecimal(c))
4809                                 return false;
4810                         break;
4811                 case 'a':
4812                         if (!ccs_alphabet_char(c))
4813                                 return false;
4814                         break;
4815                 case '':
4816                 case '1':
4817                 case '2':
4818                 case '3':
4819                         if (c == '\\' && ccs_byte_range(filename + 1)
4820                             && !strncmp(filename + 1, pattern, 3)) {
4821                                 filename += 3;
4822                                 pattern += 2;
4823                                 break;
4824                         }
4825                         return false; /* Not matched. */
4826                 case '*':
4827                 case '@':
4828                         for (i = 0; i <= filename_end - filename; i++) {
4829                                 if (ccs_file_matches_pattern2(filename + i,
4830                                                               filename_end,
4831                                                               pattern + 1,
4832                                                               pattern_end))
4833                                         return true;
4834                                 c = filename[i];
4835                                 if (c == '.' && *pattern == '@')
4836                                         break;
4837                                 if (c != '\\')
4838                                         continue;
4839                                 if (filename[i + 1] == '\\')
4840                                         i++;
4841                                 else if (ccs_byte_range(filename + i + 1))
4842                                         i += 3;
4843                                 else
4844                                         break; /* Bad pattern. */
4845                         }
4846                         return false; /* Not matched. */
4847                 default:
4848                         j = 0;
4849                         c = *pattern;
4850                         if (c == '$') {
4851                                 while (ccs_decimal(filename[j]))
4852                                         j++;
4853                         } else if (c == 'X') {
4854                                 while (ccs_hexadecimal(filename[j]))
4855                                         j++;
4856                         } else if (c == 'A') {
4857                                 while (ccs_alphabet_char(filename[j]))
4858                                         j++;
4859                         }
4860                         for (i = 1; i <= j; i++) {
4861                                 if (ccs_file_matches_pattern2(filename + i,
4862                                                               filename_end,
4863                                                               pattern + 1,
4864                                                               pattern_end))
4865                                         return true;
4866                         }
4867                         return false; /* Not matched or bad pattern. */
4868                 }
4869                 filename++;
4870                 pattern++;
4871         }
4872         while (*pattern == '\\' &&
4873                (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
4874                 pattern += 2;
4875         return filename == filename_end && pattern == pattern_end;
4876 }
4877 
4878 /**
4879  * ccs_file_matches_pattern - Pattern matching without '/' character.
4880  *
4881  * @filename:     The start of string to check.
4882  * @filename_end: The end of string to check.
4883  * @pattern:      The start of pattern to compare.
4884  * @pattern_end:  The end of pattern to compare.
4885  *
4886  * Returns true if @filename matches @pattern, false otherwise.
4887  */
4888 static bool ccs_file_matches_pattern(const char *filename,
4889                                      const char *filename_end,
4890                                      const char *pattern,
4891                                      const char *pattern_end)
4892 {
4893         const char *pattern_start = pattern;
4894         bool first = true;
4895         bool result;
4896         while (pattern < pattern_end - 1) {
4897                 /* Split at "\-" pattern. */
4898                 if (*pattern++ != '\\' || *pattern++ != '-')
4899                         continue;
4900                 result = ccs_file_matches_pattern2(filename, filename_end,
4901                                                    pattern_start, pattern - 2);
4902                 if (first)
4903                         result = !result;
4904                 if (result)
4905                         return false;
4906                 first = false;
4907                 pattern_start = pattern;
4908         }
4909         result = ccs_file_matches_pattern2(filename, filename_end,
4910                                            pattern_start, pattern_end);
4911         return first ? result : !result;
4912 }
4913 
4914 /**
4915  * ccs_path_matches_pattern2 - Do pathname pattern matching.
4916  *
4917  * @f: The start of string to check.
4918  * @p: The start of pattern to compare.
4919  *
4920  * Returns true if @f matches @p, false otherwise.
4921  */
4922 static bool ccs_path_matches_pattern2(const char *f, const char *p)
4923 {
4924         const char *f_delimiter;
4925         const char *p_delimiter;
4926         while (*f && *p) {
4927                 f_delimiter = strchr(f, '/');
4928                 if (!f_delimiter)
4929                         f_delimiter = f + strlen(f);
4930                 p_delimiter = strchr(p, '/');
4931                 if (!p_delimiter)
4932                         p_delimiter = p + strlen(p);
4933                 if (*p == '\\' && *(p + 1) == '{')
4934                         goto recursive;
4935                 if (!ccs_file_matches_pattern(f, f_delimiter, p, p_delimiter))
4936                         return false;
4937                 f = f_delimiter;
4938                 if (*f)
4939                         f++;
4940                 p = p_delimiter;
4941                 if (*p)
4942                         p++;
4943         }
4944         /* Ignore trailing "\*" and "\@" in @pattern. */
4945         while (*p == '\\' &&
4946                (*(p + 1) == '*' || *(p + 1) == '@'))
4947                 p += 2;
4948         return !*f && !*p;
4949 recursive:
4950         /*
4951          * The "\{" pattern is permitted only after '/' character.
4952          * This guarantees that below "*(p - 1)" is safe.
4953          * Also, the "\}" pattern is permitted only before '/' character
4954          * so that "\{" + "\}" pair will not break the "\-" operator.
4955          */
4956         if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
4957             *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
4958                 return false; /* Bad pattern. */
4959         do {
4960                 /* Compare current component with pattern. */
4961                 if (!ccs_file_matches_pattern(f, f_delimiter, p + 2,
4962                                               p_delimiter - 2))
4963                         break;
4964                 /* Proceed to next component. */
4965                 f = f_delimiter;
4966                 if (!*f)
4967                         break;
4968                 f++;
4969                 /* Continue comparison. */
4970                 if (ccs_path_matches_pattern2(f, p_delimiter + 1))
4971                         return true;
4972                 f_delimiter = strchr(f, '/');
4973         } while (f_delimiter);
4974         return false; /* Not matched. */
4975 }
4976 
4977 /**
4978  * ccs_path_matches_pattern - Check whether the given filename matches the given pattern.
4979  *
4980  * @filename: The filename to check.
4981  * @pattern:  The pattern to compare.
4982  *
4983  * Returns true if matches, false otherwise.
4984  *
4985  * The following patterns are available.
4986  *   \\     \ itself.
4987  *   \ooo   Octal representation of a byte.
4988  *   \*     Zero or more repetitions of characters other than '/'.
4989  *   \@     Zero or more repetitions of characters other than '/' or '.'.
4990  *   \?     1 byte character other than '/'.
4991  *   \$     One or more repetitions of decimal digits.
4992  *   \+     1 decimal digit.
4993  *   \X     One or more repetitions of hexadecimal digits.
4994  *   \x     1 hexadecimal digit.
4995  *   \A     One or more repetitions of alphabet characters.
4996  *   \a     1 alphabet character.
4997  *
4998  *   \-     Subtraction operator.
4999  *
5000  *   /\{dir\}/   '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
5001  *               /dir/dir/dir/ ).
5002  */
5003 static bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
5004                                      const struct ccs_path_info *pattern)
5005 {
5006         const char *f = filename->name;
5007         const char *p = pattern->name;
5008         const int len = pattern->const_len;
5009         /* If @pattern doesn't contain pattern, I can use strcmp(). */
5010         if (!pattern->is_patterned)
5011                 return !ccs_pathcmp(filename, pattern);
5012         /* Don't compare directory and non-directory. */
5013         if (filename->is_dir != pattern->is_dir)
5014                 return false;
5015         /* Compare the initial length without patterns. */
5016         if (strncmp(f, p, len))
5017                 return false;
5018         f += len;
5019         p += len;
5020         return ccs_path_matches_pattern2(f, p);
5021 }
5022 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp