aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/super.c
diff options
context:
space:
mode:
authorJim Meyering <meyering@redhat.com>2012-04-25 15:24:17 -0400
committerJosef Bacik <josef@redhat.com>2012-05-30 10:23:32 -0400
commitf60d16a8923201bb27ad7c09016abab2818cf8ce (patch)
tree7bb7f019dad20883b01cb7689d80195d483e37a4 /fs/btrfs/super.c
parenta27202fbe92b12eec895c36644440175de01d7a6 (diff)
Btrfs: avoid buffer overrun in mount option handling
There is an off-by-one error: allocating room for a maximal result string but without room for a trailing NUL. That, can lead to returning a transformed string that is not NUL-terminated, and then to a caller reading beyond end of the malloc'd buffer. Rewrite to s/kzalloc/kmalloc/, remove unwarranted use of strncpy (the result is guaranteed to fit), remove dead strlen at end, and change a few variable names and comments. Reviewed-by: Josef Bacik <josef@redhat.com> Signed-off-by: Jim Meyering <meyering@redhat.com>
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r--fs/btrfs/super.c67
1 files changed, 26 insertions, 41 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 46b26650415f..96eb9fef7bd2 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -923,63 +923,48 @@ static inline int is_subvolume_inode(struct inode *inode)
923 */ 923 */
924static char *setup_root_args(char *args) 924static char *setup_root_args(char *args)
925{ 925{
926 unsigned copied = 0; 926 unsigned len = strlen(args) + 2 + 1;
927 unsigned len = strlen(args) + 2; 927 char *src, *dst, *buf;
928 char *pos;
929 char *ret;
930 928
931 /* 929 /*
932 * We need the same args as before, but minus 930 * We need the same args as before, but with this substitution:
931 * s!subvol=[^,]+!subvolid=0!
933 * 932 *
934 * subvol=a 933 * Since the replacement string is up to 2 bytes longer than the
935 * 934 * original, allocate strlen(args) + 2 + 1 bytes.
936 * and add
937 *
938 * subvolid=0
939 *
940 * which is a difference of 2 characters, so we allocate strlen(args) +
941 * 2 characters.
942 */ 935 */
943 ret = kzalloc(len * sizeof(char), GFP_NOFS);
944 if (!ret)
945 return NULL;
946 pos = strstr(args, "subvol=");
947 936
937 src = strstr(args, "subvol=");
948 /* This shouldn't happen, but just in case.. */ 938 /* This shouldn't happen, but just in case.. */
949 if (!pos) { 939 if (!src)
950 kfree(ret); 940 return NULL;
941
942 buf = dst = kmalloc(len, GFP_NOFS);
943 if (!buf)
951 return NULL; 944 return NULL;
952 }
953 945
954 /* 946 /*
955 * The subvol=<> arg is not at the front of the string, copy everybody 947 * If the subvol= arg is not at the start of the string,
956 * up to that into ret. 948 * copy whatever precedes it into buf.
957 */ 949 */
958 if (pos != args) { 950 if (src != args) {
959 *pos = '\0'; 951 *src++ = '\0';
960 strcpy(ret, args); 952 strcpy(buf, args);
961 copied += strlen(args); 953 dst += strlen(args);
962 pos++;
963 } 954 }
964 955
965 strncpy(ret + copied, "subvolid=0", len - copied); 956 strcpy(dst, "subvolid=0");
966 957 dst += strlen("subvolid=0");
967 /* Length of subvolid=0 */
968 copied += 10;
969 958
970 /* 959 /*
971 * If there is no , after the subvol= option then we know there's no 960 * If there is a "," after the original subvol=... string,
972 * other options and we can just return. 961 * copy that suffix into our buffer. Otherwise, we're done.
973 */ 962 */
974 pos = strchr(pos, ','); 963 src = strchr(src, ',');
975 if (!pos) 964 if (src)
976 return ret; 965 strcpy(dst, src);
977 966
978 /* Copy the rest of the arguments into our buffer */ 967 return buf;
979 strncpy(ret + copied, pos, len - copied);
980 copied += strlen(pos);
981
982 return ret;
983} 968}
984 969
985static struct dentry *mount_subvol(const char *subvol_name, int flags, 970static struct dentry *mount_subvol(const char *subvol_name, int flags,