Skip to content

Commit d3468c5

Browse files
authored
pam-ipmi: initial integration for openbmc/pam-ipmi (google#15823)
This pull request integrates the pam-ipmi project into OSS-Fuzz, enabling continuous fuzzing of its special group password management and encryption logic. Summary of Changes 1. Project Configuration * Added projects/pam-ipmi/project.yaml with project metadata and contact information. * Added projects/pam-ipmi/Dockerfile to install build-time dependencies (libpam0g-dev, libssl-dev, meson, ninja-build) and prepare the build environment. 2. Build & Integration * Added projects/pam-ipmi/build.sh to: * Compile src/pam_ipmisave/pam_ipmisave.c with address sanitizer instrumentation. * Link the fuzzer harness against libcrypto and libpam. * Package the seed corpus for the fuzzing engine. 3. Fuzzer Harness * Added projects/pam-ipmi/pam_ipmi_fuzzer.c: * Targets update_pass_special_file, the core logic responsible for parsing, decrypting, updating, and re-encrypting the IPMI special password file (/etc/ipmi_pass). * Mocks file system locks (lckpwdf/ulckpwdf) to allow safe execution within the fuzzing container. * Provides a structured input split to exercise different usernames, passwords, and initial file states. 4. Seed Corpus * Added projects/pam-ipmi/corpus/seed1, containing a valid metapassstruct header to assist the fuzzer in reaching the deeper decryption and modification logic. Coverage Impact Local coverage analysis shows that the fuzzer currently exercises the early parsing and error-handling paths of the target function. Fixing the identified buffer overflow will allow the fuzzer to penetrate the remaining ~80% of the code, including the OpenSSL-based encryption and decryption routines.
1 parent 251e500 commit d3468c5

5 files changed

Lines changed: 155 additions & 0 deletions

File tree

projects/pam-ipmi/Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
################################################################################
16+
17+
FROM gcr.io/oss-fuzz-base/base-builder
18+
RUN apt-get update && apt-get install -y make autoconf automake libtool libpam0g-dev libssl-dev meson ninja-build
19+
RUN git clone --depth 1 https://github.com/openbmc/pam-ipmi pam-ipmi
20+
COPY build.sh pam_ipmi_fuzzer.c $SRC/
21+
COPY corpus $SRC/corpus
22+
WORKDIR $SRC/pam-ipmi

projects/pam-ipmi/build.sh

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/bash -eu
2+
# Copyright 2026 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
################################################################################
17+
18+
# Compile the source file with instrumentation
19+
$CC $CFLAGS -c $SRC/pam-ipmi/src/pam_ipmisave/pam_ipmisave.c -o pam_ipmisave.o
20+
21+
# Compile and link the fuzzer
22+
$CC $CFLAGS $LIB_FUZZING_ENGINE $SRC/pam_ipmi_fuzzer.c pam_ipmisave.o -o $OUT/pam_ipmi_fuzzer -lcrypto -lpam
23+
24+
# Package the corpus
25+
zip -j $OUT/pam_ipmi_fuzzer_seed_corpus.zip $SRC/corpus/*

projects/pam-ipmi/corpus/seed1

187 Bytes
Binary file not shown.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <stdint.h>
18+
#include <stddef.h>
19+
#include <stdlib.h>
20+
#include <string.h>
21+
#include <unistd.h>
22+
#include <stdio.h>
23+
24+
#include <security/pam_modules.h>
25+
#include <security/pam_ext.h>
26+
27+
// Mocking some functions that might be problematic
28+
int lckpwdf(void) { return 0; }
29+
int ulckpwdf(void) { return 0; }
30+
31+
// The function we want to fuzz
32+
int update_pass_special_file(const pam_handle_t *pamh, const char *keyfilename,
33+
const char *filename, const char *forwho,
34+
const char *towhat);
35+
36+
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
37+
if (size < 10) return 0;
38+
39+
char key_file[] = "/tmp/fuzz_key_XXXXXX";
40+
int key_fd = mkstemp(key_file);
41+
if (key_fd == -1) return 0;
42+
// key file must be 8 bytes as per pam_ipmisave.c: MAX_KEY_SIZE
43+
uint8_t key_data[8] = {0};
44+
if (size >= 8) {
45+
memcpy(key_data, data, 8);
46+
data += 8;
47+
size -= 8;
48+
}
49+
write(key_fd, key_data, 8);
50+
close(key_fd);
51+
52+
char pass_file[] = "/tmp/fuzz_pass_XXXXXX";
53+
int pass_fd = mkstemp(pass_file);
54+
if (pass_fd == -1) {
55+
unlink(key_file);
56+
return 0;
57+
}
58+
if (size > 0) {
59+
// Use half of remaining data for the initial pass file content
60+
size_t initial_file_size = size / 2;
61+
write(pass_fd, data, initial_file_size);
62+
data += initial_file_size;
63+
size -= initial_file_size;
64+
}
65+
close(pass_fd);
66+
67+
if (size < 2) {
68+
unlink(key_file);
69+
unlink(pass_file);
70+
return 0;
71+
}
72+
73+
// Use the rest for username and password
74+
size_t user_len = size / 2;
75+
char *user = malloc(user_len + 1);
76+
memcpy(user, data, user_len);
77+
user[user_len] = '\0';
78+
data += user_len;
79+
size -= user_len;
80+
81+
char *pass = malloc(size + 1);
82+
memcpy(pass, data, size);
83+
pass[size] = '\0';
84+
85+
// Call the function
86+
update_pass_special_file(NULL, key_file, pass_file, user, pass);
87+
88+
free(user);
89+
free(pass);
90+
unlink(key_file);
91+
unlink(pass_file);
92+
93+
return 0;
94+
}

projects/pam-ipmi/project.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
homepage: "https://github.com/openbmc/pam-ipmi"
2+
language: c
3+
primary_contact: "javanlacerda@google.com"
4+
auto_ccs:
5+
- "pedroysb@google.com"
6+
- "cloud-ti-fuzzing+bugs@google.com"
7+
fuzzing_engines:
8+
- libfuzzer
9+
sanitizers:
10+
- address
11+
- undefined
12+
architectures:
13+
- x86_64
14+
main_repo: "https://github.com/openbmc/pam-ipmi"

0 commit comments

Comments
 (0)