1 /* 2 * security/tomoyo/mount.c 3 * 4 * Copyright (C) 2005-2010 NTT DATA CORPORATION 5 */ 6 7 #include <linux/slab.h> 8 #include "common.h" 9 10 /* Keywords for mount restrictions. */ 11 12 /* Allow to call 'mount --bind /source_dir /dest_dir' */ 13 #define TOMOYO_MOUNT_BIND_KEYWORD "--bind" 14 /* Allow to call 'mount --move /old_dir /new_dir ' */ 15 #define TOMOYO_MOUNT_MOVE_KEYWORD "--move" 16 /* Allow to call 'mount -o remount /dir ' */ 17 #define TOMOYO_MOUNT_REMOUNT_KEYWORD "--remount" 18 /* Allow to call 'mount --make-unbindable /dir' */ 19 #define TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD "--make-unbindable" 20 /* Allow to call 'mount --make-private /dir' */ 21 #define TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD "--make-private" 22 /* Allow to call 'mount --make-slave /dir' */ 23 #define TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD "--make-slave" 24 /* Allow to call 'mount --make-shared /dir' */ 25 #define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD "--make-shared" 26 27 /** 28 * tomoyo_audit_mount_log - Audit mount log. 29 * 30 * @r: Pointer to "struct tomoyo_request_info". 31 * 32 * Returns 0 on success, negative value otherwise. 33 */ 34 static int tomoyo_audit_mount_log(struct tomoyo_request_info *r) 35 { 36 const char *dev = r->param.mount.dev->name; 37 const char *dir = r->param.mount.dir->name; 38 const char *type = r->param.mount.type->name; 39 const unsigned long flags = r->param.mount.flags; 40 if (r->granted) 41 return 0; 42 if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD)) 43 tomoyo_warn_log(r, "mount -o remount %s 0x%lX", dir, flags); 44 else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD) 45 || !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD)) 46 tomoyo_warn_log(r, "mount %s %s %s 0x%lX", type, dev, dir, 47 flags); 48 else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) || 49 !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) || 50 !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) || 51 !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD)) 52 tomoyo_warn_log(r, "mount %s %s 0x%lX", type, dir, flags); 53 else 54 tomoyo_warn_log(r, "mount -t %s %s %s 0x%lX", type, dev, dir, 55 flags); 56 return tomoyo_supervisor(r, 57 TOMOYO_KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n", 58 tomoyo_pattern(r->param.mount.dev), 59 tomoyo_pattern(r->param.mount.dir), type, 60 flags); 61 } 62 63 static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r, 64 const struct tomoyo_acl_info *ptr) 65 { 66 const struct tomoyo_mount_acl *acl = 67 container_of(ptr, typeof(*acl), head); 68 return tomoyo_compare_number_union(r->param.mount.flags, &acl->flags) && 69 tomoyo_compare_name_union(r->param.mount.type, &acl->fs_type) && 70 tomoyo_compare_name_union(r->param.mount.dir, &acl->dir_name) && 71 (!r->param.mount.need_dev || 72 tomoyo_compare_name_union(r->param.mount.dev, &acl->dev_name)); 73 } 74 75 /** 76 * tomoyo_mount_acl - Check permission for mount() operation. 77 * 78 * @r: Pointer to "struct tomoyo_request_info". 79 * @dev_name: Name of device file. 80 * @dir: Pointer to "struct path". 81 * @type: Name of filesystem type. 82 * @flags: Mount options. 83 * 84 * Returns 0 on success, negative value otherwise. 85 * 86 * Caller holds tomoyo_read_lock(). 87 */ 88 static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, 89 struct path *dir, char *type, unsigned long flags) 90 { 91 struct path path; 92 struct file_system_type *fstype = NULL; 93 const char *requested_type = NULL; 94 const char *requested_dir_name = NULL; 95 const char *requested_dev_name = NULL; 96 struct tomoyo_path_info rtype; 97 struct tomoyo_path_info rdev; 98 struct tomoyo_path_info rdir; 99 int need_dev = 0; 100 int error = -ENOMEM; 101 102 /* Get fstype. */ 103 requested_type = tomoyo_encode(type); 104 if (!requested_type) 105 goto out; 106 rtype.name = requested_type; 107 tomoyo_fill_path_info(&rtype); 108 109 /* Get mount point. */ 110 requested_dir_name = tomoyo_realpath_from_path(dir); 111 if (!requested_dir_name) { 112 error = -ENOMEM; 113 goto out; 114 } 115 rdir.name = requested_dir_name; 116 tomoyo_fill_path_info(&rdir); 117 118 /* Compare fs name. */ 119 if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD)) { 120 /* dev_name is ignored. */ 121 } else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) || 122 !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) || 123 !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) || 124 !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD)) { 125 /* dev_name is ignored. */ 126 } else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD) || 127 !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD)) { 128 need_dev = -1; /* dev_name is a directory */ 129 } else { 130 fstype = get_fs_type(type); 131 if (!fstype) { 132 error = -ENODEV; 133 goto out; 134 } 135 if (fstype->fs_flags & FS_REQUIRES_DEV) 136 /* dev_name is a block device file. */ 137 need_dev = 1; 138 } 139 if (need_dev) { 140 /* Get mount point or device file. */ 141 if (kern_path(dev_name, LOOKUP_FOLLOW, &path)) { 142 error = -ENOENT; 143 goto out; 144 } 145 requested_dev_name = tomoyo_realpath_from_path(&path); 146 if (!requested_dev_name) { 147 error = -ENOENT; 148 goto out; 149 } 150 } else { 151 /* Map dev_name to "<NULL>" if no dev_name given. */ 152 if (!dev_name) 153 dev_name = "<NULL>"; 154 requested_dev_name = tomoyo_encode(dev_name); 155 if (!requested_dev_name) { 156 error = -ENOMEM; 157 goto out; 158 } 159 } 160 rdev.name = requested_dev_name; 161 tomoyo_fill_path_info(&rdev); 162 r->param_type = TOMOYO_TYPE_MOUNT_ACL; 163 r->param.mount.need_dev = need_dev; 164 r->param.mount.dev = &rdev; 165 r->param.mount.dir = &rdir; 166 r->param.mount.type = &rtype; 167 r->param.mount.flags = flags; 168 do { 169 tomoyo_check_acl(r, tomoyo_check_mount_acl); 170 error = tomoyo_audit_mount_log(r); 171 } while (error == TOMOYO_RETRY_REQUEST); 172 out: 173 kfree(requested_dev_name); 174 kfree(requested_dir_name); 175 if (fstype) 176 put_filesystem(fstype); 177 kfree(requested_type); 178 return error; 179 } 180 181 /** 182 * tomoyo_mount_permission - Check permission for mount() operation. 183 * 184 * @dev_name: Name of device file. 185 * @path: Pointer to "struct path". 186 * @type: Name of filesystem type. May be NULL. 187 * @flags: Mount options. 188 * @data_page: Optional data. May be NULL. 189 * 190 * Returns 0 on success, negative value otherwise. 191 */ 192 int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, 193 unsigned long flags, void *data_page) 194 { 195 struct tomoyo_request_info r; 196 int error; 197 int idx; 198 199 if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT) 200 == TOMOYO_CONFIG_DISABLED) 201 return 0; 202 if ((flags & MS_MGC_MSK) == MS_MGC_VAL) 203 flags &= ~MS_MGC_MSK; 204 if (flags & MS_REMOUNT) { 205 type = TOMOYO_MOUNT_REMOUNT_KEYWORD; 206 flags &= ~MS_REMOUNT; 207 } 208 if (flags & MS_MOVE) { 209 type = TOMOYO_MOUNT_MOVE_KEYWORD; 210 flags &= ~MS_MOVE; 211 } 212 if (flags & MS_BIND) { 213 type = TOMOYO_MOUNT_BIND_KEYWORD; 214 flags &= ~MS_BIND; 215 } 216 if (flags & MS_UNBINDABLE) { 217 type = TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD; 218 flags &= ~MS_UNBINDABLE; 219 } 220 if (flags & MS_PRIVATE) { 221 type = TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD; 222 flags &= ~MS_PRIVATE; 223 } 224 if (flags & MS_SLAVE) { 225 type = TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD; 226 flags &= ~MS_SLAVE; 227 } 228 if (flags & MS_SHARED) { 229 type = TOMOYO_MOUNT_MAKE_SHARED_KEYWORD; 230 flags &= ~MS_SHARED; 231 } 232 if (!type) 233 type = "<NULL>"; 234 idx = tomoyo_read_lock(); 235 error = tomoyo_mount_acl(&r, dev_name, path, type, flags); 236 tomoyo_read_unlock(idx); 237 return error; 238 } 239 240 static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, 241 const struct tomoyo_acl_info *b) 242 { 243 const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); 244 const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); 245 return tomoyo_same_acl_head(&p1->head, &p2->head) && 246 tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && 247 tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && 248 tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && 249 tomoyo_same_number_union(&p1->flags, &p2->flags); 250 } 251 252 /** 253 * tomoyo_write_mount - Write "struct tomoyo_mount_acl" list. 254 * 255 * @data: String to parse. 256 * @domain: Pointer to "struct tomoyo_domain_info". 257 * @is_delete: True if it is a delete request. 258 * 259 * Returns 0 on success, negative value otherwise. 260 * 261 * Caller holds tomoyo_read_lock(). 262 */ 263 int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain, 264 const bool is_delete) 265 { 266 struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; 267 int error = is_delete ? -ENOENT : -ENOMEM; 268 char *w[4]; 269 if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0]) 270 return -EINVAL; 271 if (!tomoyo_parse_name_union(w[0], &e.dev_name) || 272 !tomoyo_parse_name_union(w[1], &e.dir_name) || 273 !tomoyo_parse_name_union(w[2], &e.fs_type) || 274 !tomoyo_parse_number_union(w[3], &e.flags)) 275 goto out; 276 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 277 tomoyo_same_mount_acl, NULL); 278 out: 279 tomoyo_put_name_union(&e.dev_name); 280 tomoyo_put_name_union(&e.dir_name); 281 tomoyo_put_name_union(&e.fs_type); 282 tomoyo_put_number_union(&e.flags); 283 return error; 284 } 285