Address some security concerns in the cgpt tool.
1. Check for potential integer overflow in sector_bytes * sector_count.
2. Added O_NOFOLLOW to open() call - Is this enough?
3. Passing buffer length to GuidToStr(), PMBRToStr().
4. Use unsigned int in GetEntry() to determine stride.
5. Address conversion between UTF16 and UTF8.
Note: The UTF conversion is complex and troublesome, and needs careful
consideration to get right. For now, I've just forced the interpretation of
the partition name to 7-bit ASCII. That's sufficient for the needs of Chrome
OS, and I can file a new issue to handle UTF correctly.
BUG=chrome-os-partner:705
TEST=manual
Running "make runtests" invokes the tests/run_cgpt_tests.sh script, which checks the behavior and output of the cgpt tool.
Review URL: http://codereview.chromium.org/3594010
Change-Id: I5fd29796d8c929527e0cfbc6d5ccbcdc77502c6b
diff --git a/cgpt/cgpt.h b/cgpt/cgpt.h
index 1ef74de..9b0805c 100644
--- a/cgpt/cgpt.h
+++ b/cgpt/cgpt.h
@@ -9,6 +9,8 @@
#define _FILE_OFFSET_BITS 64
#include <features.h>
#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
#include "endian.h"
#include "gpt.h"
#include "cgptlib.h"
@@ -45,7 +47,7 @@
uint8_t sig[2]; // 0x55, 0xaa
} __attribute__((packed));
-void PMBRToStr(struct pmbr *pmbr, char *str);
+void PMBRToStr(struct pmbr *pmbr, char *str, unsigned int buflen);
// Handle to the drive storing the GPT.
struct drive {
@@ -69,7 +71,7 @@
*/
#define GUID_STRLEN 37
int StrToGuid(const char *str, Guid *guid);
-void GuidToStr(const Guid *guid, char *str);
+void GuidToStr(const Guid *guid, char *str, unsigned int buflen);
int IsZero(const Guid *guid);
@@ -77,33 +79,33 @@
int WritePMBR(struct drive *drive);
-/* Convert UTF16 string to UTF8. Rewritten from gpt utility.
- * Caller must prepare enough space for UTF8. The rough estimation is:
- *
- * utf8 length = bytecount(utf16) * 1.5
+/* Convert possibly unterminated UTF16 string to UTF8.
+ * Caller must prepare enough space for UTF8, which could be up to
+ * twice the number of UTF16 chars plus the terminating '\0'.
*/
-void UTF16ToUTF8(const uint16_t *utf16, uint8_t *utf8);
-/* Convert UTF8 string to UTF16. Rewritten from gpt utility.
- * Caller must prepare enough space for UTF16. The conservative estimation is:
- *
- * utf16 bytecount = bytecount(utf8) / 3 * 4
+void UTF16ToUTF8(const uint16_t *utf16, unsigned int maxinput,
+ uint8_t *utf8, unsigned int maxoutput);
+/* Convert null-terminated UTF8 string to UTF16.
+ * Caller must prepare enough space for UTF16, including a terminating 0x0000
*/
-void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16);
+void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16, unsigned int maxoutput);
/* Helper functions for supported GPT types. */
int ResolveType(const Guid *type, char *buf);
int SupportedType(const char *name, Guid *type);
void PrintTypes(void);
-void EntryDetails(GptEntry *entry, int index, int raw);
+void EntryDetails(GptEntry *entry, uint32_t index, int raw);
uint32_t GetNumberOfEntries(const GptData *gpt);
-GptEntry *GetEntry(GptData *gpt, int secondary, int entry_index);
-void SetPriority(GptData *gpt, int secondary, int entry_index, int priority);
-int GetPriority(GptData *gpt, int secondary, int entry_index);
-void SetTries(GptData *gpt, int secondary, int entry_index, int tries);
-int GetTries(GptData *gpt, int secondary, int entry_index);
-void SetSuccessful(GptData *gpt, int secondary, int entry_index, int success);
-int GetSuccessful(GptData *gpt, int secondary, int entry_index);
+GptEntry *GetEntry(GptData *gpt, int secondary, uint32_t entry_index);
+void SetPriority(GptData *gpt, int secondary, uint32_t entry_index,
+ int priority);
+int GetPriority(GptData *gpt, int secondary, uint32_t entry_index);
+void SetTries(GptData *gpt, int secondary, uint32_t entry_index, int tries);
+int GetTries(GptData *gpt, int secondary, uint32_t entry_index);
+void SetSuccessful(GptData *gpt, int secondary, uint32_t entry_index,
+ int success);
+int GetSuccessful(GptData *gpt, int secondary, uint32_t entry_index);
uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers);
uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries);
@@ -127,5 +129,16 @@
#define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0]))
const char *GptError(int errnum);
+// Size in chars of the GPT Entry's PartitionName field
+#define GPT_PARTNAME_LEN 72
+
+/* The standard "assert" macro goes away when NDEBUG is defined. This doesn't.
+ */
+#define require(A) do { \
+ if (!(A)) { \
+ fprintf(stderr, "condition (%s) failed at %s:%d\n", \
+ #A, __FILE__, __LINE__); \
+ exit(1); } \
+ } while (0)
#endif // VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_