diff options
author | Tyler Hicks <tyhicks@linux.vnet.ibm.com> | 2009-03-20 03:23:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-22 14:20:43 -0400 |
commit | 2aac0cf88681bfa092f731553bc7fbd23516be73 (patch) | |
tree | b723cbe9c67b0cafa9081690d03b4ecec038d9f6 /fs/ecryptfs | |
parent | 8faece5f906725c10e7a1f6caf84452abadbdc7b (diff) |
eCryptfs: NULL crypt_stat dereference during lookup
If ecryptfs_encrypted_view or ecryptfs_xattr_metadata were being
specified as mount options, a NULL pointer dereference of crypt_stat
was possible during lookup.
This patch moves the crypt_stat assignment into
ecryptfs_lookup_and_interpose_lower(), ensuring that crypt_stat
will not be NULL before we attempt to dereference it.
Thanks to Dan Carpenter and his static analysis tool, smatch, for
finding this bug.
Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com>
Acked-by: Dustin Kirkland <kirkland@canonical.com>
Cc: Dan Carpenter <error27@gmail.com>
Cc: Serge Hallyn <serue@us.ibm.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ecryptfs')
-rw-r--r-- | fs/ecryptfs/crypto.c | 10 | ||||
-rw-r--r-- | fs/ecryptfs/ecryptfs_kernel.h | 1 | ||||
-rw-r--r-- | fs/ecryptfs/inode.c | 32 |
3 files changed, 18 insertions, 25 deletions
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 75bee99de0f6..8b65f289ee00 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c | |||
@@ -2221,17 +2221,19 @@ int ecryptfs_decode_and_decrypt_filename(char **plaintext_name, | |||
2221 | struct dentry *ecryptfs_dir_dentry, | 2221 | struct dentry *ecryptfs_dir_dentry, |
2222 | const char *name, size_t name_size) | 2222 | const char *name, size_t name_size) |
2223 | { | 2223 | { |
2224 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat = | ||
2225 | &ecryptfs_superblock_to_private( | ||
2226 | ecryptfs_dir_dentry->d_sb)->mount_crypt_stat; | ||
2224 | char *decoded_name; | 2227 | char *decoded_name; |
2225 | size_t decoded_name_size; | 2228 | size_t decoded_name_size; |
2226 | size_t packet_size; | 2229 | size_t packet_size; |
2227 | int rc = 0; | 2230 | int rc = 0; |
2228 | 2231 | ||
2229 | if ((name_size > ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) | 2232 | if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) |
2233 | && !(mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) | ||
2234 | && (name_size > ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) | ||
2230 | && (strncmp(name, ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX, | 2235 | && (strncmp(name, ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX, |
2231 | ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) == 0)) { | 2236 | ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) == 0)) { |
2232 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat = | ||
2233 | &ecryptfs_superblock_to_private( | ||
2234 | ecryptfs_dir_dentry->d_sb)->mount_crypt_stat; | ||
2235 | const char *orig_name = name; | 2237 | const char *orig_name = name; |
2236 | size_t orig_name_size = name_size; | 2238 | size_t orig_name_size = name_size; |
2237 | 2239 | ||
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index eb2267eca1fe..ac749d4d644f 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h | |||
@@ -620,7 +620,6 @@ int ecryptfs_interpose(struct dentry *hidden_dentry, | |||
620 | u32 flags); | 620 | u32 flags); |
621 | int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, | 621 | int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, |
622 | struct dentry *lower_dentry, | 622 | struct dentry *lower_dentry, |
623 | struct ecryptfs_crypt_stat *crypt_stat, | ||
624 | struct inode *ecryptfs_dir_inode, | 623 | struct inode *ecryptfs_dir_inode, |
625 | struct nameidata *ecryptfs_nd); | 624 | struct nameidata *ecryptfs_nd); |
626 | int ecryptfs_decode_and_decrypt_filename(char **decrypted_name, | 625 | int ecryptfs_decode_and_decrypt_filename(char **decrypted_name, |
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 5697899a168d..55b3145b8072 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
@@ -246,7 +246,6 @@ out: | |||
246 | */ | 246 | */ |
247 | int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, | 247 | int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, |
248 | struct dentry *lower_dentry, | 248 | struct dentry *lower_dentry, |
249 | struct ecryptfs_crypt_stat *crypt_stat, | ||
250 | struct inode *ecryptfs_dir_inode, | 249 | struct inode *ecryptfs_dir_inode, |
251 | struct nameidata *ecryptfs_nd) | 250 | struct nameidata *ecryptfs_nd) |
252 | { | 251 | { |
@@ -254,6 +253,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, | |||
254 | struct vfsmount *lower_mnt; | 253 | struct vfsmount *lower_mnt; |
255 | struct inode *lower_inode; | 254 | struct inode *lower_inode; |
256 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat; | 255 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat; |
256 | struct ecryptfs_crypt_stat *crypt_stat; | ||
257 | char *page_virt = NULL; | 257 | char *page_virt = NULL; |
258 | u64 file_size; | 258 | u64 file_size; |
259 | int rc = 0; | 259 | int rc = 0; |
@@ -314,6 +314,11 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, | |||
314 | goto out_free_kmem; | 314 | goto out_free_kmem; |
315 | } | 315 | } |
316 | } | 316 | } |
317 | crypt_stat = &ecryptfs_inode_to_private( | ||
318 | ecryptfs_dentry->d_inode)->crypt_stat; | ||
319 | /* TODO: lock for crypt_stat comparison */ | ||
320 | if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) | ||
321 | ecryptfs_set_default_sizes(crypt_stat); | ||
317 | rc = ecryptfs_read_and_validate_header_region(page_virt, | 322 | rc = ecryptfs_read_and_validate_header_region(page_virt, |
318 | ecryptfs_dentry->d_inode); | 323 | ecryptfs_dentry->d_inode); |
319 | if (rc) { | 324 | if (rc) { |
@@ -362,9 +367,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, | |||
362 | { | 367 | { |
363 | char *encrypted_and_encoded_name = NULL; | 368 | char *encrypted_and_encoded_name = NULL; |
364 | size_t encrypted_and_encoded_name_size; | 369 | size_t encrypted_and_encoded_name_size; |
365 | struct ecryptfs_crypt_stat *crypt_stat = NULL; | ||
366 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; | 370 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; |
367 | struct ecryptfs_inode_info *inode_info; | ||
368 | struct dentry *lower_dir_dentry, *lower_dentry; | 371 | struct dentry *lower_dir_dentry, *lower_dentry; |
369 | int rc = 0; | 372 | int rc = 0; |
370 | 373 | ||
@@ -388,26 +391,15 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, | |||
388 | } | 391 | } |
389 | if (lower_dentry->d_inode) | 392 | if (lower_dentry->d_inode) |
390 | goto lookup_and_interpose; | 393 | goto lookup_and_interpose; |
391 | inode_info = ecryptfs_inode_to_private(ecryptfs_dentry->d_inode); | 394 | mount_crypt_stat = &ecryptfs_superblock_to_private( |
392 | if (inode_info) { | 395 | ecryptfs_dentry->d_sb)->mount_crypt_stat; |
393 | crypt_stat = &inode_info->crypt_stat; | 396 | if (!(mount_crypt_stat |
394 | /* TODO: lock for crypt_stat comparison */ | 397 | && (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES))) |
395 | if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) | ||
396 | ecryptfs_set_default_sizes(crypt_stat); | ||
397 | } | ||
398 | if (crypt_stat) | ||
399 | mount_crypt_stat = crypt_stat->mount_crypt_stat; | ||
400 | else | ||
401 | mount_crypt_stat = &ecryptfs_superblock_to_private( | ||
402 | ecryptfs_dentry->d_sb)->mount_crypt_stat; | ||
403 | if (!(crypt_stat && (crypt_stat->flags & ECRYPTFS_ENCRYPT_FILENAMES)) | ||
404 | && !(mount_crypt_stat && (mount_crypt_stat->flags | ||
405 | & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES))) | ||
406 | goto lookup_and_interpose; | 398 | goto lookup_and_interpose; |
407 | dput(lower_dentry); | 399 | dput(lower_dentry); |
408 | rc = ecryptfs_encrypt_and_encode_filename( | 400 | rc = ecryptfs_encrypt_and_encode_filename( |
409 | &encrypted_and_encoded_name, &encrypted_and_encoded_name_size, | 401 | &encrypted_and_encoded_name, &encrypted_and_encoded_name_size, |
410 | crypt_stat, mount_crypt_stat, ecryptfs_dentry->d_name.name, | 402 | NULL, mount_crypt_stat, ecryptfs_dentry->d_name.name, |
411 | ecryptfs_dentry->d_name.len); | 403 | ecryptfs_dentry->d_name.len); |
412 | if (rc) { | 404 | if (rc) { |
413 | printk(KERN_ERR "%s: Error attempting to encrypt and encode " | 405 | printk(KERN_ERR "%s: Error attempting to encrypt and encode " |
@@ -426,7 +418,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, | |||
426 | } | 418 | } |
427 | lookup_and_interpose: | 419 | lookup_and_interpose: |
428 | rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry, | 420 | rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry, |
429 | crypt_stat, ecryptfs_dir_inode, | 421 | ecryptfs_dir_inode, |
430 | ecryptfs_nd); | 422 | ecryptfs_nd); |
431 | goto out; | 423 | goto out; |
432 | out_d_drop: | 424 | out_d_drop: |