mount.c revision 75093152a97ee0ec281895b4f6229ff3c481fd64
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 */ 34static 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_file_pattern(r->param.mount.dev), 59 tomoyo_file_pattern(r->param.mount.dir), type, 60 flags); 61} 62 63static bool tomoyo_check_mount_acl(const 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_acl2 - 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 */ 88static int tomoyo_mount_acl2(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_acl - Check permission for mount() operation. 183 * 184 * @r: Pointer to "struct tomoyo_request_info". 185 * @dev_name: Name of device file. 186 * @dir: Pointer to "struct path". 187 * @type: Name of filesystem type. 188 * @flags: Mount options. 189 * 190 * Returns 0 on success, negative value otherwise. 191 * 192 * Caller holds tomoyo_read_lock(). 193 */ 194static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, 195 struct path *dir, char *type, unsigned long flags) 196{ 197 int error; 198 error = -EPERM; 199 if ((flags & MS_MGC_MSK) == MS_MGC_VAL) 200 flags &= ~MS_MGC_MSK; 201 switch (flags & (MS_REMOUNT | MS_MOVE | MS_BIND)) { 202 case MS_REMOUNT: 203 case MS_MOVE: 204 case MS_BIND: 205 case 0: 206 break; 207 default: 208 printk(KERN_WARNING "ERROR: " 209 "%s%s%sare given for single mount operation.\n", 210 flags & MS_REMOUNT ? "'remount' " : "", 211 flags & MS_MOVE ? "'move' " : "", 212 flags & MS_BIND ? "'bind' " : ""); 213 return -EINVAL; 214 } 215 switch (flags & (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED)) { 216 case MS_UNBINDABLE: 217 case MS_PRIVATE: 218 case MS_SLAVE: 219 case MS_SHARED: 220 case 0: 221 break; 222 default: 223 printk(KERN_WARNING "ERROR: " 224 "%s%s%s%sare given for single mount operation.\n", 225 flags & MS_UNBINDABLE ? "'unbindable' " : "", 226 flags & MS_PRIVATE ? "'private' " : "", 227 flags & MS_SLAVE ? "'slave' " : "", 228 flags & MS_SHARED ? "'shared' " : ""); 229 return -EINVAL; 230 } 231 if (flags & MS_REMOUNT) 232 error = tomoyo_mount_acl(r, dev_name, dir, 233 TOMOYO_MOUNT_REMOUNT_KEYWORD, 234 flags & ~MS_REMOUNT); 235 else if (flags & MS_MOVE) 236 error = tomoyo_mount_acl(r, dev_name, dir, 237 TOMOYO_MOUNT_MOVE_KEYWORD, 238 flags & ~MS_MOVE); 239 else if (flags & MS_BIND) 240 error = tomoyo_mount_acl(r, dev_name, dir, 241 TOMOYO_MOUNT_BIND_KEYWORD, 242 flags & ~MS_BIND); 243 else if (flags & MS_UNBINDABLE) 244 error = tomoyo_mount_acl(r, dev_name, dir, 245 TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD, 246 flags & ~MS_UNBINDABLE); 247 else if (flags & MS_PRIVATE) 248 error = tomoyo_mount_acl(r, dev_name, dir, 249 TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD, 250 flags & ~MS_PRIVATE); 251 else if (flags & MS_SLAVE) 252 error = tomoyo_mount_acl(r, dev_name, dir, 253 TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD, 254 flags & ~MS_SLAVE); 255 else if (flags & MS_SHARED) 256 error = tomoyo_mount_acl(r, dev_name, dir, 257 TOMOYO_MOUNT_MAKE_SHARED_KEYWORD, 258 flags & ~MS_SHARED); 259 else 260 do { 261 error = tomoyo_mount_acl2(r, dev_name, dir, type, 262 flags); 263 } while (error == TOMOYO_RETRY_REQUEST); 264 if (r->mode != TOMOYO_CONFIG_ENFORCING) 265 error = 0; 266 return error; 267} 268 269/** 270 * tomoyo_mount_permission - Check permission for mount() operation. 271 * 272 * @dev_name: Name of device file. 273 * @path: Pointer to "struct path". 274 * @type: Name of filesystem type. May be NULL. 275 * @flags: Mount options. 276 * @data_page: Optional data. May be NULL. 277 * 278 * Returns 0 on success, negative value otherwise. 279 */ 280int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, 281 unsigned long flags, void *data_page) 282{ 283 struct tomoyo_request_info r; 284 int error; 285 int idx; 286 287 if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT) 288 == TOMOYO_CONFIG_DISABLED) 289 return 0; 290 if (!type) 291 type = "<NULL>"; 292 idx = tomoyo_read_lock(); 293 error = tomoyo_mount_acl(&r, dev_name, path, type, flags); 294 tomoyo_read_unlock(idx); 295 return error; 296} 297 298static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, 299 const struct tomoyo_acl_info *b) 300{ 301 const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); 302 const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); 303 return tomoyo_same_acl_head(&p1->head, &p2->head) && 304 tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && 305 tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && 306 tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && 307 tomoyo_same_number_union(&p1->flags, &p2->flags); 308} 309 310/** 311 * tomoyo_write_mount_policy - Write "struct tomoyo_mount_acl" list. 312 * 313 * @data: String to parse. 314 * @domain: Pointer to "struct tomoyo_domain_info". 315 * @is_delete: True if it is a delete request. 316 * 317 * Returns 0 on success, negative value otherwise. 318 * 319 * Caller holds tomoyo_read_lock(). 320 */ 321int tomoyo_write_mount_policy(char *data, struct tomoyo_domain_info *domain, 322 const bool is_delete) 323{ 324 struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; 325 int error = is_delete ? -ENOENT : -ENOMEM; 326 char *w[4]; 327 if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0]) 328 return -EINVAL; 329 if (!tomoyo_parse_name_union(w[0], &e.dev_name) || 330 !tomoyo_parse_name_union(w[1], &e.dir_name) || 331 !tomoyo_parse_name_union(w[2], &e.fs_type) || 332 !tomoyo_parse_number_union(w[3], &e.flags)) 333 goto out; 334 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 335 tomoyo_same_mount_acl, NULL); 336 out: 337 tomoyo_put_name_union(&e.dev_name); 338 tomoyo_put_name_union(&e.dir_name); 339 tomoyo_put_name_union(&e.fs_type); 340 tomoyo_put_number_union(&e.flags); 341 return error; 342} 343