diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2015-01-03 15:54:04 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2015-01-03 15:54:04 +0100 |
commit | 8d547aca75f8b096976a472714241acd4328be46 (patch) | |
tree | cd7c4ba350c19f5369374302f7eb001e53cfe77e | |
parent | 31d6734457b9cafeeaa862750c2afa80aa67816c (diff) | |
download | busybox-w32-8d547aca75f8b096976a472714241acd4328be46.tar.gz busybox-w32-8d547aca75f8b096976a472714241acd4328be46.tar.bz2 busybox-w32-8d547aca75f8b096976a472714241acd4328be46.zip |
libpwdgrp: fix a memory leak in getXXnam (we did not save address of string buf)
function old new delta
convert_to_struct 261 269 +8
const_sp_db 20 24 +4
const_pw_db 20 24 +4
const_gr_db 20 24 +4
tokenize 144 147 +3
parse_common 185 188 +3
get_S 82 85 +3
bb_internal_getpwent_r 188 185 -3
gr_off 4 - -4
getXXnam 171 165 -6
pw_off 7 - -7
getgrouplist_internal 237 229 -8
getXXnam_r 215 207 -8
sp_off 9 - -9
------------------------------------------------------------------------------
(add/remove: 0/3 grow/shrink: 7/4 up/down: 29/-45) Total: -16 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | libpwdgrp/pwd_grp.c | 131 |
1 files changed, 74 insertions, 57 deletions
diff --git a/libpwdgrp/pwd_grp.c b/libpwdgrp/pwd_grp.c index 823884edc..6d938f621 100644 --- a/libpwdgrp/pwd_grp.c +++ b/libpwdgrp/pwd_grp.c | |||
@@ -32,69 +32,79 @@ | |||
32 | 32 | ||
33 | #include "libbb.h" | 33 | #include "libbb.h" |
34 | 34 | ||
35 | /* S = string not empty, s = string maybe empty, | ||
36 | * I = uid,gid, l = long maybe empty, m = members, | ||
37 | * r = reserved | ||
38 | */ | ||
39 | #define PW_DEF "SsIIsSS" | ||
40 | #define GR_DEF "SsIm" | ||
41 | #define SP_DEF "Ssllllllr" | ||
42 | |||
43 | static const uint8_t pw_off[] ALIGN1 = { | ||
44 | offsetof(struct passwd, pw_name), /* 0 S */ | ||
45 | offsetof(struct passwd, pw_passwd), /* 1 s */ | ||
46 | offsetof(struct passwd, pw_uid), /* 2 I */ | ||
47 | offsetof(struct passwd, pw_gid), /* 3 I */ | ||
48 | offsetof(struct passwd, pw_gecos), /* 4 s */ | ||
49 | offsetof(struct passwd, pw_dir), /* 5 S */ | ||
50 | offsetof(struct passwd, pw_shell) /* 6 S */ | ||
51 | }; | ||
52 | static const uint8_t gr_off[] ALIGN1 = { | ||
53 | offsetof(struct group, gr_name), /* 0 S */ | ||
54 | offsetof(struct group, gr_passwd), /* 1 s */ | ||
55 | offsetof(struct group, gr_gid), /* 2 I */ | ||
56 | offsetof(struct group, gr_mem) /* 3 m (char **) */ | ||
57 | }; | ||
58 | #if ENABLE_USE_BB_SHADOW | ||
59 | static const uint8_t sp_off[] ALIGN1 = { | ||
60 | offsetof(struct spwd, sp_namp), /* 0 S Login name */ | ||
61 | offsetof(struct spwd, sp_pwdp), /* 1 s Encrypted password */ | ||
62 | offsetof(struct spwd, sp_lstchg), /* 2 l */ | ||
63 | offsetof(struct spwd, sp_min), /* 3 l */ | ||
64 | offsetof(struct spwd, sp_max), /* 4 l */ | ||
65 | offsetof(struct spwd, sp_warn), /* 5 l */ | ||
66 | offsetof(struct spwd, sp_inact), /* 6 l */ | ||
67 | offsetof(struct spwd, sp_expire), /* 7 l */ | ||
68 | offsetof(struct spwd, sp_flag) /* 8 r Reserved */ | ||
69 | }; | ||
70 | #endif | ||
71 | |||
72 | struct const_passdb { | 35 | struct const_passdb { |
73 | const char *filename; | 36 | const char *filename; |
74 | const uint8_t *off; | ||
75 | const char def[10]; | 37 | const char def[10]; |
38 | const uint8_t off[9]; | ||
76 | uint8_t numfields; | 39 | uint8_t numfields; |
77 | uint8_t size_of; | ||
78 | }; | 40 | }; |
79 | struct passdb { | 41 | struct passdb { |
80 | const char *filename; | 42 | const char *filename; |
81 | const uint8_t *off; | ||
82 | const char def[10]; | 43 | const char def[10]; |
44 | const uint8_t off[9]; | ||
83 | uint8_t numfields; | 45 | uint8_t numfields; |
84 | uint8_t size_of; | ||
85 | FILE *fp; | 46 | FILE *fp; |
86 | void *malloced; | 47 | char *malloced; |
48 | char struct_result[0 | ||
49 | | sizeof(struct passwd) | ||
50 | | sizeof(struct group) | ||
51 | IF_USE_BB_SHADOW( | sizeof(struct spwd) ) | ||
52 | /* bitwise OR above is poor man's max(a,b,c) */ | ||
53 | ]; | ||
87 | }; | 54 | }; |
88 | 55 | ||
89 | static const struct const_passdb const_pw_db = { _PATH_PASSWD, pw_off, PW_DEF, sizeof(PW_DEF)-1, sizeof(struct passwd) }; | 56 | /* S = string not empty, s = string maybe empty, |
90 | static const struct const_passdb const_gr_db = { _PATH_GROUP , gr_off, GR_DEF, sizeof(GR_DEF)-1, sizeof(struct group) }; | 57 | * I = uid,gid, l = long maybe empty, m = members, |
58 | * r = reserved | ||
59 | */ | ||
60 | #define PW_DEF "SsIIsSS" | ||
61 | #define GR_DEF "SsIm" | ||
62 | #define SP_DEF "Ssllllllr" | ||
63 | |||
64 | static const struct const_passdb const_pw_db = { | ||
65 | _PATH_PASSWD, PW_DEF, | ||
66 | { | ||
67 | offsetof(struct passwd, pw_name), /* 0 S */ | ||
68 | offsetof(struct passwd, pw_passwd), /* 1 s */ | ||
69 | offsetof(struct passwd, pw_uid), /* 2 I */ | ||
70 | offsetof(struct passwd, pw_gid), /* 3 I */ | ||
71 | offsetof(struct passwd, pw_gecos), /* 4 s */ | ||
72 | offsetof(struct passwd, pw_dir), /* 5 S */ | ||
73 | offsetof(struct passwd, pw_shell) /* 6 S */ | ||
74 | }, | ||
75 | sizeof(PW_DEF)-1 | ||
76 | }; | ||
77 | static const struct const_passdb const_gr_db = { | ||
78 | _PATH_GROUP, GR_DEF, | ||
79 | { | ||
80 | offsetof(struct group, gr_name), /* 0 S */ | ||
81 | offsetof(struct group, gr_passwd), /* 1 s */ | ||
82 | offsetof(struct group, gr_gid), /* 2 I */ | ||
83 | offsetof(struct group, gr_mem) /* 3 m (char **) */ | ||
84 | }, | ||
85 | sizeof(GR_DEF)-1 | ||
86 | }; | ||
91 | #if ENABLE_USE_BB_SHADOW | 87 | #if ENABLE_USE_BB_SHADOW |
92 | static const struct const_passdb const_sp_db = { _PATH_SHADOW, sp_off, SP_DEF, sizeof(SP_DEF)-1, sizeof(struct spwd) }; | 88 | static const struct const_passdb const_sp_db = { |
89 | _PATH_SHADOW, SP_DEF, | ||
90 | { | ||
91 | offsetof(struct spwd, sp_namp), /* 0 S Login name */ | ||
92 | offsetof(struct spwd, sp_pwdp), /* 1 s Encrypted password */ | ||
93 | offsetof(struct spwd, sp_lstchg), /* 2 l */ | ||
94 | offsetof(struct spwd, sp_min), /* 3 l */ | ||
95 | offsetof(struct spwd, sp_max), /* 4 l */ | ||
96 | offsetof(struct spwd, sp_warn), /* 5 l */ | ||
97 | offsetof(struct spwd, sp_inact), /* 6 l */ | ||
98 | offsetof(struct spwd, sp_expire), /* 7 l */ | ||
99 | offsetof(struct spwd, sp_flag) /* 8 r Reserved */ | ||
100 | }, | ||
101 | sizeof(SP_DEF)-1 | ||
102 | }; | ||
93 | #endif | 103 | #endif |
94 | 104 | ||
95 | /* We avoid having big global data. */ | 105 | /* We avoid having big global data. */ |
96 | struct statics { | 106 | struct statics { |
97 | /* It's ok to use same buffer (db[0].malloced) for getpwuid and getpwnam. | 107 | /* It's ok to use same buffer (db[0].struct_result) for getpwuid and getpwnam. |
98 | * Manpage says: | 108 | * Manpage says: |
99 | * "The return value may point to a static area, and may be overwritten | 109 | * "The return value may point to a static area, and may be overwritten |
100 | * by subsequent calls to getpwent(), getpwnam(), or getpwuid()." | 110 | * by subsequent calls to getpwent(), getpwnam(), or getpwuid()." |
@@ -223,9 +233,15 @@ static char *parse_file(const char *filename, | |||
223 | } | 233 | } |
224 | 234 | ||
225 | /* Convert passwd/group/shadow file record in buffer to a struct */ | 235 | /* Convert passwd/group/shadow file record in buffer to a struct */ |
226 | static void *convert_to_struct(const char *def, const unsigned char *off, | 236 | static void *convert_to_struct(struct passdb *db, |
227 | char *buffer, void *result) | 237 | char *buffer, void *result) |
228 | { | 238 | { |
239 | const char *def = db->def; | ||
240 | const uint8_t *off = db->off; | ||
241 | |||
242 | /* TODO? for consistency, zero out all fields */ | ||
243 | /* memset(result, 0, size_of_result);*/ | ||
244 | |||
229 | for (;;) { | 245 | for (;;) { |
230 | void *member = (char*)result + (*off++); | 246 | void *member = (char*)result + (*off++); |
231 | 247 | ||
@@ -282,7 +298,8 @@ static void *convert_to_struct(const char *def, const unsigned char *off, | |||
282 | 298 | ||
283 | /****** getXXnam/id_r */ | 299 | /****** getXXnam/id_r */ |
284 | 300 | ||
285 | static int FAST_FUNC getXXnam_r(const char *name, uintptr_t db_and_field_pos, char *buffer, size_t buflen, | 301 | static int FAST_FUNC getXXnam_r(const char *name, uintptr_t db_and_field_pos, |
302 | char *buffer, size_t buflen, | ||
286 | void *result) | 303 | void *result) |
287 | { | 304 | { |
288 | void *struct_buf = *(void**)result; | 305 | void *struct_buf = *(void**)result; |
@@ -299,7 +316,7 @@ static int FAST_FUNC getXXnam_r(const char *name, uintptr_t db_and_field_pos, ch | |||
299 | errno = ERANGE; | 316 | errno = ERANGE; |
300 | } else { | 317 | } else { |
301 | memcpy(buffer, buf, size); | 318 | memcpy(buffer, buf, size); |
302 | *(void**)result = convert_to_struct(db->def, db->off, buffer, struct_buf); | 319 | *(void**)result = convert_to_struct(db, buffer, struct_buf); |
303 | } | 320 | } |
304 | free(buf); | 321 | free(buf); |
305 | } | 322 | } |
@@ -310,8 +327,9 @@ static int FAST_FUNC getXXnam_r(const char *name, uintptr_t db_and_field_pos, ch | |||
310 | return errno; | 327 | return errno; |
311 | } | 328 | } |
312 | 329 | ||
313 | int FAST_FUNC getpwnam_r(const char *name, struct passwd *struct_buf, char *buffer, size_t buflen, | 330 | int FAST_FUNC getpwnam_r(const char *name, struct passwd *struct_buf, |
314 | struct passwd **result) | 331 | char *buffer, size_t buflen, |
332 | struct passwd **result) | ||
315 | { | 333 | { |
316 | /* Why the "store buffer address in result" trick? | 334 | /* Why the "store buffer address in result" trick? |
317 | * This way, getXXnam_r has the same ABI signature as getpwnam_r, | 335 | * This way, getXXnam_r has the same ABI signature as getpwnam_r, |
@@ -357,7 +375,7 @@ static int FAST_FUNC getXXent_r(void *struct_buf, char *buffer, size_t buflen, | |||
357 | errno = ERANGE; | 375 | errno = ERANGE; |
358 | } else { | 376 | } else { |
359 | memcpy(buffer, buf, size); | 377 | memcpy(buffer, buf, size); |
360 | *(void**)result = convert_to_struct(db->def, db->off, buffer, struct_buf); | 378 | *(void**)result = convert_to_struct(db, buffer, struct_buf); |
361 | } | 379 | } |
362 | free(buf); | 380 | free(buf); |
363 | } | 381 | } |
@@ -393,12 +411,11 @@ static void* FAST_FUNC getXXnam(const char *name, unsigned db_and_field_pos) | |||
393 | close_on_exec_on(fileno(db->fp)); | 411 | close_on_exec_on(fileno(db->fp)); |
394 | } | 412 | } |
395 | 413 | ||
396 | free(db->malloced); | ||
397 | db->malloced = NULL; | ||
398 | buf = parse_common(db->fp, db->filename, db->numfields, name, db_and_field_pos & 3); | 414 | buf = parse_common(db->fp, db->filename, db->numfields, name, db_and_field_pos & 3); |
399 | if (buf) { | 415 | if (buf) { |
400 | db->malloced = xzalloc(db->size_of); | 416 | free(db->malloced); |
401 | result = convert_to_struct(db->def, db->off, buf, db->malloced); | 417 | db->malloced = buf; |
418 | result = convert_to_struct(db, buf, db->struct_result); | ||
402 | } | 419 | } |
403 | return result; | 420 | return result; |
404 | } | 421 | } |
@@ -465,7 +482,7 @@ static gid_t* FAST_FUNC getgrouplist_internal(int *ngroups_ptr, | |||
465 | while ((buf = parse_common(fp, _PATH_GROUP, sizeof(GR_DEF)-1, NULL, 0)) != NULL) { | 482 | while ((buf = parse_common(fp, _PATH_GROUP, sizeof(GR_DEF)-1, NULL, 0)) != NULL) { |
466 | char **m; | 483 | char **m; |
467 | struct group group; | 484 | struct group group; |
468 | if (!convert_to_struct(GR_DEF, gr_off, buf, &group)) | 485 | if (!convert_to_struct(&S.db[1], buf, &group)) |
469 | goto next; | 486 | goto next; |
470 | if (group.gr_gid == gid) | 487 | if (group.gr_gid == gid) |
471 | goto next; | 488 | goto next; |