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 (!dev_name || kern_path(dev_name, LOOKUP_FOLLOW, &path)) { 142 error = -ENOENT; 143 goto out; 144 } 145 requested_dev_name = tomoyo_realpath_from_path(&path); 146 path_put(&path); 147 if (!requested_dev_name) { 148 error = -ENOENT; 149 goto out; 150 } 151 } else { 152 /* Map dev_name to "<NULL>" if no dev_name given. */ 153 if (!dev_name) 154 dev_name = "<NULL>"; 155 requested_dev_name = tomoyo_encode(dev_name); 156 if (!requested_dev_name) { 157 error = -ENOMEM; 158 goto out; 159 } 160 } 161 rdev.name = requested_dev_name; 162 tomoyo_fill_path_info(&rdev); 163 r->param_type = TOMOYO_TYPE_MOUNT_ACL; 164 r->param.mount.need_dev = need_dev; 165 r->param.mount.dev = &rdev; 166 r->param.mount.dir = &rdir; 167 r->param.mount.type = &rtype; 168 r->param.mount.flags = flags; 169 do { 170 tomoyo_check_acl(r, tomoyo_check_mount_acl); 171 error = tomoyo_audit_mount_log(r); 172 } while (error == TOMOYO_RETRY_REQUEST); 173 out: 174 kfree(requested_dev_name); 175 kfree(requested_dir_name); 176 if (fstype) 177 put_filesystem(fstype); 178 kfree(requested_type); 179 return error; 180 } 181 182 /** 183 * tomoyo_mount_permission - Check permission for mount() operation. 184 * 185 * @dev_name: Name of device file. 186 * @path: Pointer to "struct path". 187 * @type: Name of filesystem type. May be NULL. 188 * @flags: Mount options. 189 * @data_page: Optional data. May be NULL. 190 * 191 * Returns 0 on success, negative value otherwise. 192 */ 193 int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, 194 unsigned long flags, void *data_page) 195 { 196 struct tomoyo_request_info r; 197 int error; 198 int idx; 199 200 if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT) 201 == TOMOYO_CONFIG_DISABLED) 202 return 0; 203 if ((flags & MS_MGC_MSK) == MS_MGC_VAL) 204 flags &= ~MS_MGC_MSK; 205 if (flags & MS_REMOUNT) { 206 type = TOMOYO_MOUNT_REMOUNT_KEYWORD; 207 flags &= ~MS_REMOUNT; 208 } 209 if (flags & MS_MOVE) { 210 type = TOMOYO_MOUNT_MOVE_KEYWORD; 211 flags &= ~MS_MOVE; 212 } 213 if (flags & MS_BIND) { 214 type = TOMOYO_MOUNT_BIND_KEYWORD; 215 flags &= ~MS_BIND; 216 } 217 if (flags & MS_UNBINDABLE) { 218 type = TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD; 219 flags &= ~MS_UNBINDABLE; 220 } 221 if (flags & MS_PRIVATE) { 222 type = TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD; 223 flags &= ~MS_PRIVATE; 224 } 225 if (flags & MS_SLAVE) { 226 type = TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD; 227 flags &= ~MS_SLAVE; 228 } 229 if (flags & MS_SHARED) { 230 type = TOMOYO_MOUNT_MAKE_SHARED_KEYWORD; 231 flags &= ~MS_SHARED; 232 } 233 if (!type) 234 type = "<NULL>"; 235 idx = tomoyo_read_lock(); 236 error = tomoyo_mount_acl(&r, dev_name, path, type, flags); 237 tomoyo_read_unlock(idx); 238 return error; 239 } 240 241 static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, 242 const struct tomoyo_acl_info *b) 243 { 244 const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); 245 const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); 246 return tomoyo_same_acl_head(&p1->head, &p2->head) && 247 tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && 248 tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && 249 tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && 250 tomoyo_same_number_union(&p1->flags, &p2->flags); 251 } 252 253 /** 254 * tomoyo_write_mount - Write "struct tomoyo_mount_acl" list. 255 * 256 * @data: String to parse. 257 * @domain: Pointer to "struct tomoyo_domain_info". 258 * @is_delete: True if it is a delete request. 259 * 260 * Returns 0 on success, negative value otherwise. 261 * 262 * Caller holds tomoyo_read_lock(). 263 */ 264 int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain, 265 const bool is_delete) 266 { 267 struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; 268 int error = is_delete ? -ENOENT : -ENOMEM; 269 char *w[4]; 270 if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0]) 271 return -EINVAL; 272 if (!tomoyo_parse_name_union(w[0], &e.dev_name) || 273 !tomoyo_parse_name_union(w[1], &e.dir_name) || 274 !tomoyo_parse_name_union(w[2], &e.fs_type) || 275 !tomoyo_parse_number_union(w[3], &e.flags)) 276 goto out; 277 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 278 tomoyo_same_mount_acl, NULL); 279 out: 280 tomoyo_put_name_union(&e.dev_name); 281 tomoyo_put_name_union(&e.dir_name); 282 tomoyo_put_name_union(&e.fs_type); 283 tomoyo_put_number_union(&e.flags); 284 return error; 285 } 286