diff options
author | John Johansen <john.johansen@canonical.com> | 2011-07-22 11:14:15 -0400 |
---|---|---|
committer | Tyler Hicks <tyhicks@linux.vnet.ibm.com> | 2011-08-10 00:29:01 -0400 |
commit | 764355487ea220fdc2faf128d577d7f679b91f97 (patch) | |
tree | f265a3f71bd57838bf3d00c26ed385f8978ef139 /fs/ecryptfs/main.c | |
parent | 99b373ff2d1246f64b97a3d449a2fd6018d504e6 (diff) |
Ecryptfs: Add mount option to check uid of device being mounted = expect uid
Close a TOCTOU race for mounts done via ecryptfs-mount-private. The mount
source (device) can be raced when the ownership test is done in userspace.
Provide Ecryptfs a means to force the uid check at mount time.
Signed-off-by: John Johansen <john.johansen@canonical.com>
Cc: <stable@kernel.org>
Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com>
Diffstat (limited to 'fs/ecryptfs/main.c')
-rw-r--r-- | fs/ecryptfs/main.c | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 9f1bb747d77d..b4a6befb1216 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c | |||
@@ -175,6 +175,7 @@ enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, | |||
175 | ecryptfs_opt_encrypted_view, ecryptfs_opt_fnek_sig, | 175 | ecryptfs_opt_encrypted_view, ecryptfs_opt_fnek_sig, |
176 | ecryptfs_opt_fn_cipher, ecryptfs_opt_fn_cipher_key_bytes, | 176 | ecryptfs_opt_fn_cipher, ecryptfs_opt_fn_cipher_key_bytes, |
177 | ecryptfs_opt_unlink_sigs, ecryptfs_opt_mount_auth_tok_only, | 177 | ecryptfs_opt_unlink_sigs, ecryptfs_opt_mount_auth_tok_only, |
178 | ecryptfs_opt_check_dev_ruid, | ||
178 | ecryptfs_opt_err }; | 179 | ecryptfs_opt_err }; |
179 | 180 | ||
180 | static const match_table_t tokens = { | 181 | static const match_table_t tokens = { |
@@ -191,6 +192,7 @@ static const match_table_t tokens = { | |||
191 | {ecryptfs_opt_fn_cipher_key_bytes, "ecryptfs_fn_key_bytes=%u"}, | 192 | {ecryptfs_opt_fn_cipher_key_bytes, "ecryptfs_fn_key_bytes=%u"}, |
192 | {ecryptfs_opt_unlink_sigs, "ecryptfs_unlink_sigs"}, | 193 | {ecryptfs_opt_unlink_sigs, "ecryptfs_unlink_sigs"}, |
193 | {ecryptfs_opt_mount_auth_tok_only, "ecryptfs_mount_auth_tok_only"}, | 194 | {ecryptfs_opt_mount_auth_tok_only, "ecryptfs_mount_auth_tok_only"}, |
195 | {ecryptfs_opt_check_dev_ruid, "ecryptfs_check_dev_ruid"}, | ||
194 | {ecryptfs_opt_err, NULL} | 196 | {ecryptfs_opt_err, NULL} |
195 | }; | 197 | }; |
196 | 198 | ||
@@ -236,6 +238,7 @@ static void ecryptfs_init_mount_crypt_stat( | |||
236 | * ecryptfs_parse_options | 238 | * ecryptfs_parse_options |
237 | * @sb: The ecryptfs super block | 239 | * @sb: The ecryptfs super block |
238 | * @options: The options passed to the kernel | 240 | * @options: The options passed to the kernel |
241 | * @check_ruid: set to 1 if device uid should be checked against the ruid | ||
239 | * | 242 | * |
240 | * Parse mount options: | 243 | * Parse mount options: |
241 | * debug=N - ecryptfs_verbosity level for debug output | 244 | * debug=N - ecryptfs_verbosity level for debug output |
@@ -251,7 +254,8 @@ static void ecryptfs_init_mount_crypt_stat( | |||
251 | * | 254 | * |
252 | * Returns zero on success; non-zero on error | 255 | * Returns zero on success; non-zero on error |
253 | */ | 256 | */ |
254 | static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options) | 257 | static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, |
258 | uid_t *check_ruid) | ||
255 | { | 259 | { |
256 | char *p; | 260 | char *p; |
257 | int rc = 0; | 261 | int rc = 0; |
@@ -276,6 +280,8 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options) | |||
276 | char *cipher_key_bytes_src; | 280 | char *cipher_key_bytes_src; |
277 | char *fn_cipher_key_bytes_src; | 281 | char *fn_cipher_key_bytes_src; |
278 | 282 | ||
283 | *check_ruid = 0; | ||
284 | |||
279 | if (!options) { | 285 | if (!options) { |
280 | rc = -EINVAL; | 286 | rc = -EINVAL; |
281 | goto out; | 287 | goto out; |
@@ -380,6 +386,9 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options) | |||
380 | mount_crypt_stat->flags |= | 386 | mount_crypt_stat->flags |= |
381 | ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY; | 387 | ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY; |
382 | break; | 388 | break; |
389 | case ecryptfs_opt_check_dev_ruid: | ||
390 | *check_ruid = 1; | ||
391 | break; | ||
383 | case ecryptfs_opt_err: | 392 | case ecryptfs_opt_err: |
384 | default: | 393 | default: |
385 | printk(KERN_WARNING | 394 | printk(KERN_WARNING |
@@ -475,6 +484,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags | |||
475 | const char *err = "Getting sb failed"; | 484 | const char *err = "Getting sb failed"; |
476 | struct inode *inode; | 485 | struct inode *inode; |
477 | struct path path; | 486 | struct path path; |
487 | uid_t check_ruid; | ||
478 | int rc; | 488 | int rc; |
479 | 489 | ||
480 | sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL); | 490 | sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL); |
@@ -483,7 +493,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags | |||
483 | goto out; | 493 | goto out; |
484 | } | 494 | } |
485 | 495 | ||
486 | rc = ecryptfs_parse_options(sbi, raw_data); | 496 | rc = ecryptfs_parse_options(sbi, raw_data, &check_ruid); |
487 | if (rc) { | 497 | if (rc) { |
488 | err = "Error parsing options"; | 498 | err = "Error parsing options"; |
489 | goto out; | 499 | goto out; |
@@ -521,6 +531,15 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags | |||
521 | "known incompatibilities\n"); | 531 | "known incompatibilities\n"); |
522 | goto out_free; | 532 | goto out_free; |
523 | } | 533 | } |
534 | |||
535 | if (check_ruid && path.dentry->d_inode->i_uid != current_uid()) { | ||
536 | rc = -EPERM; | ||
537 | printk(KERN_ERR "Mount of device (uid: %d) not owned by " | ||
538 | "requested user (uid: %d)\n", | ||
539 | path.dentry->d_inode->i_uid, current_uid()); | ||
540 | goto out_free; | ||
541 | } | ||
542 | |||
524 | ecryptfs_set_superblock_lower(s, path.dentry->d_sb); | 543 | ecryptfs_set_superblock_lower(s, path.dentry->d_sb); |
525 | s->s_maxbytes = path.dentry->d_sb->s_maxbytes; | 544 | s->s_maxbytes = path.dentry->d_sb->s_maxbytes; |
526 | s->s_blocksize = path.dentry->d_sb->s_blocksize; | 545 | s->s_blocksize = path.dentry->d_sb->s_blocksize; |