Currently, applications that wish to get or set security descriptors have to explicitly open the volume's security descriptor index ("$Secure") using ntfs_open_secure(). Applications are also responsible for closing the index when done with it. However, the cleanup function for doing so, ntfs_close_secure(), cannot be called easily by all applications because it requires a SECURITY_CONTEXT argument, not simply the ntfs_volume. Some applications therefore have to close the inode and its index contexts manually in order to clean up properly.
This proposal updates libntfs-3g to open $Secure unconditonally as part of ntfs_mount(), so that applications do not have to worry about it. ntfs_close_secure() is updated to take in a ntfs_volume for internal use, and ntfs_destroy_security_context() is now the function to call to free memory associated with a SECURITY_CONTEXT rather than a ntfs_volume. Some memory leaks in error paths of ntfs_open_secure() are also fixed. [v2: call ntfs_close_secure() earlier, check for error, and other cleanups] Signed-off-by: Eric Biggers <ebigge...@gmail.com> --- include/ntfs-3g/security.h | 4 +- libntfs-3g/security.c | 97 +++++++++++++++++++++++++++++----------------- libntfs-3g/volume.c | 9 +++++ src/lowntfs-3g.c | 6 +-- src/ntfs-3g.c | 6 +-- 5 files changed, 75 insertions(+), 47 deletions(-) diff --git a/include/ntfs-3g/security.h b/include/ntfs-3g/security.h index b5c6375..c76ce9f 100644 --- a/include/ntfs-3g/security.h +++ b/include/ntfs-3g/security.h @@ -256,7 +256,9 @@ int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx, ntfs_inode *dir_ni, BOOL fordir); int ntfs_open_secure(ntfs_volume *vol); -void ntfs_close_secure(struct SECURITY_CONTEXT *scx); +int ntfs_close_secure(ntfs_volume *vol); + +void ntfs_destroy_security_context(struct SECURITY_CONTEXT *scx); #if POSIXACLS diff --git a/libntfs-3g/security.c b/libntfs-3g/security.c index ef036af..b87745a 100644 --- a/libntfs-3g/security.c +++ b/libntfs-3g/security.c @@ -4466,55 +4466,81 @@ int ntfs_set_ntfs_attrib(ntfs_inode *ni, /* - * Open $Secure once for all - * returns zero if it succeeds - * non-zero if it fails. This is not an error (on NTFS v1.x) + * Open the volume's security descriptor index ($Secure) + * + * returns 0 if it succeeds + * -1 with errno set if it fails and the volume is NTFS v3.0+ */ - - int ntfs_open_secure(ntfs_volume *vol) { ntfs_inode *ni; - int res; + ntfs_index_context *sii; + ntfs_index_context *sdh; - res = -1; - vol->secure_ni = (ntfs_inode*)NULL; - vol->secure_xsii = (ntfs_index_context*)NULL; - vol->secure_xsdh = (ntfs_index_context*)NULL; - if (vol->major_ver >= 3) { - /* make sure this is a genuine $Secure inode 9 */ - ni = ntfs_pathname_to_inode(vol, NULL, "$Secure"); - if (ni && (ni->mft_no == 9)) { - vol->secure_reentry = 0; - vol->secure_xsii = ntfs_index_ctx_get(ni, - sii_stream, 4); - vol->secure_xsdh = ntfs_index_ctx_get(ni, - sdh_stream, 4); - if (ni && vol->secure_xsii && vol->secure_xsdh) { - vol->secure_ni = ni; - res = 0; - } - } + if (vol->secure_ni) /* Already open? */ + return 0; + + ni = ntfs_pathname_to_inode(vol, NULL, "$Secure"); + if (!ni) + goto err; + + if (ni->mft_no != FILE_Secure) { + ntfs_log_error("$Secure does not have expected inode number!"); + errno = EINVAL; + goto err_close_ni; } - return (res); + + /* Allocate the needed index contexts. */ + sii = ntfs_index_ctx_get(ni, sii_stream, 4); + if (!sii) + goto err_close_ni; + + sdh = ntfs_index_ctx_get(ni, sdh_stream, 4); + if (!sdh) + goto err_close_sii; + + vol->secure_xsdh = sdh; + vol->secure_xsii = sii; + vol->secure_ni = ni; + return 0; + +err_close_sii: + ntfs_index_ctx_put(sii); +err_close_ni: + ntfs_inode_close(ni); +err: + /* Failing on NTFS pre-v3.0 is expected. */ + if (vol->major_ver < 3) + return 0; + ntfs_log_perror("Failed to open $Secure"); + return -1; } /* - * Final cleaning - * Allocated memory is freed to facilitate the detection of memory leaks + * Close the volume's security descriptor index ($Secure) + * + * returns 0 if it succeeds + * -1 with errno set if it fails */ - -void ntfs_close_secure(struct SECURITY_CONTEXT *scx) +int ntfs_close_secure(ntfs_volume *vol) { - ntfs_volume *vol; + int res = 0; - vol = scx->vol; if (vol->secure_ni) { - ntfs_index_ctx_put(vol->secure_xsii); ntfs_index_ctx_put(vol->secure_xsdh); - ntfs_inode_close(vol->secure_ni); - + ntfs_index_ctx_put(vol->secure_xsii); + res = ntfs_inode_close(vol->secure_ni); + vol->secure_ni = NULL; } + return res; +} + +/* + * Destroy a security context + * Allocated memory is freed to facilitate the detection of memory leaks + */ +void ntfs_destroy_security_context(struct SECURITY_CONTEXT *scx) +{ ntfs_free_mapping(scx->mapping); free_caches(scx); } @@ -5333,7 +5359,6 @@ struct SECURITY_API *ntfs_initialize_file_security(const char *device, scx->vol->secure_flags = 0; /* accept no mapping and no $Secure */ ntfs_build_mapping(scx,(const char*)NULL,TRUE); - ntfs_open_secure(vol); } else { if (scapi) free(scapi); @@ -5365,7 +5390,7 @@ BOOL ntfs_leave_file_security(struct SECURITY_API *scapi) ok = FALSE; if (scapi && (scapi->magic == MAGIC_API) && scapi->security.vol) { vol = scapi->security.vol; - ntfs_close_secure(&scapi->security); + ntfs_destroy_security_context(&scapi->security); free(scapi); if (!ntfs_umount(vol, 0)) ok = TRUE; diff --git a/libntfs-3g/volume.c b/libntfs-3g/volume.c index 4861d2f..68b8ee1 100644 --- a/libntfs-3g/volume.c +++ b/libntfs-3g/volume.c @@ -74,6 +74,7 @@ #include "cache.h" #include "realpath.h" #include "misc.h" +#include "security.h" const char *ntfs_home = "News, support and information: http://tuxera.com\n"; @@ -172,6 +173,9 @@ static int __ntfs_volume_release(ntfs_volume *v) { int err = 0; + if (ntfs_close_secure(v)) + ntfs_error_set(&err); + if (ntfs_inode_free(&v->vol_ni)) ntfs_error_set(&err); /* @@ -1234,6 +1238,11 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) ntfs_log_perror("Failed to close $AttrDef"); goto error_exit; } + + /* Open $Secure. */ + if (ntfs_open_secure(vol)) + goto error_exit; + /* * Check for dirty logfile and hibernated Windows. * We care only about read-write mounts. diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index 08529a4..a91d123 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -3852,7 +3852,7 @@ static void ntfs_close(void) / ctx->seccache->head.p_reads % 10); } } - ntfs_close_secure(&security); + ntfs_destroy_security_context(&security); } if (ntfs_umount(ctx->vol, FALSE)) @@ -4363,10 +4363,6 @@ int main(int argc, char *argv[]) #ifdef HAVE_SETXATTR /* extended attributes interface required */ ctx->vol->efs_raw = ctx->efs_raw; #endif /* HAVE_SETXATTR */ - /* JPA open $Secure, (whatever NTFS version !) */ - /* to initialize security data */ - if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3)) - failed_secure = "Could not open file $Secure"; if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path, (ctx->vol->secure_flags & ((1 << SECURITY_DEFAULT) | (1 << SECURITY_ACL))) diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 640cfc4..2578fef 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -3651,7 +3651,7 @@ static void ntfs_close(void) / ctx->seccache->head.p_reads % 10); } } - ntfs_close_secure(&security); + ntfs_destroy_security_context(&security); } if (ntfs_umount(ctx->vol, FALSE)) @@ -4168,10 +4168,6 @@ int main(int argc, char *argv[]) #ifdef HAVE_SETXATTR /* extended attributes interface required */ ctx->vol->efs_raw = ctx->efs_raw; #endif /* HAVE_SETXATTR */ - /* JPA open $Secure, (whatever NTFS version !) */ - /* to initialize security data */ - if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3)) - failed_secure = "Could not open file $Secure"; if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path, (ctx->vol->secure_flags & ((1 << SECURITY_DEFAULT) | (1 << SECURITY_ACL))) -- 2.9.0 ------------------------------------------------------------------------------ _______________________________________________ ntfs-3g-devel mailing list ntfs-3g-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/ntfs-3g-devel