Many functions require the allocation of multiple resources. Failing and returning somewhere in the middle of this function without freeing all of the allocated resources could produce a memory leak. It is a common error to forget to free one (or all) of the resources in this manner, so a goto-chain is the simplest and cleanest way to organize exits while preserving the order of freed resources.
Noncompliant Code Example
In this noncompliant example, exit code is written for every instance in which the function can terminate prematurely. Notice how failing to close fin2
produces a resource leak, leaving an open file descriptor.
...
This is also just a small example; in much larger examples, errors like this would be even harder to detect.
Compliant Solution
In this revised version, we have used a goto-chain in replacement of each individual return segment. If there is no error, control flow will fall through to the SUCCESS
label, release all of the resources and return NOERR
. In the case of an error, the return value will be set to errno
, control flow will jump to the proper failure label, and the appropriate resources will be released before returning.
...
The benefits of this method are that the code is cleaner and we prevent the rewriting of similar code upon every function error.
Compliant Solution (copy_process()
from Linux kernel)
Some effective examples of goto-chains are quite large. The following compliant code is an excerpt from the Linux kernel. This is the copy_process
function from kernel/fork.c
from Version 2.6.29 of the kernel.
...
Code Block | ||
---|---|---|
| ||
static struct task_struct *copy_process(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *child_tidptr, struct pid *pid, int trace) { int retval; struct task_struct *p; int cgroup_callbacks_done = 0; if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) return ERR_PTR(-EINVAL); /* ... */ retval = security_task_create(clone_flags); if (retval) goto fork_out; retval = -ENOMEM; p = dup_task_struct(current); if (!p) goto fork_out; /* ... */ /* copy all the process information */ if ((retval = copy_semundo(clone_flags, p))) goto bad_fork_cleanup_audit; if ((retval = copy_files(clone_flags, p))) goto bad_fork_cleanup_semundo; if ((retval = copy_fs(clone_flags, p))) goto bad_fork_cleanup_files; if ((retval = copy_sighand(clone_flags, p))) goto bad_fork_cleanup_fs; if ((retval = copy_signal(clone_flags, p))) goto bad_fork_cleanup_sighand; if ((retval = copy_mm(clone_flags, p))) goto bad_fork_cleanup_signal; if ((retval = copy_namespaces(clone_flags, p))) goto bad_fork_cleanup_mm; if ((retval = copy_io(clone_flags, p))) goto bad_fork_cleanup_namespaces; retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); if (retval) goto bad_fork_cleanup_io; /* ... */ return p; /* ... cleanup code starts here ... */ bad_fork_cleanup_io: put_io_context(p->io_context); bad_fork_cleanup_namespaces: exit_task_namespaces(p); bad_fork_cleanup_mm: if (p->mm) mmput(p->mm); bad_fork_cleanup_signal: cleanup_signal(p); bad_fork_cleanup_sighand: __cleanup_sighand(p->sighand); bad_fork_cleanup_fs: exit_fs(p); /* blocking */ bad_fork_cleanup_files: exit_files(p); /* blocking */ bad_fork_cleanup_semundo: exit_sem(p); bad_fork_cleanup_audit: audit_free(p); /* ... more cleanup code ... */ fork_out: return ERR_PTR(retval); } |
Risk Assessment
Failure to free allocated memory or close opened files results in a memory leak and possibly unexpected results.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MEM12-C | low | probable | medium | P3 | L3 |
References
Wiki Markup |
---|
\[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Section 7.20.3, "Memory management functions" \[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Section 7.19.5, "File access functions" [Linux kernel Sourcecode (v2.6.xx)|http://www.kernel.org/pub/linux/kernel/v2.6] 2.6.29, {{kernel/fork.c}}, the {{copy_process()}} function \[[Seacord 05|AA. C References#Seacord 05]\] Chapter 4, "Dynamic Memory Management" |
...